Refactor blog module and remove blog-related functionality
- Removed blog router and associated API endpoints. - Deleted blog persistence functions and related query parameters. - Removed blog schemas and models from the codebase. - Introduced common crate for shared types, including DateTimeWithTimeZoneWrapper. - Added Thought and Follow models with corresponding migrations. - Updated dependencies in Cargo.toml files to reflect changes. - Adjusted tests to remove references to the blog module.
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
HOST=0.0.0.0
|
HOST=0.0.0.0
|
||||||
PORT=8000
|
PORT=8000
|
||||||
#DATABASE_URL="sqlite://dev.db"
|
#DATABASE_URL="sqlite://dev.db"
|
||||||
# DATABASE_URL="postgresql://postgres:postgres@localhost/thoughts"
|
DATABASE_URL="postgresql://postgres:postgres@localhost/thoughts"
|
||||||
DATABASE_URL=postgres://thoughts_user:postgres@database:5432/thoughts_db
|
#DATABASE_URL=postgres://thoughts_user:postgres@database:5432/thoughts_db
|
||||||
PREFORK=1
|
PREFORK=1
|
||||||
|
330
thoughts-backend/Cargo.lock
generated
330
thoughts-backend/Cargo.lock
generated
@@ -17,6 +17,17 @@ version = "2.0.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
|
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ahash"
|
||||||
|
version = "0.7.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom 0.2.16",
|
||||||
|
"once_cell",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aho-corasick"
|
name = "aho-corasick"
|
||||||
version = "1.1.3"
|
version = "1.1.3"
|
||||||
@@ -145,6 +156,12 @@ dependencies = [
|
|||||||
"derive_arbitrary",
|
"derive_arbitrary",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "arrayvec"
|
||||||
|
version = "0.7.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-attributes"
|
name = "async-attributes"
|
||||||
version = "1.1.2"
|
version = "1.1.2"
|
||||||
@@ -418,6 +435,20 @@ version = "1.8.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba"
|
checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bigdecimal"
|
||||||
|
version = "0.4.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1a22f228ab7a1b23027ccc6c350b72868017af7ea8356fbdf19f8d991c690013"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"libm",
|
||||||
|
"num-bigint",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "2.9.1"
|
version = "2.9.1"
|
||||||
@@ -427,6 +458,18 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitvec"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c"
|
||||||
|
dependencies = [
|
||||||
|
"funty",
|
||||||
|
"radium",
|
||||||
|
"tap",
|
||||||
|
"wyz",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "block-buffer"
|
name = "block-buffer"
|
||||||
version = "0.10.4"
|
version = "0.10.4"
|
||||||
@@ -449,12 +492,57 @@ dependencies = [
|
|||||||
"piper",
|
"piper",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "borsh"
|
||||||
|
version = "1.5.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ad8646f98db542e39fc66e68a20b2144f6a732636df7c2354e74645faaa433ce"
|
||||||
|
dependencies = [
|
||||||
|
"borsh-derive",
|
||||||
|
"cfg_aliases",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "borsh-derive"
|
||||||
|
version = "1.5.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fdd1d3c0c2f5833f22386f252fe8ed005c7f59fdcddeef025c01b4c3b9fd9ac3"
|
||||||
|
dependencies = [
|
||||||
|
"once_cell",
|
||||||
|
"proc-macro-crate",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.104",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bumpalo"
|
name = "bumpalo"
|
||||||
version = "3.19.0"
|
version = "3.19.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
|
checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bytecheck"
|
||||||
|
version = "0.6.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2"
|
||||||
|
dependencies = [
|
||||||
|
"bytecheck_derive",
|
||||||
|
"ptr_meta",
|
||||||
|
"simdutf8",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bytecheck_derive"
|
||||||
|
version = "0.6.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 1.0.109",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "byteorder"
|
name = "byteorder"
|
||||||
version = "1.5.0"
|
version = "1.5.0"
|
||||||
@@ -549,6 +637,15 @@ version = "1.0.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
|
checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "common"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"sea-orm",
|
||||||
|
"serde",
|
||||||
|
"utoipa",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "concurrent-queue"
|
name = "concurrent-queue"
|
||||||
version = "2.5.0"
|
version = "2.5.0"
|
||||||
@@ -698,6 +795,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e"
|
checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"powerfmt",
|
"powerfmt",
|
||||||
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -932,6 +1030,12 @@ dependencies = [
|
|||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "funty"
|
||||||
|
version = "2.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures"
|
name = "futures"
|
||||||
version = "0.3.31"
|
version = "0.3.31"
|
||||||
@@ -1123,6 +1227,15 @@ dependencies = [
|
|||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hashbrown"
|
||||||
|
version = "0.12.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||||
|
dependencies = [
|
||||||
|
"ahash",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.15.4"
|
version = "0.15.4"
|
||||||
@@ -1140,7 +1253,7 @@ version = "0.10.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1"
|
checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hashbrown",
|
"hashbrown 0.15.4",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1476,7 +1589,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661"
|
checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"equivalent",
|
"equivalent",
|
||||||
"hashbrown",
|
"hashbrown 0.15.4",
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -1696,6 +1809,7 @@ dependencies = [
|
|||||||
name = "models"
|
name = "models"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"common",
|
||||||
"sea-orm",
|
"sea-orm",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
@@ -1725,6 +1839,16 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-bigint"
|
||||||
|
version = "0.4.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
|
||||||
|
dependencies = [
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-bigint-dig"
|
name = "num-bigint-dig"
|
||||||
version = "0.8.4"
|
version = "0.8.4"
|
||||||
@@ -1882,6 +2006,15 @@ version = "2.3.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
|
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pgvector"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fc58e2d255979a31caa7cabfa7aac654af0354220719ab7a68520ae7a91e8c0b"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "phf"
|
name = "phf"
|
||||||
version = "0.11.3"
|
version = "0.11.3"
|
||||||
@@ -2031,6 +2164,15 @@ dependencies = [
|
|||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro-crate"
|
||||||
|
version = "3.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35"
|
||||||
|
dependencies = [
|
||||||
|
"toml_edit",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro-error-attr2"
|
name = "proc-macro-error-attr2"
|
||||||
version = "2.0.0"
|
version = "2.0.0"
|
||||||
@@ -2075,6 +2217,26 @@ dependencies = [
|
|||||||
"yansi",
|
"yansi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ptr_meta"
|
||||||
|
version = "0.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1"
|
||||||
|
dependencies = [
|
||||||
|
"ptr_meta_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ptr_meta_derive"
|
||||||
|
version = "0.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 1.0.109",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quinn"
|
name = "quinn"
|
||||||
version = "0.11.8"
|
version = "0.11.8"
|
||||||
@@ -2145,6 +2307,12 @@ version = "5.3.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
|
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "radium"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand"
|
name = "rand"
|
||||||
version = "0.8.5"
|
version = "0.8.5"
|
||||||
@@ -2257,6 +2425,15 @@ version = "0.8.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rend"
|
||||||
|
version = "0.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "71fe3824f5629716b1589be05dacd749f6aa084c87e00e016714a8cdfccc997c"
|
||||||
|
dependencies = [
|
||||||
|
"bytecheck",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "reqwest"
|
name = "reqwest"
|
||||||
version = "0.12.20"
|
version = "0.12.20"
|
||||||
@@ -2324,6 +2501,35 @@ dependencies = [
|
|||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rkyv"
|
||||||
|
version = "0.7.45"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9008cd6385b9e161d8229e1f6549dd23c3d022f132a2ea37ac3a10ac4935779b"
|
||||||
|
dependencies = [
|
||||||
|
"bitvec",
|
||||||
|
"bytecheck",
|
||||||
|
"bytes",
|
||||||
|
"hashbrown 0.12.3",
|
||||||
|
"ptr_meta",
|
||||||
|
"rend",
|
||||||
|
"rkyv_derive",
|
||||||
|
"seahash",
|
||||||
|
"tinyvec",
|
||||||
|
"uuid",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rkyv_derive"
|
||||||
|
version = "0.7.45"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "503d1d27590a2b0a3a4ca4c94755aa2875657196ecbf401a42eff41d7de532c0"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 1.0.109",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rsa"
|
name = "rsa"
|
||||||
version = "0.9.8"
|
version = "0.9.8"
|
||||||
@@ -2378,6 +2584,22 @@ dependencies = [
|
|||||||
"walkdir",
|
"walkdir",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rust_decimal"
|
||||||
|
version = "1.37.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b203a6425500a03e0919c42d3c47caca51e79f1132046626d2c8871c5092035d"
|
||||||
|
dependencies = [
|
||||||
|
"arrayvec",
|
||||||
|
"borsh",
|
||||||
|
"bytes",
|
||||||
|
"num-traits",
|
||||||
|
"rand 0.8.5",
|
||||||
|
"rkyv",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc-demangle"
|
name = "rustc-demangle"
|
||||||
version = "0.1.25"
|
version = "0.1.25"
|
||||||
@@ -2495,18 +2717,25 @@ checksum = "18b7272b88bd608cd846de24f41b74a0315a135fe761b0aed4ec1ce6a6327a93"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"async-stream",
|
"async-stream",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
|
"bigdecimal",
|
||||||
|
"chrono",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"log",
|
"log",
|
||||||
"ouroboros",
|
"ouroboros",
|
||||||
|
"pgvector",
|
||||||
|
"rust_decimal",
|
||||||
"sea-orm-macros",
|
"sea-orm-macros",
|
||||||
"sea-query",
|
"sea-query",
|
||||||
"sea-query-binder",
|
"sea-query-binder",
|
||||||
"serde",
|
"serde",
|
||||||
|
"serde_json",
|
||||||
"sqlx",
|
"sqlx",
|
||||||
"strum 0.26.3",
|
"strum 0.26.3",
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.12",
|
||||||
|
"time",
|
||||||
"tracing",
|
"tracing",
|
||||||
"url",
|
"url",
|
||||||
|
"uuid",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2563,9 +2792,15 @@ version = "0.32.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "64c91783d1514b99754fc6a4079081dcc2c587dadbff65c48c7f62297443536a"
|
checksum = "64c91783d1514b99754fc6a4079081dcc2c587dadbff65c48c7f62297443536a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"bigdecimal",
|
||||||
|
"chrono",
|
||||||
"inherent",
|
"inherent",
|
||||||
"ordered-float",
|
"ordered-float",
|
||||||
|
"rust_decimal",
|
||||||
"sea-query-derive",
|
"sea-query-derive",
|
||||||
|
"serde_json",
|
||||||
|
"time",
|
||||||
|
"uuid",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2574,8 +2809,14 @@ version = "0.7.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b0019f47430f7995af63deda77e238c17323359af241233ec768aba1faea7608"
|
checksum = "b0019f47430f7995af63deda77e238c17323359af241233ec768aba1faea7608"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"bigdecimal",
|
||||||
|
"chrono",
|
||||||
|
"rust_decimal",
|
||||||
"sea-query",
|
"sea-query",
|
||||||
|
"serde_json",
|
||||||
"sqlx",
|
"sqlx",
|
||||||
|
"time",
|
||||||
|
"uuid",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2617,6 +2858,12 @@ dependencies = [
|
|||||||
"syn 2.0.104",
|
"syn 2.0.104",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "seahash"
|
||||||
|
version = "4.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "semver"
|
name = "semver"
|
||||||
version = "1.0.26"
|
version = "1.0.26"
|
||||||
@@ -2863,6 +3110,12 @@ version = "0.3.7"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
|
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "simdutf8"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "siphasher"
|
name = "siphasher"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
@@ -2933,7 +3186,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "ee6798b1838b6a0f69c007c133b8df5866302197e404e8b6ee8ed3e3a5e68dc6"
|
checksum = "ee6798b1838b6a0f69c007c133b8df5866302197e404e8b6ee8ed3e3a5e68dc6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64",
|
"base64",
|
||||||
|
"bigdecimal",
|
||||||
"bytes",
|
"bytes",
|
||||||
|
"chrono",
|
||||||
"crc",
|
"crc",
|
||||||
"crossbeam-queue",
|
"crossbeam-queue",
|
||||||
"either",
|
"either",
|
||||||
@@ -2942,23 +3197,26 @@ dependencies = [
|
|||||||
"futures-intrusive",
|
"futures-intrusive",
|
||||||
"futures-io",
|
"futures-io",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"hashbrown",
|
"hashbrown 0.15.4",
|
||||||
"hashlink",
|
"hashlink",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"log",
|
"log",
|
||||||
"memchr",
|
"memchr",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
|
"rust_decimal",
|
||||||
"rustls",
|
"rustls",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sha2",
|
"sha2",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.12",
|
||||||
|
"time",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-stream",
|
"tokio-stream",
|
||||||
"tracing",
|
"tracing",
|
||||||
"url",
|
"url",
|
||||||
|
"uuid",
|
||||||
"webpki-roots 0.26.11",
|
"webpki-roots 0.26.11",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -3008,9 +3266,11 @@ checksum = "aa003f0038df784eb8fecbbac13affe3da23b45194bd57dba231c8f48199c526"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"atoi",
|
"atoi",
|
||||||
"base64",
|
"base64",
|
||||||
|
"bigdecimal",
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"bytes",
|
"bytes",
|
||||||
|
"chrono",
|
||||||
"crc",
|
"crc",
|
||||||
"digest",
|
"digest",
|
||||||
"dotenvy",
|
"dotenvy",
|
||||||
@@ -3031,6 +3291,7 @@ dependencies = [
|
|||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"rand 0.8.5",
|
"rand 0.8.5",
|
||||||
"rsa",
|
"rsa",
|
||||||
|
"rust_decimal",
|
||||||
"serde",
|
"serde",
|
||||||
"sha1",
|
"sha1",
|
||||||
"sha2",
|
"sha2",
|
||||||
@@ -3038,7 +3299,9 @@ dependencies = [
|
|||||||
"sqlx-core",
|
"sqlx-core",
|
||||||
"stringprep",
|
"stringprep",
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.12",
|
||||||
|
"time",
|
||||||
"tracing",
|
"tracing",
|
||||||
|
"uuid",
|
||||||
"whoami",
|
"whoami",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -3050,8 +3313,10 @@ checksum = "db58fcd5a53cf07c184b154801ff91347e4c30d17a3562a635ff028ad5deda46"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"atoi",
|
"atoi",
|
||||||
"base64",
|
"base64",
|
||||||
|
"bigdecimal",
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
|
"chrono",
|
||||||
"crc",
|
"crc",
|
||||||
"dotenvy",
|
"dotenvy",
|
||||||
"etcetera",
|
"etcetera",
|
||||||
@@ -3066,8 +3331,10 @@ dependencies = [
|
|||||||
"log",
|
"log",
|
||||||
"md-5",
|
"md-5",
|
||||||
"memchr",
|
"memchr",
|
||||||
|
"num-bigint",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"rand 0.8.5",
|
"rand 0.8.5",
|
||||||
|
"rust_decimal",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sha2",
|
"sha2",
|
||||||
@@ -3075,7 +3342,9 @@ dependencies = [
|
|||||||
"sqlx-core",
|
"sqlx-core",
|
||||||
"stringprep",
|
"stringprep",
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.12",
|
||||||
|
"time",
|
||||||
"tracing",
|
"tracing",
|
||||||
|
"uuid",
|
||||||
"whoami",
|
"whoami",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -3086,6 +3355,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "c2d12fe70b2c1b4401038055f90f151b78208de1f9f89a7dbfd41587a10c3eea"
|
checksum = "c2d12fe70b2c1b4401038055f90f151b78208de1f9f89a7dbfd41587a10c3eea"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"atoi",
|
"atoi",
|
||||||
|
"chrono",
|
||||||
"flume",
|
"flume",
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
@@ -3099,8 +3369,10 @@ dependencies = [
|
|||||||
"serde_urlencoded",
|
"serde_urlencoded",
|
||||||
"sqlx-core",
|
"sqlx-core",
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.12",
|
||||||
|
"time",
|
||||||
"tracing",
|
"tracing",
|
||||||
"url",
|
"url",
|
||||||
|
"uuid",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3214,6 +3486,12 @@ dependencies = [
|
|||||||
"syn 2.0.104",
|
"syn 2.0.104",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tap"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "1.0.69"
|
version = "1.0.69"
|
||||||
@@ -3446,6 +3724,23 @@ dependencies = [
|
|||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml_datetime"
|
||||||
|
version = "0.6.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml_edit"
|
||||||
|
version = "0.22.27"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a"
|
||||||
|
dependencies = [
|
||||||
|
"indexmap",
|
||||||
|
"toml_datetime",
|
||||||
|
"winnow",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tower"
|
name = "tower"
|
||||||
version = "0.5.2"
|
version = "0.5.2"
|
||||||
@@ -3784,6 +4079,17 @@ version = "0.1.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e2eebbbfe4093922c2b6734d7c679ebfebd704a0d7e56dfcb0d05818ce28977d"
|
checksum = "e2eebbbfe4093922c2b6734d7c679ebfebd704a0d7e56dfcb0d05818ce28977d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "uuid"
|
||||||
|
version = "1.18.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f33196643e165781c20a5ead5582283a7dacbb87855d867fbc2df3f81eddc1be"
|
||||||
|
dependencies = [
|
||||||
|
"js-sys",
|
||||||
|
"serde",
|
||||||
|
"wasm-bindgen",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "validator"
|
name = "validator"
|
||||||
version = "0.20.0"
|
version = "0.20.0"
|
||||||
@@ -4309,6 +4615,15 @@ version = "0.53.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486"
|
checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winnow"
|
||||||
|
version = "0.7.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wit-bindgen-rt"
|
name = "wit-bindgen-rt"
|
||||||
version = "0.39.0"
|
version = "0.39.0"
|
||||||
@@ -4324,6 +4639,15 @@ version = "0.6.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb"
|
checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wyz"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed"
|
||||||
|
dependencies = [
|
||||||
|
"tap",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "yansi"
|
name = "yansi"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
|
@@ -16,12 +16,13 @@ members = ["api", "app", "doc", "models", "migration", "utils"]
|
|||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
axum = { version = "0.8.4", default-features = false }
|
axum = { version = "0.8.4", default-features = false }
|
||||||
tower = { version = "0.5.2", default-features = false }
|
tower = { version = "0.5.2", default-features = false }
|
||||||
sea-orm = { version = "1.1.12", default-features = false }
|
sea-orm = { version = "1.1.12" }
|
||||||
serde = { version = "1.0.219", features = ["derive"] }
|
serde = { version = "1.0.219", features = ["derive"] }
|
||||||
serde_json = { version = "1.0.140", default-features = false }
|
serde_json = { version = "1.0.140" }
|
||||||
tracing = "0.1.41"
|
tracing = "0.1.41"
|
||||||
utoipa = { version = "5.4.0", default-features = false, features = ["macros"] }
|
utoipa = { version = "5.4.0", features = ["macros", "chrono"] }
|
||||||
validator = { version = "0.20.0", default-features = false }
|
validator = { version = "0.20.0", default-features = false }
|
||||||
|
chrono = { version = "0.4.41", features = ["serde"] }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
api = { path = "api" }
|
api = { path = "api" }
|
||||||
|
@@ -1,68 +0,0 @@
|
|||||||
use axum::{
|
|
||||||
extract::{Query, State},
|
|
||||||
http::StatusCode,
|
|
||||||
response::IntoResponse,
|
|
||||||
routing::get,
|
|
||||||
Router,
|
|
||||||
};
|
|
||||||
use sea_orm::TryIntoModel;
|
|
||||||
|
|
||||||
use app::persistence::blog::{create_blog, search_blogs};
|
|
||||||
use app::state::AppState;
|
|
||||||
use models::params::blog::CreateBlogParams;
|
|
||||||
use models::queries::blog::BlogQuery;
|
|
||||||
use models::schemas::blog::{BlogListSchema, BlogSchema};
|
|
||||||
|
|
||||||
use crate::error::ApiError;
|
|
||||||
use crate::extractor::{Json, Valid};
|
|
||||||
use crate::models::{ApiErrorResponse, ParamsErrorResponse};
|
|
||||||
|
|
||||||
#[utoipa::path(
|
|
||||||
post,
|
|
||||||
path = "",
|
|
||||||
request_body = CreateBlogParams,
|
|
||||||
responses(
|
|
||||||
(status = 201, description = "Blog created", body = BlogSchema),
|
|
||||||
(status = 400, description = "Bad request", body = ApiErrorResponse),
|
|
||||||
(status = 422, description = "Validation error", body = ParamsErrorResponse),
|
|
||||||
(status = 500, description = "Internal server error", body = ApiErrorResponse),
|
|
||||||
)
|
|
||||||
)]
|
|
||||||
async fn blogs_post(
|
|
||||||
state: State<AppState>,
|
|
||||||
Valid(Json(params)): Valid<Json<CreateBlogParams>>,
|
|
||||||
) -> Result<impl IntoResponse, ApiError> {
|
|
||||||
let blog = create_blog(&state.conn, params)
|
|
||||||
.await
|
|
||||||
.map_err(ApiError::from)?;
|
|
||||||
|
|
||||||
let blog = blog.try_into_model().unwrap();
|
|
||||||
Ok((StatusCode::CREATED, Json(BlogSchema::from(blog))))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[utoipa::path(
|
|
||||||
get,
|
|
||||||
path = "",
|
|
||||||
params(
|
|
||||||
BlogQuery
|
|
||||||
),
|
|
||||||
responses(
|
|
||||||
(status = 200, description = "List blogs", body = BlogListSchema),
|
|
||||||
(status = 500, description = "Internal server error", body = ApiErrorResponse),
|
|
||||||
)
|
|
||||||
)]
|
|
||||||
async fn blogs_get(
|
|
||||||
state: State<AppState>,
|
|
||||||
query: Query<BlogQuery>,
|
|
||||||
) -> Result<impl IntoResponse, ApiError> {
|
|
||||||
let Query(query) = query;
|
|
||||||
|
|
||||||
let blogs = search_blogs(&state.conn, query)
|
|
||||||
.await
|
|
||||||
.map_err(ApiError::from)?;
|
|
||||||
Ok(Json(BlogListSchema::from(blogs)))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn create_blog_router() -> Router<AppState> {
|
|
||||||
Router::new().route("/", get(blogs_get).post(blogs_post))
|
|
||||||
}
|
|
@@ -1,11 +1,9 @@
|
|||||||
use axum::Router;
|
use axum::Router;
|
||||||
|
|
||||||
pub mod blog;
|
|
||||||
pub mod root;
|
pub mod root;
|
||||||
pub mod user;
|
pub mod user;
|
||||||
|
|
||||||
use app::state::AppState;
|
use app::state::AppState;
|
||||||
use blog::create_blog_router;
|
|
||||||
use root::create_root_router;
|
use root::create_root_router;
|
||||||
use user::create_user_router;
|
use user::create_user_router;
|
||||||
|
|
||||||
@@ -13,6 +11,5 @@ pub fn create_router(state: AppState) -> Router {
|
|||||||
Router::new()
|
Router::new()
|
||||||
.merge(create_root_router())
|
.merge(create_root_router())
|
||||||
.nest("/users", create_user_router())
|
.nest("/users", create_user_router())
|
||||||
.nest("/blogs", create_blog_router())
|
|
||||||
.with_state(state)
|
.with_state(state)
|
||||||
}
|
}
|
||||||
|
@@ -1,24 +0,0 @@
|
|||||||
use sea_orm::{ActiveModelTrait, ColumnTrait, DbConn, DbErr, EntityTrait, QueryFilter, Set};
|
|
||||||
|
|
||||||
use models::{domains::blog, params::blog::CreateBlogParams, queries::blog::BlogQuery};
|
|
||||||
|
|
||||||
pub async fn search_blogs(db: &DbConn, query: BlogQuery) -> Result<Vec<blog::Model>, DbErr> {
|
|
||||||
blog::Entity::find()
|
|
||||||
.filter(blog::Column::Title.contains(query.title.unwrap_or_default()))
|
|
||||||
.all(db)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn create_blog(
|
|
||||||
db: &DbConn,
|
|
||||||
params: CreateBlogParams,
|
|
||||||
) -> Result<blog::ActiveModel, DbErr> {
|
|
||||||
blog::ActiveModel {
|
|
||||||
author_id: Set(params.author_id as i32),
|
|
||||||
title: Set(params.title),
|
|
||||||
content: Set(params.content),
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
.save(db)
|
|
||||||
.await
|
|
||||||
}
|
|
@@ -1,2 +1 @@
|
|||||||
pub mod blog;
|
|
||||||
pub mod user;
|
pub mod user;
|
||||||
|
9
thoughts-backend/common/Cargo.toml
Normal file
9
thoughts-backend/common/Cargo.toml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
[package]
|
||||||
|
name = "common"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
serde = { workspace = true }
|
||||||
|
utoipa = { workspace = true }
|
||||||
|
sea-orm = { workspace = true }
|
14
thoughts-backend/common/src/lib.rs
Normal file
14
thoughts-backend/common/src/lib.rs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
use sea_orm::prelude::DateTimeWithTimeZone;
|
||||||
|
use serde::Serialize;
|
||||||
|
use utoipa::ToSchema;
|
||||||
|
|
||||||
|
// Wrapper type for DateTimeWithTimeZone
|
||||||
|
#[derive(Serialize, ToSchema)]
|
||||||
|
#[schema(example = "2025-09-05T12:34:56Z")] // Example for OpenAPI
|
||||||
|
pub struct DateTimeWithTimeZoneWrapper(String);
|
||||||
|
|
||||||
|
impl From<DateTimeWithTimeZone> for DateTimeWithTimeZoneWrapper {
|
||||||
|
fn from(value: DateTimeWithTimeZone) -> Self {
|
||||||
|
DateTimeWithTimeZoneWrapper(value.to_rfc3339())
|
||||||
|
}
|
||||||
|
}
|
@@ -1,20 +0,0 @@
|
|||||||
use utoipa::OpenApi;
|
|
||||||
|
|
||||||
use models::params::blog::CreateBlogParams;
|
|
||||||
use models::schemas::blog::{BlogListSchema, BlogSchema};
|
|
||||||
|
|
||||||
use api::models::{ApiErrorResponse, ParamsErrorResponse};
|
|
||||||
use api::routers::blog::*;
|
|
||||||
|
|
||||||
#[derive(OpenApi)]
|
|
||||||
#[openapi(
|
|
||||||
paths(blogs_get, blogs_post),
|
|
||||||
components(schemas(
|
|
||||||
CreateBlogParams,
|
|
||||||
BlogListSchema,
|
|
||||||
BlogSchema,
|
|
||||||
ApiErrorResponse,
|
|
||||||
ParamsErrorResponse,
|
|
||||||
))
|
|
||||||
)]
|
|
||||||
pub(super) struct BlogApi;
|
|
@@ -3,7 +3,6 @@ use utoipa::OpenApi;
|
|||||||
use utoipa_scalar::{Scalar, Servable as ScalarServable};
|
use utoipa_scalar::{Scalar, Servable as ScalarServable};
|
||||||
use utoipa_swagger_ui::SwaggerUi;
|
use utoipa_swagger_ui::SwaggerUi;
|
||||||
|
|
||||||
mod blog;
|
|
||||||
mod root;
|
mod root;
|
||||||
mod user;
|
mod user;
|
||||||
|
|
||||||
@@ -12,13 +11,10 @@ mod user;
|
|||||||
nest(
|
nest(
|
||||||
(path = "/", api = root::RootApi),
|
(path = "/", api = root::RootApi),
|
||||||
(path = "/users", api = user::UserApi),
|
(path = "/users", api = user::UserApi),
|
||||||
(path = "/blogs", api = blog::BlogApi),
|
|
||||||
),
|
),
|
||||||
tags(
|
tags(
|
||||||
(name = "root", description = "Root API"),
|
(name = "root", description = "Root API"),
|
||||||
(name = "user", description = "User API"),
|
(name = "user", description = "User API"),
|
||||||
(name = "blog", description = "Blog API"),
|
|
||||||
|
|
||||||
)
|
)
|
||||||
)]
|
)]
|
||||||
struct _ApiDoc;
|
struct _ApiDoc;
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
pub use sea_orm_migration::prelude::*;
|
pub use sea_orm_migration::prelude::*;
|
||||||
|
|
||||||
mod m20240101_000001_init;
|
mod m20240101_000001_init;
|
||||||
mod m20240816_160144_blog;
|
mod m20250905_000001_init;
|
||||||
|
|
||||||
pub struct Migrator;
|
pub struct Migrator;
|
||||||
|
|
||||||
@@ -10,7 +10,7 @@ impl MigratorTrait for Migrator {
|
|||||||
fn migrations() -> Vec<Box<dyn MigrationTrait>> {
|
fn migrations() -> Vec<Box<dyn MigrationTrait>> {
|
||||||
vec![
|
vec![
|
||||||
Box::new(m20240101_000001_init::Migration),
|
Box::new(m20240101_000001_init::Migration),
|
||||||
Box::new(m20240816_160144_blog::Migration),
|
Box::new(m20250905_000001_init::Migration),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,47 +0,0 @@
|
|||||||
use sea_orm_migration::{prelude::*, schema::*};
|
|
||||||
|
|
||||||
use super::m20240101_000001_init::User;
|
|
||||||
|
|
||||||
#[derive(DeriveMigrationName)]
|
|
||||||
pub struct Migration;
|
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
|
||||||
impl MigrationTrait for Migration {
|
|
||||||
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
|
||||||
manager
|
|
||||||
.create_table(
|
|
||||||
Table::create()
|
|
||||||
.table(Blog::Table)
|
|
||||||
.if_not_exists()
|
|
||||||
.col(pk_auto(Blog::Id))
|
|
||||||
.col(integer(Blog::AuthorId).not_null())
|
|
||||||
.foreign_key(
|
|
||||||
ForeignKey::create()
|
|
||||||
.name("fk_blog_author_id")
|
|
||||||
.from(Blog::Table, Blog::AuthorId)
|
|
||||||
.to(User::Table, User::Id)
|
|
||||||
.on_update(ForeignKeyAction::NoAction)
|
|
||||||
.on_delete(ForeignKeyAction::Cascade),
|
|
||||||
)
|
|
||||||
.col(ColumnDef::new(Blog::Title).string().not_null())
|
|
||||||
.col(ColumnDef::new(Blog::Content).string().not_null())
|
|
||||||
.to_owned(),
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
|
||||||
manager
|
|
||||||
.drop_table(Table::drop().table(Blog::Table).to_owned())
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(DeriveIden)]
|
|
||||||
enum Blog {
|
|
||||||
Table,
|
|
||||||
Id,
|
|
||||||
AuthorId,
|
|
||||||
Title,
|
|
||||||
Content,
|
|
||||||
}
|
|
95
thoughts-backend/migration/src/m20250905_000001_init.rs
Normal file
95
thoughts-backend/migration/src/m20250905_000001_init.rs
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
use super::m20240101_000001_init::User;
|
||||||
|
use sea_orm_migration::{prelude::*, schema::*};
|
||||||
|
|
||||||
|
#[derive(DeriveMigrationName)]
|
||||||
|
pub struct Migration;
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl MigrationTrait for Migration {
|
||||||
|
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||||
|
// --- Create Thought Table ---
|
||||||
|
manager
|
||||||
|
.create_table(
|
||||||
|
Table::create()
|
||||||
|
.table(Thought::Table)
|
||||||
|
.if_not_exists()
|
||||||
|
.col(pk_auto(Thought::Id))
|
||||||
|
.col(integer(Thought::AuthorId).not_null())
|
||||||
|
.foreign_key(
|
||||||
|
ForeignKey::create()
|
||||||
|
.name("fk_thought_author_id")
|
||||||
|
.from(Thought::Table, Thought::AuthorId)
|
||||||
|
.to(User::Table, User::Id)
|
||||||
|
.on_update(ForeignKeyAction::NoAction)
|
||||||
|
.on_delete(ForeignKeyAction::Cascade),
|
||||||
|
)
|
||||||
|
.col(string(Thought::Content).not_null())
|
||||||
|
.col(
|
||||||
|
timestamp_with_time_zone(Thought::CreatedAt)
|
||||||
|
.not_null()
|
||||||
|
.default(Expr::current_timestamp()),
|
||||||
|
)
|
||||||
|
.to_owned(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
// --- Create Follow Table ---
|
||||||
|
manager
|
||||||
|
.create_table(
|
||||||
|
Table::create()
|
||||||
|
.table(Follow::Table)
|
||||||
|
.if_not_exists()
|
||||||
|
.col(integer(Follow::FollowerId).not_null())
|
||||||
|
.col(integer(Follow::FollowedId).not_null())
|
||||||
|
// Composite Primary Key to ensure a user can only follow another once
|
||||||
|
.primary_key(
|
||||||
|
Index::create()
|
||||||
|
.col(Follow::FollowerId)
|
||||||
|
.col(Follow::FollowedId),
|
||||||
|
)
|
||||||
|
.foreign_key(
|
||||||
|
ForeignKey::create()
|
||||||
|
.name("fk_follow_follower_id")
|
||||||
|
.from(Follow::Table, Follow::FollowerId)
|
||||||
|
.to(User::Table, User::Id)
|
||||||
|
.on_delete(ForeignKeyAction::Cascade),
|
||||||
|
)
|
||||||
|
.foreign_key(
|
||||||
|
ForeignKey::create()
|
||||||
|
.name("fk_follow_followed_id")
|
||||||
|
.from(Follow::Table, Follow::FollowedId)
|
||||||
|
.to(User::Table, User::Id)
|
||||||
|
.on_delete(ForeignKeyAction::Cascade),
|
||||||
|
)
|
||||||
|
.to_owned(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||||
|
manager
|
||||||
|
.drop_table(Table::drop().table(Follow::Table).to_owned())
|
||||||
|
.await?;
|
||||||
|
manager
|
||||||
|
.drop_table(Table::drop().table(Thought::Table).to_owned())
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(DeriveIden)]
|
||||||
|
enum Thought {
|
||||||
|
Table,
|
||||||
|
Id,
|
||||||
|
AuthorId,
|
||||||
|
Content,
|
||||||
|
CreatedAt,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(DeriveIden)]
|
||||||
|
enum Follow {
|
||||||
|
Table,
|
||||||
|
// The user who is initiating the follow
|
||||||
|
FollowerId,
|
||||||
|
// The user who is being followed
|
||||||
|
FollowedId,
|
||||||
|
}
|
@@ -19,3 +19,5 @@ sea-orm = { workspace = true, features = [
|
|||||||
] }
|
] }
|
||||||
validator = { workspace = true, features = ["derive"] }
|
validator = { workspace = true, features = ["derive"] }
|
||||||
utoipa = { workspace = true }
|
utoipa = { workspace = true }
|
||||||
|
|
||||||
|
common = { path = "../common" }
|
||||||
|
32
thoughts-backend/models/src/domains/follow.rs
Normal file
32
thoughts-backend/models/src/domains/follow.rs
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
||||||
|
#[sea_orm(table_name = "follow")]
|
||||||
|
pub struct Model {
|
||||||
|
#[sea_orm(primary_key)]
|
||||||
|
pub follower_id: i32,
|
||||||
|
#[sea_orm(primary_key)]
|
||||||
|
pub followed_id: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||||
|
pub enum Relation {
|
||||||
|
#[sea_orm(
|
||||||
|
belongs_to = "super::user::Entity",
|
||||||
|
from = "Column::FollowerId",
|
||||||
|
to = "super::user::Column::Id",
|
||||||
|
on_update = "NoAction",
|
||||||
|
on_delete = "Cascade"
|
||||||
|
)]
|
||||||
|
Follower,
|
||||||
|
#[sea_orm(
|
||||||
|
belongs_to = "super::user::Entity",
|
||||||
|
from = "Column::FollowedId",
|
||||||
|
to = "super::user::Column::Id",
|
||||||
|
on_update = "NoAction",
|
||||||
|
on_delete = "Cascade"
|
||||||
|
)]
|
||||||
|
Followed,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ActiveModelBehavior for ActiveModel {}
|
@@ -2,5 +2,6 @@
|
|||||||
|
|
||||||
pub mod prelude;
|
pub mod prelude;
|
||||||
|
|
||||||
pub mod blog;
|
pub mod follow;
|
||||||
|
pub mod thought;
|
||||||
pub mod user;
|
pub mod user;
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
//! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.0
|
//! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.0
|
||||||
|
|
||||||
pub use super::blog::Entity as Blog;
|
pub use super::follow::Entity as Follow;
|
||||||
|
pub use super::thought::Entity as Thought;
|
||||||
pub use super::user::Entity as User;
|
pub use super::user::Entity as User;
|
||||||
|
@@ -1,15 +1,13 @@
|
|||||||
//! `SeaORM` Entity, @generated by sea-orm-codegen 1.0.0
|
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
||||||
#[sea_orm(table_name = "blog")]
|
#[sea_orm(table_name = "thought")]
|
||||||
pub struct Model {
|
pub struct Model {
|
||||||
#[sea_orm(primary_key)]
|
#[sea_orm(primary_key)]
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub author_id: i32,
|
pub author_id: i32,
|
||||||
pub title: String,
|
|
||||||
pub content: String,
|
pub content: String,
|
||||||
|
pub created_at: DateTimeWithTimeZone,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
@@ -12,15 +12,6 @@ pub struct Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||||
pub enum Relation {
|
pub enum Relation {}
|
||||||
#[sea_orm(has_many = "super::blog::Entity")]
|
|
||||||
Blog,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Related<super::blog::Entity> for Entity {
|
|
||||||
fn to() -> RelationDef {
|
|
||||||
Relation::Blog.def()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ActiveModelBehavior for ActiveModel {}
|
impl ActiveModelBehavior for ActiveModel {}
|
||||||
|
@@ -1,14 +0,0 @@
|
|||||||
use serde::Deserialize;
|
|
||||||
use utoipa::ToSchema;
|
|
||||||
use validator::Validate;
|
|
||||||
|
|
||||||
#[derive(Deserialize, Validate, ToSchema)]
|
|
||||||
pub struct CreateBlogParams {
|
|
||||||
pub author_id: u32,
|
|
||||||
|
|
||||||
#[validate(length(min = 2))]
|
|
||||||
pub title: String,
|
|
||||||
|
|
||||||
#[validate(length(min = 2))]
|
|
||||||
pub content: String,
|
|
||||||
}
|
|
@@ -1,2 +1,2 @@
|
|||||||
pub mod blog;
|
pub mod thought;
|
||||||
pub mod user;
|
pub mod user;
|
||||||
|
11
thoughts-backend/models/src/params/thought.rs
Normal file
11
thoughts-backend/models/src/params/thought.rs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
use serde::Deserialize;
|
||||||
|
use utoipa::ToSchema;
|
||||||
|
use validator::Validate;
|
||||||
|
|
||||||
|
#[derive(Deserialize, Validate, ToSchema)]
|
||||||
|
pub struct CreateThoughtParams {
|
||||||
|
pub author_id: i32,
|
||||||
|
|
||||||
|
#[validate(length(min = 1, max = 128))]
|
||||||
|
pub content: String,
|
||||||
|
}
|
@@ -1,9 +0,0 @@
|
|||||||
use serde::Deserialize;
|
|
||||||
use utoipa::IntoParams;
|
|
||||||
|
|
||||||
#[derive(Deserialize, Default, IntoParams)]
|
|
||||||
#[into_params(style = Form, parameter_in = Query)]
|
|
||||||
pub struct BlogQuery {
|
|
||||||
#[param(nullable = true)]
|
|
||||||
pub title: Option<String>,
|
|
||||||
}
|
|
@@ -1,2 +1 @@
|
|||||||
pub mod blog;
|
|
||||||
pub mod user;
|
pub mod user;
|
||||||
|
@@ -1,36 +0,0 @@
|
|||||||
use serde::Serialize;
|
|
||||||
use utoipa::ToSchema;
|
|
||||||
|
|
||||||
use crate::domains::blog;
|
|
||||||
|
|
||||||
#[derive(Serialize, ToSchema)]
|
|
||||||
pub struct BlogSchema {
|
|
||||||
pub id: u32,
|
|
||||||
pub title: String,
|
|
||||||
pub content: String,
|
|
||||||
pub author_id: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<blog::Model> for BlogSchema {
|
|
||||||
fn from(blog: blog::Model) -> Self {
|
|
||||||
Self {
|
|
||||||
id: blog.id as u32,
|
|
||||||
title: blog.title,
|
|
||||||
content: blog.content,
|
|
||||||
author_id: blog.author_id as u32,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, ToSchema)]
|
|
||||||
pub struct BlogListSchema {
|
|
||||||
pub blogs: Vec<BlogSchema>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Vec<blog::Model>> for BlogListSchema {
|
|
||||||
fn from(blogs: Vec<blog::Model>) -> Self {
|
|
||||||
Self {
|
|
||||||
blogs: blogs.into_iter().map(BlogSchema::from).collect(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,2 +1,2 @@
|
|||||||
pub mod blog;
|
pub mod thought;
|
||||||
pub mod user;
|
pub mod user;
|
||||||
|
36
thoughts-backend/models/src/schemas/thought.rs
Normal file
36
thoughts-backend/models/src/schemas/thought.rs
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
use crate::domains::thought;
|
||||||
|
use common::DateTimeWithTimeZoneWrapper;
|
||||||
|
use serde::Serialize;
|
||||||
|
use utoipa::ToSchema;
|
||||||
|
|
||||||
|
#[derive(Serialize, ToSchema)]
|
||||||
|
pub struct ThoughtSchema {
|
||||||
|
pub id: i32,
|
||||||
|
pub author_id: i32,
|
||||||
|
pub content: String,
|
||||||
|
pub created_at: DateTimeWithTimeZoneWrapper,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<thought::Model> for ThoughtSchema {
|
||||||
|
fn from(model: thought::Model) -> Self {
|
||||||
|
Self {
|
||||||
|
id: model.id,
|
||||||
|
author_id: model.author_id,
|
||||||
|
content: model.content,
|
||||||
|
created_at: model.created_at.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, ToSchema)]
|
||||||
|
pub struct ThoughtListSchema {
|
||||||
|
pub thoughts: Vec<ThoughtSchema>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Vec<thought::Model>> for ThoughtListSchema {
|
||||||
|
fn from(models: Vec<thought::Model>) -> Self {
|
||||||
|
Self {
|
||||||
|
thoughts: models.into_iter().map(ThoughtSchema::from).collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -1,30 +0,0 @@
|
|||||||
use axum::{http::StatusCode, Router};
|
|
||||||
use http_body_util::BodyExt;
|
|
||||||
use serde_json::Value;
|
|
||||||
|
|
||||||
use utils::testing::{make_get_request, make_post_request};
|
|
||||||
|
|
||||||
pub(super) async fn test_post_blogs(app: Router) {
|
|
||||||
let response = make_post_request(
|
|
||||||
app,
|
|
||||||
"/blogs",
|
|
||||||
r#"{"author_id": 1, "title": "title", "content": "test"}"#.to_owned(),
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
|
|
||||||
assert_eq!(response.status(), StatusCode::CREATED);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) async fn test_get_blogs(app: Router) {
|
|
||||||
let response = make_get_request(app, "/blogs").await;
|
|
||||||
assert_eq!(response.status(), StatusCode::OK);
|
|
||||||
|
|
||||||
let body = response.into_body().collect().await.unwrap().to_bytes();
|
|
||||||
let result: Value = serde_json::from_slice(&body).unwrap();
|
|
||||||
assert_eq!(result["blogs"].as_array().unwrap().len(), 1);
|
|
||||||
|
|
||||||
let blog = &result["blogs"][0];
|
|
||||||
assert_eq!(blog["author_id"], 1);
|
|
||||||
assert_eq!(blog["title"], "title");
|
|
||||||
assert_eq!(blog["content"], "test");
|
|
||||||
}
|
|
@@ -1,11 +1,9 @@
|
|||||||
use api::setup_router;
|
use api::setup_router;
|
||||||
use utils::testing::setup_test_db;
|
use utils::testing::setup_test_db;
|
||||||
|
|
||||||
mod blog;
|
|
||||||
mod root;
|
mod root;
|
||||||
mod user;
|
mod user;
|
||||||
|
|
||||||
use blog::*;
|
|
||||||
use root::*;
|
use root::*;
|
||||||
use user::*;
|
use user::*;
|
||||||
|
|
||||||
@@ -30,15 +28,3 @@ async fn user_main() {
|
|||||||
test_post_users_error(app.clone()).await;
|
test_post_users_error(app.clone()).await;
|
||||||
test_get_users(app).await;
|
test_get_users(app).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn blog_main() {
|
|
||||||
let db = setup_test_db("sqlite::blog?mode=memory&cache=shared")
|
|
||||||
.await
|
|
||||||
.expect("Set up db failed!");
|
|
||||||
|
|
||||||
let app = setup_router(db);
|
|
||||||
test_post_users(app.clone()).await;
|
|
||||||
test_post_blogs(app.clone()).await;
|
|
||||||
test_get_blogs(app).await;
|
|
||||||
}
|
|
||||||
|
@@ -1,22 +0,0 @@
|
|||||||
use sea_orm::{DatabaseConnection, Unchanged};
|
|
||||||
|
|
||||||
use app::persistence::blog::create_blog;
|
|
||||||
use models::domains::blog;
|
|
||||||
use models::params::blog::CreateBlogParams;
|
|
||||||
|
|
||||||
pub(super) async fn test_blog(db: &DatabaseConnection) {
|
|
||||||
let params = CreateBlogParams {
|
|
||||||
author_id: 1,
|
|
||||||
title: "title".to_string(),
|
|
||||||
content: "test".to_string(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let blog = create_blog(db, params).await.expect("Create blog failed!");
|
|
||||||
let expected = blog::ActiveModel {
|
|
||||||
id: Unchanged(1),
|
|
||||||
author_id: Unchanged(1),
|
|
||||||
title: Unchanged("title".to_owned()),
|
|
||||||
content: Unchanged("test".to_owned()),
|
|
||||||
};
|
|
||||||
assert_eq!(blog, expected);
|
|
||||||
}
|
|
@@ -1,9 +1,7 @@
|
|||||||
use utils::testing::setup_test_db;
|
use utils::testing::setup_test_db;
|
||||||
|
|
||||||
mod blog;
|
|
||||||
mod user;
|
mod user;
|
||||||
|
|
||||||
use blog::test_blog;
|
|
||||||
use user::test_user;
|
use user::test_user;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -14,13 +12,3 @@ async fn user_main() {
|
|||||||
|
|
||||||
test_user(&db).await;
|
test_user(&db).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn blog_main() {
|
|
||||||
let db = setup_test_db("sqlite::memory:")
|
|
||||||
.await
|
|
||||||
.expect("Set up db failed!");
|
|
||||||
|
|
||||||
test_user(&db).await;
|
|
||||||
test_blog(&db).await;
|
|
||||||
}
|
|
||||||
|
Reference in New Issue
Block a user