Upgrade and organize
This commit is contained in:
parent
cad12e7a76
commit
a192a1584e
497
Cargo.lock
generated
497
Cargo.lock
generated
@ -79,10 +79,12 @@ dependencies = [
|
||||
"ahash 0.8.3",
|
||||
"base64 0.21.0",
|
||||
"bitflags 1.3.2",
|
||||
"brotli",
|
||||
"bytes",
|
||||
"bytestring",
|
||||
"derive_more",
|
||||
"encoding_rs",
|
||||
"flate2",
|
||||
"futures-core",
|
||||
"h2",
|
||||
"http",
|
||||
@ -100,6 +102,17 @@ dependencies = [
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tracing",
|
||||
"zstd",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "actix-macros"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "465a6172cf69b960917811022d8f29bc0b7fa1398bc4f78b3c466673db1213b6"
|
||||
dependencies = [
|
||||
"quote 1.0.26",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -159,6 +172,7 @@ version = "2.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "15265b6b8e2347670eb363c47fc8c75208b4a4994b27192f345fcbe707804f3e"
|
||||
dependencies = [
|
||||
"actix-macros",
|
||||
"futures-core",
|
||||
"tokio",
|
||||
]
|
||||
@ -210,15 +224,18 @@ checksum = "cd3cb42f9566ab176e1ef0b8b3a896529062b4efc6be0123046095914c4c1c96"
|
||||
dependencies = [
|
||||
"actix-codec",
|
||||
"actix-http",
|
||||
"actix-macros",
|
||||
"actix-router",
|
||||
"actix-rt",
|
||||
"actix-server",
|
||||
"actix-service",
|
||||
"actix-utils",
|
||||
"actix-web-codegen",
|
||||
"ahash 0.7.6",
|
||||
"bytes",
|
||||
"bytestring",
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if",
|
||||
"cookie",
|
||||
"derive_more",
|
||||
"encoding_rs",
|
||||
"futures-core",
|
||||
@ -240,6 +257,36 @@ dependencies = [
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "actix-web-actors"
|
||||
version = "4.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf6e9ccc371cfddbed7aa842256a4abc7a6dcac9f3fce392fe1d0f68cfd136b2"
|
||||
dependencies = [
|
||||
"actix",
|
||||
"actix-codec",
|
||||
"actix-http",
|
||||
"actix-web",
|
||||
"bytes",
|
||||
"bytestring",
|
||||
"futures-core",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "actix-web-codegen"
|
||||
version = "4.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2262160a7ae29e3415554a3f1fc04c764b1540c116aa524683208078b7a75bc9"
|
||||
dependencies = [
|
||||
"actix-router",
|
||||
"proc-macro2 1.0.54",
|
||||
"quote 1.0.26",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "actix_derive"
|
||||
version = "0.6.0"
|
||||
@ -274,7 +321,7 @@ version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if",
|
||||
"getrandom",
|
||||
"once_cell",
|
||||
"version_check 0.9.4",
|
||||
@ -289,6 +336,21 @@ dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "alloc-no-stdlib"
|
||||
version = "2.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3"
|
||||
|
||||
[[package]]
|
||||
name = "alloc-stdlib"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece"
|
||||
dependencies = [
|
||||
"alloc-no-stdlib",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "amazon-actor"
|
||||
version = "0.1.0"
|
||||
@ -296,7 +358,6 @@ dependencies = [
|
||||
"actix",
|
||||
"bitque-config",
|
||||
"bytes",
|
||||
"common",
|
||||
"futures",
|
||||
"libc",
|
||||
"openssl-sys",
|
||||
@ -305,6 +366,7 @@ dependencies = [
|
||||
"rusoto_signature",
|
||||
"serde",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"uuid 1.3.0",
|
||||
]
|
||||
|
||||
@ -478,10 +540,11 @@ name = "bitque"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"actix",
|
||||
"actix-rt",
|
||||
"actix-web",
|
||||
"amazon-actor",
|
||||
"bitque-config",
|
||||
"bitque-data",
|
||||
"common",
|
||||
"database-actor",
|
||||
"dotenv",
|
||||
"filesystem-actor",
|
||||
@ -494,6 +557,8 @@ dependencies = [
|
||||
"serde_json",
|
||||
"tokio",
|
||||
"toml",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
"web-actor",
|
||||
"websocket-actor",
|
||||
]
|
||||
@ -516,7 +581,7 @@ dependencies = [
|
||||
"actix",
|
||||
"chrono",
|
||||
"diesel 2.0.3",
|
||||
"diesel-derive-enum",
|
||||
"diesel-derive-enum 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"diesel-derive-more",
|
||||
"diesel-derive-newtype",
|
||||
"serde",
|
||||
@ -525,38 +590,12 @@ dependencies = [
|
||||
"uuid 1.3.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitque_client"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"bitque-data",
|
||||
"chrono",
|
||||
"console_error_panic_hook",
|
||||
"derive_enum_iter",
|
||||
"derive_enum_primitive",
|
||||
"dotenv",
|
||||
"futures",
|
||||
"js-sys",
|
||||
"seed",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tracing",
|
||||
"uuid 1.3.0",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"wasm-bindgen-test",
|
||||
"web-sys",
|
||||
"wee_alloc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitquec"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"actix",
|
||||
"clap",
|
||||
"common",
|
||||
"termion 2.0.1",
|
||||
"tui",
|
||||
]
|
||||
@ -579,6 +618,27 @@ dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "brotli"
|
||||
version = "3.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1a0b1dbcc8ae29329621f8d4f0d835787c1c38bb1401979b49d13b0b305ff68"
|
||||
dependencies = [
|
||||
"alloc-no-stdlib",
|
||||
"alloc-stdlib",
|
||||
"brotli-decompressor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "brotli-decompressor"
|
||||
version = "2.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4b6561fd3f895a11e8f72af2cb7d22e08366bebc2b6b57f7744c4bda27034744"
|
||||
dependencies = [
|
||||
"alloc-no-stdlib",
|
||||
"alloc-stdlib",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.12.0"
|
||||
@ -617,12 +677,9 @@ name = "cc"
|
||||
version = "1.0.79"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||
dependencies = [
|
||||
"jobserver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
@ -708,10 +765,6 @@ dependencies = [
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "common"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "comrak"
|
||||
version = "0.18.0"
|
||||
@ -746,22 +799,23 @@ dependencies = [
|
||||
"windows-sys 0.45.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "console_error_panic_hook"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "convert_case"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
|
||||
|
||||
[[package]]
|
||||
name = "cookie"
|
||||
version = "0.16.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb"
|
||||
dependencies = [
|
||||
"percent-encoding",
|
||||
"time 0.3.20",
|
||||
"version_check 0.9.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation"
|
||||
version = "0.9.3"
|
||||
@ -793,7 +847,7 @@ version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -802,7 +856,7 @@ version = "0.5.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf2b3e8478797446514c91ef04bafcb59faba183e621ad488df88983cc14128c"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
@ -812,7 +866,7 @@ version = "0.8.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -951,7 +1005,6 @@ dependencies = [
|
||||
"bitque-data",
|
||||
"byteorder",
|
||||
"chrono",
|
||||
"common",
|
||||
"derive_db_execute",
|
||||
"diesel 2.0.3",
|
||||
"dotenv",
|
||||
@ -985,10 +1038,6 @@ version = "0.1.0"
|
||||
name = "derive_enum_primitive"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "derive_enum_sql"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "derive_more"
|
||||
version = "0.99.17"
|
||||
@ -1041,6 +1090,16 @@ dependencies = [
|
||||
"uuid 1.3.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "diesel-derive-enum"
|
||||
version = "2.0.1"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2 1.0.54",
|
||||
"quote 1.0.26",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "diesel-derive-enum"
|
||||
version = "2.0.1"
|
||||
@ -1132,7 +1191,7 @@ version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if",
|
||||
"dirs-sys-next",
|
||||
]
|
||||
|
||||
@ -1195,12 +1254,6 @@ version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2153bd83ebc09db15bcbdc3e2194d901804952e3dc96967e1cd3b0c5c32d112"
|
||||
|
||||
[[package]]
|
||||
name = "enclose"
|
||||
version = "1.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1056f553da426e9c025a662efa48b52e62e0a3a7648aa2d15aeaaf7f0d329357"
|
||||
|
||||
[[package]]
|
||||
name = "encoding"
|
||||
version = "0.2.33"
|
||||
@ -1271,7 +1324,7 @@ version = "0.8.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1348,7 +1401,6 @@ dependencies = [
|
||||
"actix-files",
|
||||
"bitque-config",
|
||||
"bytes",
|
||||
"common",
|
||||
"futures",
|
||||
"tokio",
|
||||
]
|
||||
@ -1504,59 +1556,9 @@ version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"js-sys",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gloo-events"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68b107f8abed8105e4182de63845afcc7b69c098b7852a813ea7462a320992fc"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gloo-file"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8d5564e570a38b43d78bdc063374a0c3098c4f0d64005b12f9bbe87e869b6d7"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"gloo-events",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gloo-timers"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gloo-utils"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8e8fc851e9c7b9852508bc6e3f690f452f474417e8545ec9857b7f7377036b5"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1619,7 +1621,6 @@ dependencies = [
|
||||
"bincode",
|
||||
"bitque-config",
|
||||
"bitque-data",
|
||||
"common",
|
||||
"flate2",
|
||||
"lazy_static",
|
||||
"serde",
|
||||
@ -1782,7 +1783,7 @@ version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1823,6 +1824,15 @@ version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
|
||||
|
||||
[[package]]
|
||||
name = "jobserver"
|
||||
version = "0.1.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.61"
|
||||
@ -1967,7 +1977,7 @@ version = "0.4.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1976,7 +1986,6 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"actix",
|
||||
"bitque-config",
|
||||
"common",
|
||||
"dotenv",
|
||||
"futures",
|
||||
"lettre 0.10.3",
|
||||
@ -1995,6 +2004,15 @@ version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4"
|
||||
|
||||
[[package]]
|
||||
name = "matchers"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
|
||||
dependencies = [
|
||||
"regex-automata",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "md-5"
|
||||
version = "0.9.1"
|
||||
@ -2012,12 +2030,6 @@ version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||
|
||||
[[package]]
|
||||
name = "memory_units"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8452105ba047068f40ff7093dd1d9da90898e63dd61736462e9cdda6a90ad3c3"
|
||||
|
||||
[[package]]
|
||||
name = "mime"
|
||||
version = "0.3.17"
|
||||
@ -2089,6 +2101,16 @@ dependencies = [
|
||||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-ansi-term"
|
||||
version = "0.46.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
|
||||
dependencies = [
|
||||
"overload",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.4.3"
|
||||
@ -2176,7 +2198,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "518915b97df115dd36109bfa429a48b8f737bd05508cf9588977b599648926d2"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if",
|
||||
"foreign-types",
|
||||
"libc",
|
||||
"once_cell",
|
||||
@ -2224,6 +2246,12 @@ dependencies = [
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "overload"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.1"
|
||||
@ -2240,7 +2268,7 @@ version = "0.9.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall 0.2.16",
|
||||
"smallvec",
|
||||
@ -2623,6 +2651,15 @@ dependencies = [
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
|
||||
dependencies = [
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.29"
|
||||
@ -2793,12 +2830,6 @@ dependencies = [
|
||||
"parking_lot",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scoped-tls"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.1.0"
|
||||
@ -2834,28 +2865,6 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "seed"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c0e296ea0569d20467e9a1df3cb6ed66ce3b791a7eaf1e1110ae231f75e2b46"
|
||||
dependencies = [
|
||||
"enclose",
|
||||
"futures",
|
||||
"getrandom",
|
||||
"gloo-file",
|
||||
"gloo-timers",
|
||||
"gloo-utils",
|
||||
"indexmap",
|
||||
"js-sys",
|
||||
"rand 0.8.5",
|
||||
"uuid 1.3.0",
|
||||
"version_check 0.9.4",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "1.0.17"
|
||||
@ -2929,7 +2938,7 @@ version = "0.10.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"digest 0.10.6",
|
||||
]
|
||||
@ -2947,12 +2956,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800"
|
||||
dependencies = [
|
||||
"block-buffer 0.9.0",
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"digest 0.9.0",
|
||||
"opaque-debug",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sharded-slab"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shell-words"
|
||||
version = "1.1.0"
|
||||
@ -3039,12 +3057,6 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.10.0"
|
||||
@ -3153,7 +3165,7 @@ version = "3.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if",
|
||||
"fastrand",
|
||||
"redox_syscall 0.3.5",
|
||||
"rustix 0.37.5",
|
||||
@ -3223,6 +3235,16 @@ dependencies = [
|
||||
"syn 2.0.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "1.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.1.45"
|
||||
@ -3376,7 +3398,7 @@ version = "0.1.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if",
|
||||
"log",
|
||||
"pin-project-lite",
|
||||
"tracing-attributes",
|
||||
@ -3401,6 +3423,37 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"valuable",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-log"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"log",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-subscriber"
|
||||
version = "0.3.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70"
|
||||
dependencies = [
|
||||
"matchers",
|
||||
"nu-ansi-term",
|
||||
"once_cell",
|
||||
"regex",
|
||||
"serde_json",
|
||||
"sharded-slab",
|
||||
"smallvec",
|
||||
"thread_local",
|
||||
"tracing",
|
||||
"tracing-core",
|
||||
"tracing-log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3532,6 +3585,12 @@ dependencies = [
|
||||
"sha1_smol",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "valuable"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
@ -3588,7 +3647,7 @@ version = "0.2.84"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if",
|
||||
"wasm-bindgen-macro",
|
||||
]
|
||||
|
||||
@ -3607,18 +3666,6 @@ dependencies = [
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-futures"
|
||||
version = "0.4.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.84"
|
||||
@ -3648,41 +3695,19 @@ version = "0.2.84"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-test"
|
||||
version = "0.3.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6db36fc0f9fb209e88fb3642590ae0205bb5a56216dabd963ba15879fe53a30b"
|
||||
dependencies = [
|
||||
"console_error_panic_hook",
|
||||
"js-sys",
|
||||
"scoped-tls",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"wasm-bindgen-test-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-test-macro"
|
||||
version = "0.3.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0734759ae6b3b1717d661fe4f016efcfb9828f5edb4520c18eaee05af3b43be9"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.54",
|
||||
"quote 1.0.26",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "web-actor"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"actix",
|
||||
"actix-multipart",
|
||||
"actix-web",
|
||||
"actix-web-actors",
|
||||
"amazon-actor",
|
||||
"bincode",
|
||||
"bitque-config",
|
||||
"bitque-data",
|
||||
"common",
|
||||
"bytes",
|
||||
"database-actor",
|
||||
"filesystem-actor",
|
||||
"futures",
|
||||
@ -3692,30 +3717,22 @@ dependencies = [
|
||||
"serde",
|
||||
"tokio",
|
||||
"toml",
|
||||
"tracing",
|
||||
"uuid 1.3.0",
|
||||
"websocket-actor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.61"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "websocket-actor"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"actix",
|
||||
"actix-web",
|
||||
"actix-web-actors",
|
||||
"async-trait",
|
||||
"bincode",
|
||||
"bitque-config",
|
||||
"bitque-data",
|
||||
"common",
|
||||
"comrak",
|
||||
"database-actor",
|
||||
"flate2",
|
||||
@ -3728,22 +3745,10 @@ dependencies = [
|
||||
"serde",
|
||||
"syntect",
|
||||
"toml",
|
||||
"tracing",
|
||||
"uuid 1.3.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wee_alloc"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dbb3b5a6b2bb17cb6ad44a2e68a43e8d2722c997da10e928665c72ec6c0a0b8e"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10",
|
||||
"libc",
|
||||
"memory_units",
|
||||
"spin",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
@ -3960,3 +3965,33 @@ name = "zeroize"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9"
|
||||
|
||||
[[package]]
|
||||
name = "zstd"
|
||||
version = "0.12.3+zstd.1.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "76eea132fb024e0e13fd9c2f5d5d595d8a967aa72382ac2f9d39fcc95afd0806"
|
||||
dependencies = [
|
||||
"zstd-safe",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zstd-safe"
|
||||
version = "6.0.4+zstd.1.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7afb4b54b8910cf5447638cb54bf4e8a65cbedd783af98b98c62ffe91f185543"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"zstd-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zstd-sys"
|
||||
version = "2.0.7+zstd.1.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94509c3ba2fe55294d752b79842c530ccfab760192521df74a081a78d2b3c7f5"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
]
|
||||
|
@ -10,7 +10,6 @@
|
||||
|
||||
[workspace]
|
||||
members = [
|
||||
"./crates/common",
|
||||
"./crates/bitque-cli",
|
||||
"./crates/bitque-server",
|
||||
"./crates/bitque-config",
|
||||
@ -27,11 +26,14 @@ members = [
|
||||
"./crates/amazon-actor",
|
||||
"./crates/filesystem-actor",
|
||||
# Client
|
||||
"./crates/web"
|
||||
# "./crates/web"
|
||||
]
|
||||
exclude = [
|
||||
"crates/bitque-cli",
|
||||
"crates/web",
|
||||
]
|
||||
|
||||
[workspace.dependencies]
|
||||
common = { path = "./crates/common" }
|
||||
bitque-cli = { path = "./crates/bitque-cli" }
|
||||
bitque-server = { path = "./crates/bitque-server" }
|
||||
bitque-config = { path = "./crates/bitque-config" }
|
||||
|
@ -15,8 +15,7 @@ path = "./src/lib.rs"
|
||||
[dependencies]
|
||||
actix = { version = "0.13.0" }
|
||||
bitque-config = { workspace = true, features = ["mail", "web", "local-storage"] }
|
||||
bytes = { version = "1.0.0" }
|
||||
common = { workspace = true }
|
||||
bytes = { version = "1" }
|
||||
futures = { version = "0.3.8" }
|
||||
libc = { version = "0.2.0", default-features = false }
|
||||
openssl-sys = { version = "*", features = ["vendored"] }
|
||||
@ -25,4 +24,5 @@ rusoto_s3 = { version = "0.48.0" }
|
||||
rusoto_signature = { version = "0.48.0" }
|
||||
serde = { version = "*" }
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
tracing = { version = "0.1.37" }
|
||||
uuid = { version = "1.3.0", features = ["serde", "v4", "v5"] }
|
||||
|
@ -1,4 +1,3 @@
|
||||
extern crate common;
|
||||
use rusoto_s3::{PutObjectRequest, S3Client, S3};
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -21,7 +20,7 @@ impl actix::Actor for AmazonExecutor {
|
||||
#[derive(actix::Message)]
|
||||
#[rtype(result = "Result<String, AmazonError>")]
|
||||
pub struct S3PutObject {
|
||||
pub source: tokio::sync::broadcast::Receiver<common::bytes::Bytes>,
|
||||
pub source: tokio::sync::broadcast::Receiver<bytes::Bytes>,
|
||||
pub file_name: String,
|
||||
}
|
||||
|
||||
@ -40,7 +39,7 @@ impl actix::Handler<S3PutObject> for AmazonExecutor {
|
||||
.expect("Failed to start amazon agent")
|
||||
.block_on(async {
|
||||
let s3 = bitque_config::amazon::config();
|
||||
::tracing::debug!("{:?}", s3);
|
||||
tracing::debug!("{:?}", s3);
|
||||
|
||||
// TODO: Unable to upload as stream because there is no size_hint
|
||||
// let stream = source
|
||||
@ -50,10 +49,9 @@ impl actix::Handler<S3PutObject> for AmazonExecutor {
|
||||
// use common::bytes::Buf;
|
||||
// ::bytes::Bytes::from(b.bytes())
|
||||
// });
|
||||
use common::bytes::Buf;
|
||||
let mut v: Vec<u8> = vec![];
|
||||
while let Ok(b) = source.recv().await {
|
||||
v.extend_from_slice(b.bytes())
|
||||
v.extend_from_slice(&b)
|
||||
}
|
||||
|
||||
let client = S3Client::new(s3.region());
|
||||
|
@ -7,6 +7,5 @@ edition = "2018"
|
||||
[dependencies]
|
||||
actix = { version = "0.13.0" }
|
||||
clap = { version = "4.1.13" }
|
||||
common = { workspace = true }
|
||||
termion = { version = "*" }
|
||||
tui = { version = "0.19.0", features = ["termion"] }
|
||||
|
@ -5,12 +5,11 @@ use std::sync::{mpsc, Arc};
|
||||
use std::time::Duration;
|
||||
|
||||
use termion::event::Key;
|
||||
use termion::input::MouseTerminal;
|
||||
use termion::raw::IntoRawMode;
|
||||
use termion::screen::AlternateScreen;
|
||||
use termion::screen::IntoAlternateScreen;
|
||||
use tui::backend::TermionBackend;
|
||||
use tui::layout::{Constraint, Direction, Layout};
|
||||
use tui::style::{Color, Style};
|
||||
use tui::text::{Span, Spans};
|
||||
use tui::widgets::{Block, Borders, Tabs};
|
||||
use tui::Terminal;
|
||||
|
||||
@ -126,9 +125,7 @@ struct App<'a> {
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
// Terminal initialization
|
||||
let stdout = io::stdout().into_raw_mode()?;
|
||||
let stdout = MouseTerminal::from(stdout);
|
||||
let stdout = AlternateScreen::from(stdout);
|
||||
let stdout = io::stdout().into_alternate_screen().unwrap();
|
||||
let backend = TermionBackend::new(stdout);
|
||||
let mut terminal = Terminal::new(backend)?;
|
||||
terminal.hide_cursor()?;
|
||||
@ -142,7 +139,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||
|
||||
// Main loop
|
||||
loop {
|
||||
terminal.draw(|mut f| {
|
||||
terminal.draw(|f| {
|
||||
let size = f.size();
|
||||
let chunks = Layout::default()
|
||||
.direction(Direction::Vertical)
|
||||
@ -152,12 +149,17 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||
|
||||
let block = Block::default().style(Style::default().bg(Color::White));
|
||||
f.render_widget(block, size);
|
||||
let tabs = Tabs::default()
|
||||
.block(Block::default().borders(Borders::ALL).title("Tabs"))
|
||||
.titles(&app.tabs.titles)
|
||||
.select(app.tabs.index)
|
||||
.style(Style::default().fg(Color::Cyan))
|
||||
.highlight_style(Style::default().fg(Color::Yellow));
|
||||
let tabs = Tabs::new(
|
||||
app.tabs
|
||||
.titles
|
||||
.iter()
|
||||
.map(|s| Spans::from(vec![Span::styled(*s, Style::default())]))
|
||||
.collect(),
|
||||
)
|
||||
.block(Block::default().borders(Borders::ALL).title("Tabs"))
|
||||
.select(app.tabs.index)
|
||||
.style(Style::default().fg(Color::Cyan))
|
||||
.highlight_style(Style::default().fg(Color::Yellow));
|
||||
f.render_widget(tabs, chunks[0]);
|
||||
let inner = match app.tabs.index {
|
||||
0 => Block::default().title("Inner 0").borders(Borders::ALL),
|
||||
|
@ -21,6 +21,7 @@ actix = { version = "0.13.0", optional = true }
|
||||
chrono = { version = "*", features = ["serde"] }
|
||||
diesel = { version = "2.0.3", features = ["postgres", "numeric", "uuid", "r2d2"], optional = true }
|
||||
diesel-derive-enum = { version = "2.0.1", features = ["postgres"] }
|
||||
#diesel-derive-enum = { path = "../derive_enum_sql", features = ["postgres"] }
|
||||
diesel-derive-more = { version = "1.1.3" }
|
||||
diesel-derive-newtype = { version = "2.0.0-rc.0", optional = true }
|
||||
serde = { version = "*" }
|
||||
|
@ -2,15 +2,15 @@ use std::cmp::Ordering;
|
||||
|
||||
use chrono::NaiveDateTime;
|
||||
#[cfg(feature = "backend")]
|
||||
use diesel_derive_enum::DbEnum;
|
||||
#[cfg(feature = "backend")]
|
||||
use diesel::*;
|
||||
#[cfg(feature = "backend")]
|
||||
use diesel_derive_enum::DbEnum;
|
||||
pub use fields::*;
|
||||
pub use msg::WsMsg;
|
||||
pub use payloads::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
use strum::*;
|
||||
use uuid::Uuid;
|
||||
|
||||
pub mod fields;
|
||||
pub mod msg;
|
||||
@ -52,7 +52,18 @@ pub type EndsAt = NaiveDateTime;
|
||||
|
||||
#[cfg_attr(feature = "backend", derive(DbEnum))]
|
||||
#[derive(
|
||||
Clone, Copy, Debug, Deserialize, Display, EnumIter, EnumString, Hash, IntoStaticStr, PartialEq, PartialOrd, Serialize,
|
||||
Clone,
|
||||
Copy,
|
||||
Debug,
|
||||
Deserialize,
|
||||
Display,
|
||||
EnumIter,
|
||||
EnumString,
|
||||
Hash,
|
||||
IntoStaticStr,
|
||||
PartialEq,
|
||||
PartialOrd,
|
||||
Serialize,
|
||||
)]
|
||||
#[strum(serialize_all = "snake_case")]
|
||||
pub enum IssueType {
|
||||
@ -69,7 +80,18 @@ impl Default for IssueType {
|
||||
|
||||
#[cfg_attr(feature = "backend", derive(DbEnum))]
|
||||
#[derive(
|
||||
Clone, Copy, Debug, Deserialize, Display, EnumIter, EnumString, Hash, IntoStaticStr, PartialEq, PartialOrd, Serialize,
|
||||
Clone,
|
||||
Copy,
|
||||
Debug,
|
||||
Deserialize,
|
||||
Display,
|
||||
EnumIter,
|
||||
EnumString,
|
||||
Hash,
|
||||
IntoStaticStr,
|
||||
PartialEq,
|
||||
PartialOrd,
|
||||
Serialize,
|
||||
)]
|
||||
#[strum(serialize_all = "snake_case")]
|
||||
pub enum IssuePriority {
|
||||
@ -87,7 +109,19 @@ impl Default for IssuePriority {
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "backend", derive(DbEnum))]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Display, EnumIter, EnumString, Hash, IntoStaticStr, PartialEq, Serialize)]
|
||||
#[derive(
|
||||
Clone,
|
||||
Copy,
|
||||
Debug,
|
||||
Deserialize,
|
||||
Display,
|
||||
EnumIter,
|
||||
EnumString,
|
||||
Hash,
|
||||
IntoStaticStr,
|
||||
PartialEq,
|
||||
Serialize,
|
||||
)]
|
||||
#[strum(serialize_all = "snake_case")]
|
||||
pub enum UserRole {
|
||||
User,
|
||||
@ -117,8 +151,20 @@ impl Default for UserRole {
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "backend", derive(DbEnum))]
|
||||
#[cfg_attr(feature = "backend", PgType = "ProjectCategoryMapping")]
|
||||
#[derive(
|
||||
Clone, Copy, Debug, Deserialize, Display, EnumIter, EnumString, Hash, IntoStaticStr, PartialEq, PartialOrd, Serialize,
|
||||
Clone,
|
||||
Copy,
|
||||
Debug,
|
||||
Deserialize,
|
||||
Display,
|
||||
EnumIter,
|
||||
EnumString,
|
||||
Hash,
|
||||
IntoStaticStr,
|
||||
PartialEq,
|
||||
PartialOrd,
|
||||
Serialize,
|
||||
)]
|
||||
#[strum(serialize_all = "snake_case")]
|
||||
pub enum ProjectCategory {
|
||||
@ -134,8 +180,20 @@ impl Default for ProjectCategory {
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "backend", derive(DbEnum))]
|
||||
#[cfg_attr(feature = "backend", PgType = "InvitationStateMapping")]
|
||||
#[derive(
|
||||
Clone, Copy, Debug, Deserialize, Display, EnumIter, EnumString, Hash, IntoStaticStr, PartialEq, PartialOrd, Serialize,
|
||||
Clone,
|
||||
Copy,
|
||||
Debug,
|
||||
Deserialize,
|
||||
Display,
|
||||
EnumIter,
|
||||
EnumString,
|
||||
Hash,
|
||||
IntoStaticStr,
|
||||
PartialEq,
|
||||
PartialOrd,
|
||||
Serialize,
|
||||
)]
|
||||
#[strum(serialize_all = "snake_case")]
|
||||
pub enum InvitationState {
|
||||
@ -151,8 +209,20 @@ impl Default for InvitationState {
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "backend", derive(DbEnum))]
|
||||
#[cfg_attr(feature = "backend", PgType = "TimeTrackingMapping")]
|
||||
#[derive(
|
||||
Clone, Copy, Debug, Deserialize, Display, EnumIter, EnumString, Hash, IntoStaticStr, PartialEq, PartialOrd, Serialize,
|
||||
Clone,
|
||||
Copy,
|
||||
Debug,
|
||||
Deserialize,
|
||||
Display,
|
||||
EnumIter,
|
||||
EnumString,
|
||||
Hash,
|
||||
IntoStaticStr,
|
||||
PartialEq,
|
||||
PartialOrd,
|
||||
Serialize,
|
||||
)]
|
||||
#[strum(serialize_all = "snake_case")]
|
||||
pub enum TimeTracking {
|
||||
@ -311,8 +381,19 @@ pub struct IssueAssignee {
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "backend", derive(DbEnum))]
|
||||
#[cfg_attr(feature = "backend", PgType = "MessageTypeMapping")]
|
||||
#[derive(
|
||||
Clone, Copy, Debug, Deserialize, Display, EnumString, Hash, IntoStaticStr, PartialEq, PartialOrd, Serialize,
|
||||
Clone,
|
||||
Copy,
|
||||
Debug,
|
||||
Deserialize,
|
||||
Display,
|
||||
EnumString,
|
||||
Hash,
|
||||
IntoStaticStr,
|
||||
PartialEq,
|
||||
PartialOrd,
|
||||
Serialize,
|
||||
)]
|
||||
#[strum(serialize_all = "snake_case")]
|
||||
pub enum MessageType {
|
||||
@ -391,9 +472,21 @@ pub struct HighlightedCode {
|
||||
|
||||
#[cfg_attr(feature = "backend", derive(DbEnum))]
|
||||
#[derive(
|
||||
Clone, Copy, Debug, Deserialize, Display, EnumIter, EnumString, Hash, IntoStaticStr, PartialEq, PartialOrd, Serialize,
|
||||
Clone,
|
||||
Copy,
|
||||
Debug,
|
||||
Deserialize,
|
||||
Display,
|
||||
EnumIter,
|
||||
EnumString,
|
||||
Hash,
|
||||
IntoStaticStr,
|
||||
PartialEq,
|
||||
PartialOrd,
|
||||
Serialize,
|
||||
)]
|
||||
#[strum(serialize_all = "snake_case")]
|
||||
#[cfg_attr(feature = "backend", PgType = "TextEditorModeMapping")]
|
||||
#[repr(C)]
|
||||
pub enum TextEditorMode {
|
||||
MdOnly,
|
||||
|
@ -15,10 +15,11 @@ default = ["local-storage"]
|
||||
|
||||
[dependencies]
|
||||
actix = { version = "0" }
|
||||
actix-rt = { version = "2" }
|
||||
actix-web = { version = "4" }
|
||||
amazon-actor = { workspace = true, optional = true }
|
||||
bitque-config = { workspace = true, features = ["web", "websocket", "local-storage", "hi", "database"] }
|
||||
bitque-data = { workspace = true, features = ["backend"] }
|
||||
common = { workspace = true }
|
||||
database-actor = { workspace = true }
|
||||
dotenv = { version = "*" }
|
||||
filesystem-actor = { workspace = true, optional = true }
|
||||
@ -31,5 +32,7 @@ serde = { version = "*", features = ["derive"] }
|
||||
serde_json = { version = ">=0.8.0, <2.0" }
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
toml = { version = "0.7.3" }
|
||||
tracing = "0"
|
||||
tracing-subscriber = { version = "0", features = ['env-filter', 'thread_local', 'serde_json'] }
|
||||
web-actor = { workspace = true, features = ["local-storage"] }
|
||||
websocket-actor = { workspace = true }
|
||||
|
@ -1 +0,0 @@
|
||||
../LICENSE
|
@ -1,5 +1,4 @@
|
||||
use actix_web::HttpResponse;
|
||||
use common::*;
|
||||
use bitque_data::msg::WsError;
|
||||
use bitque_data::ErrorResponse;
|
||||
|
||||
|
@ -1,11 +1,9 @@
|
||||
#![feature(async_closure)]
|
||||
#![recursion_limit = "256"]
|
||||
|
||||
extern crate common;
|
||||
|
||||
use actix::Actor;
|
||||
use actix_web::{App, HttpServer};
|
||||
use common::*;
|
||||
use tracing_subscriber::util::SubscriberInitExt;
|
||||
|
||||
pub mod errors;
|
||||
|
||||
@ -19,7 +17,10 @@ macro_rules! featured {
|
||||
#[actix_rt::main]
|
||||
async fn main() -> Result<(), String> {
|
||||
dotenv::dotenv().ok();
|
||||
pretty_env_logger::init();
|
||||
tracing_subscriber::fmt::fmt()
|
||||
.with_env_filter(tracing_subscriber::filter::EnvFilter::from_default_env())
|
||||
.finish()
|
||||
.init();
|
||||
|
||||
let web_config = bitque_config::web::Configuration::read();
|
||||
|
||||
@ -53,12 +54,12 @@ async fn main() -> Result<(), String> {
|
||||
|
||||
// data step
|
||||
let app = app
|
||||
.data(ws_server.clone())
|
||||
.data(db_addr.clone())
|
||||
.data(mail_addr.clone())
|
||||
.data(hi_addr.clone())
|
||||
.data(database_actor::build_pool());
|
||||
featured! { app, "local-storage", app.data(fs_addr.clone()) };
|
||||
.app_data(ws_server.clone())
|
||||
.app_data(db_addr.clone())
|
||||
.app_data(mail_addr.clone())
|
||||
.app_data(hi_addr.clone())
|
||||
.app_data(database_actor::build_pool());
|
||||
featured! { app, "local-storage", app.app_data(fs_addr.clone()) };
|
||||
featured! { app, "aws-s3", app.data(amazon_addr.clone()) };
|
||||
|
||||
// services step
|
||||
|
@ -1,10 +0,0 @@
|
||||
[package]
|
||||
name = "common"
|
||||
version = "0.1.0"
|
||||
authors = ["Adrian Wozniak <adrian.wozniak@ita-prog.pl>"]
|
||||
edition = "2018"
|
||||
description = "JIRS (Simplified JIRA in Rust) Actix server"
|
||||
repository = "https://gitlab.com/adrian.wozniak/bitque"
|
||||
license = "MPL-2.0"
|
||||
|
||||
[dependencies]
|
@ -21,7 +21,6 @@ bitque-config = { workspace = true, features = ["database"] }
|
||||
bitque-data = { workspace = true, features = ["backend"] }
|
||||
byteorder = { version = "1.0" }
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
common = { workspace = true }
|
||||
derive_db_execute = { workspace = true }
|
||||
diesel = { version = "2.0.3", features = ["postgres", "numeric", "uuid", "r2d2", "chrono"] }
|
||||
dotenv = { version = "*" }
|
||||
|
141
crates/database-actor/schema.patch
Normal file
141
crates/database-actor/schema.patch
Normal file
@ -0,0 +1,141 @@
|
||||
diff --git a/crates/database-actor/src/schema.rs b/crates/database-actor/src/schema.rs
|
||||
index 34a35365..a8f775b2 100644
|
||||
--- a/crates/database-actor/src/schema.rs
|
||||
+++ b/crates/database-actor/src/schema.rs
|
||||
@@ -37,19 +37,19 @@ diesel::table! {
|
||||
use bitque_data::*;
|
||||
|
||||
invitations (id) {
|
||||
id -> Int4,
|
||||
name -> Text,
|
||||
email -> Text,
|
||||
- state -> InvitationState,
|
||||
+ state -> InvitationStateMapping,
|
||||
project_id -> Int4,
|
||||
invited_by_id -> Int4,
|
||||
created_at -> Timestamp,
|
||||
updated_at -> Timestamp,
|
||||
bind_token -> Uuid,
|
||||
- role -> UserRole,
|
||||
+ role -> UserRoleMapping,
|
||||
}
|
||||
}
|
||||
|
||||
diesel::table! {
|
||||
use diesel::sql_types::*;
|
||||
use bitque_data::*;
|
||||
@@ -81,14 +81,14 @@ diesel::table! {
|
||||
use diesel::sql_types::*;
|
||||
use bitque_data::*;
|
||||
|
||||
issues (id) {
|
||||
id -> Int4,
|
||||
title -> Text,
|
||||
- issue_type -> IssueType,
|
||||
- priority -> IssuePriority,
|
||||
+ issue_type -> IssueTypeMapping,
|
||||
+ priority -> IssuePriorityMapping,
|
||||
list_position -> Int4,
|
||||
description -> Nullable<Text>,
|
||||
description_text -> Nullable<Text>,
|
||||
estimate -> Nullable<Int4>,
|
||||
time_spent -> Nullable<Int4>,
|
||||
time_remaining -> Nullable<Int4>,
|
||||
@@ -108,13 +108,13 @@ diesel::table! {
|
||||
messages (id) {
|
||||
id -> Int4,
|
||||
receiver_id -> Int4,
|
||||
sender_id -> Int4,
|
||||
summary -> Text,
|
||||
description -> Text,
|
||||
- message_type -> MessageType,
|
||||
+ message_type -> MessageTypeMapping,
|
||||
hyper_link -> Text,
|
||||
created_at -> Timestamp,
|
||||
updated_at -> Timestamp,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,16 +124,16 @@ diesel::table! {
|
||||
|
||||
projects (id) {
|
||||
id -> Int4,
|
||||
name -> Text,
|
||||
url -> Text,
|
||||
description -> Text,
|
||||
- category -> ProjectCategory,
|
||||
+ category -> ProjectCategoryMapping,
|
||||
created_at -> Timestamp,
|
||||
updated_at -> Timestamp,
|
||||
- time_tracking -> TimeTracking,
|
||||
+ time_tracking -> TimeTrackingMapping,
|
||||
}
|
||||
}
|
||||
|
||||
diesel::table! {
|
||||
use diesel::sql_types::*;
|
||||
use bitque_data::*;
|
||||
@@ -156,26 +156,26 @@ diesel::table! {
|
||||
user_projects (id) {
|
||||
id -> Int4,
|
||||
user_id -> Int4,
|
||||
project_id -> Int4,
|
||||
is_default -> Bool,
|
||||
is_current -> Bool,
|
||||
- role -> UserRole,
|
||||
+ role -> UserRoleMapping,
|
||||
created_at -> Timestamp,
|
||||
updated_at -> Timestamp,
|
||||
}
|
||||
}
|
||||
|
||||
diesel::table! {
|
||||
use diesel::sql_types::*;
|
||||
use bitque_data::*;
|
||||
|
||||
user_settings (id) {
|
||||
id -> Int4,
|
||||
user_id -> Int4,
|
||||
- text_editor_mode -> TextEditorMode,
|
||||
+ text_editor_mode -> TextEditorModeMapping,
|
||||
}
|
||||
}
|
||||
|
||||
diesel::table! {
|
||||
use diesel::sql_types::*;
|
||||
use bitque_data::*;
|
||||
@@ -205,20 +205,20 @@ diesel::joinable!(issues -> projects (project_id));
|
||||
diesel::joinable!(issues -> users (reporter_id));
|
||||
diesel::joinable!(tokens -> users (user_id));
|
||||
diesel::joinable!(user_projects -> projects (project_id));
|
||||
diesel::joinable!(user_projects -> users (user_id));
|
||||
diesel::joinable!(user_settings -> users (user_id));
|
||||
|
||||
-diesel::allow_tables_to_appear_in_same_query!(
|
||||
- comments,
|
||||
- epics,
|
||||
- invitations,
|
||||
- issue_assignees,
|
||||
- issue_statuses,
|
||||
- issues,
|
||||
- messages,
|
||||
- projects,
|
||||
- tokens,
|
||||
- user_projects,
|
||||
- user_settings,
|
||||
- users,
|
||||
-);
|
||||
+// diesel::allow_tables_to_appear_in_same_query!(
|
||||
+// comments,
|
||||
+// epics,
|
||||
+// invitations,
|
||||
+// issue_assignees,
|
||||
+// issue_statuses,
|
||||
+// issues,
|
||||
+// messages,
|
||||
+// projects,
|
||||
+// tokens,
|
||||
+// user_projects,
|
||||
+// user_settings,
|
||||
+// users,
|
||||
+// );
|
@ -1,5 +1,5 @@
|
||||
use diesel::prelude::*;
|
||||
use bitque_data::User;
|
||||
use diesel::prelude::*;
|
||||
|
||||
use crate::db_find;
|
||||
use crate::tokens::FindAccessToken;
|
||||
|
@ -1,5 +1,5 @@
|
||||
use diesel::prelude::*;
|
||||
use bitque_data::{Comment, CommentId, IssueId, UserId};
|
||||
use diesel::prelude::*;
|
||||
|
||||
use crate::{db_create, db_delete, db_load, db_update};
|
||||
|
||||
|
@ -1,10 +1,9 @@
|
||||
use derive_db_execute::Execute;
|
||||
use diesel::prelude::*;
|
||||
use bitque_data::{DescriptionString, EndsAt, Epic, EpicId, ProjectId, StartsAt};
|
||||
use diesel::prelude::*;
|
||||
|
||||
use crate::{db_create, db_delete, db_load, db_update};
|
||||
|
||||
#[derive(Execute)]
|
||||
#[derive(derive_db_execute::Execute)]
|
||||
#[db_exec(schema = "epics", result = "Epic", find = "epics.find(msg.epic_id)")]
|
||||
pub struct FindEpic {
|
||||
pub epic_id: EpicId,
|
||||
|
@ -1,15 +1,15 @@
|
||||
use actix::{Handler, Message};
|
||||
use diesel::prelude::*;
|
||||
use bitque_data::{
|
||||
EmailString, Invitation, InvitationId, InvitationState, InvitationToken, ProjectId, Token,
|
||||
User, UserId, UserRole, UsernameString,
|
||||
};
|
||||
use diesel::prelude::*;
|
||||
|
||||
use crate::tokens::CreateBindToken;
|
||||
use crate::users::{LookupUser, Register};
|
||||
use crate::{
|
||||
db_create, db_delete, db_find, db_load, db_pool, db_update, DbExecutor, DbPooledConn,
|
||||
InvitationError,
|
||||
db_create, db_delete, db_find, db_load, db_pool, db_update, DatabaseError, DbExecutor,
|
||||
DbPooledConn, InvitationError,
|
||||
};
|
||||
|
||||
db_find! {
|
||||
@ -80,12 +80,12 @@ impl Handler<RevokeInvitation> for DbExecutor {
|
||||
type Result = Result<(), crate::DatabaseError>;
|
||||
|
||||
fn handle(&mut self, msg: RevokeInvitation, _ctx: &mut Self::Context) -> Self::Result {
|
||||
let conn = db_pool!(self);
|
||||
let mut conn = db_pool!(self);
|
||||
UpdateInvitationState {
|
||||
id: msg.id,
|
||||
state: InvitationState::Revoked,
|
||||
}
|
||||
.execute(conn)?;
|
||||
.execute(&mut conn)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@ -95,63 +95,75 @@ pub struct AcceptInvitation {
|
||||
}
|
||||
|
||||
impl AcceptInvitation {
|
||||
pub fn execute(self, conn: &DbPooledConn) -> Result<Token, crate::DatabaseError> {
|
||||
crate::Guard::new(conn)?.run::<Token, _>(|_guard| {
|
||||
let invitation = crate::invitations::FindByBindToken {
|
||||
token: self.invitation_token,
|
||||
pub fn execute(self, conn: &mut DbPooledConn) -> Result<Token, crate::DatabaseError> {
|
||||
let mut res = Err(DatabaseError::DatabaseConnectionLost);
|
||||
conn.transaction(|conn| {
|
||||
res = self.exec_in_transaction(conn);
|
||||
if res.is_err() {
|
||||
Err(diesel::NotFound)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
.execute(conn)?;
|
||||
})
|
||||
.ok();
|
||||
res
|
||||
}
|
||||
|
||||
if invitation.state == InvitationState::Revoked {
|
||||
return Err(crate::DatabaseError::Invitation(
|
||||
InvitationError::InvitationRevoked,
|
||||
));
|
||||
}
|
||||
fn exec_in_transaction(self, conn: &mut DbPooledConn) -> Result<Token, crate::DatabaseError> {
|
||||
let invitation = FindByBindToken {
|
||||
token: self.invitation_token,
|
||||
}
|
||||
.execute(conn)?;
|
||||
|
||||
crate::invitations::UpdateInvitationState {
|
||||
id: invitation.id,
|
||||
state: InvitationState::Accepted,
|
||||
}
|
||||
.execute(conn)?;
|
||||
if invitation.state == InvitationState::Revoked {
|
||||
return Err(crate::DatabaseError::Invitation(
|
||||
InvitationError::InvitationRevoked,
|
||||
));
|
||||
}
|
||||
|
||||
UpdateInvitationState {
|
||||
id: invitation.id,
|
||||
state: InvitationState::Accepted,
|
||||
}
|
||||
.execute(conn)?;
|
||||
UpdateInvitationState {
|
||||
id: invitation.id,
|
||||
state: InvitationState::Accepted,
|
||||
}
|
||||
.execute(conn)?;
|
||||
|
||||
match {
|
||||
Register {
|
||||
name: invitation.name.clone(),
|
||||
email: invitation.email.clone(),
|
||||
project_id: Some(invitation.project_id),
|
||||
role: UserRole::User,
|
||||
}
|
||||
.execute(conn)
|
||||
} {
|
||||
Ok(_) => (),
|
||||
Err(crate::DatabaseError::User(crate::UserError::InvalidPair(..))) => (),
|
||||
Err(e) => return Err(e),
|
||||
};
|
||||
UpdateInvitationState {
|
||||
id: invitation.id,
|
||||
state: InvitationState::Accepted,
|
||||
}
|
||||
.execute(conn)?;
|
||||
|
||||
let user: User = LookupUser {
|
||||
match {
|
||||
Register {
|
||||
name: invitation.name.clone(),
|
||||
email: invitation.email.clone(),
|
||||
project_id: Some(invitation.project_id),
|
||||
role: UserRole::User,
|
||||
}
|
||||
.execute(conn)?;
|
||||
CreateBindToken { user_id: user.id }.execute(conn)?;
|
||||
.execute(conn)
|
||||
} {
|
||||
Ok(_) => (),
|
||||
Err(crate::DatabaseError::User(crate::UserError::InvalidPair(..))) => (),
|
||||
Err(e) => return Err(e),
|
||||
};
|
||||
|
||||
crate::user_projects::CreateUserProject {
|
||||
user_id: user.id,
|
||||
project_id: invitation.project_id,
|
||||
is_current: false,
|
||||
is_default: false,
|
||||
role: invitation.role,
|
||||
}
|
||||
.execute(conn)?;
|
||||
let user: User = LookupUser {
|
||||
name: invitation.name.clone(),
|
||||
email: invitation.email.clone(),
|
||||
}
|
||||
.execute(conn)?;
|
||||
CreateBindToken { user_id: user.id }.execute(conn)?;
|
||||
|
||||
crate::tokens::FindUserId { user_id: user.id }.execute(conn)
|
||||
})
|
||||
crate::user_projects::CreateUserProject {
|
||||
user_id: user.id,
|
||||
project_id: invitation.project_id,
|
||||
is_current: false,
|
||||
is_default: false,
|
||||
role: invitation.role,
|
||||
}
|
||||
.execute(conn)?;
|
||||
|
||||
crate::tokens::FindUserId { user_id: user.id }.execute(conn)
|
||||
}
|
||||
}
|
||||
|
||||
@ -163,8 +175,8 @@ impl Handler<AcceptInvitation> for DbExecutor {
|
||||
type Result = Result<Token, crate::DatabaseError>;
|
||||
|
||||
fn handle(&mut self, msg: AcceptInvitation, _ctx: &mut Self::Context) -> Self::Result {
|
||||
let conn = db_pool!(self);
|
||||
let mut conn = db_pool!(self);
|
||||
|
||||
msg.execute(conn)
|
||||
msg.execute(&mut conn)
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use diesel::prelude::*;
|
||||
use diesel::dsl::not;
|
||||
use bitque_data::{IssueAssignee, IssueId, UserId};
|
||||
use diesel::dsl::not;
|
||||
use diesel::prelude::*;
|
||||
|
||||
use crate::{db_create, db_delete, db_load, db_load_field};
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
use diesel::prelude::*;
|
||||
use bitque_data::{IssueStatus, IssueStatusId, Position, ProjectId, TitleString};
|
||||
use diesel::prelude::*;
|
||||
|
||||
use crate::{db_create, db_delete, db_load, db_update};
|
||||
|
||||
|
@ -1,11 +1,10 @@
|
||||
use derive_db_execute::Execute;
|
||||
use bitque_data::{IssueId, IssuePriority, IssueStatusId, IssueType, ProjectId, UserId};
|
||||
use diesel::dsl::sql;
|
||||
use diesel::prelude::*;
|
||||
use bitque_data::{IssueId, IssuePriority, IssueStatusId, IssueType, ProjectId, UserId};
|
||||
|
||||
use crate::models::Issue;
|
||||
|
||||
#[derive(Default, Execute)]
|
||||
#[derive(derive_db_execute::Execute, Default)]
|
||||
#[db_exec(
|
||||
result = "Issue",
|
||||
schema = "issues",
|
||||
@ -15,7 +14,7 @@ pub struct LoadIssue {
|
||||
pub issue_id: IssueId,
|
||||
}
|
||||
|
||||
#[derive(Execute)]
|
||||
#[derive(derive_db_execute::Execute)]
|
||||
#[db_exec(
|
||||
result = "Issue",
|
||||
schema = "issues",
|
||||
@ -25,7 +24,7 @@ pub struct LoadProjectIssues {
|
||||
pub project_id: ProjectId,
|
||||
}
|
||||
|
||||
#[derive(Default, Execute)]
|
||||
#[derive(derive_db_execute::Execute, Default)]
|
||||
#[db_exec(result = "Issue", schema = "issues")]
|
||||
pub struct UpdateIssue {
|
||||
pub issue_id: bitque_data::IssueId,
|
||||
@ -46,7 +45,7 @@ pub struct UpdateIssue {
|
||||
}
|
||||
|
||||
impl UpdateIssue {
|
||||
fn execute(self, conn: &crate::DbPooledConn) -> Result<Issue, crate::DatabaseError> {
|
||||
fn execute(self, conn: &mut crate::DbPooledConn) -> Result<Issue, crate::DatabaseError> {
|
||||
let msg = self;
|
||||
use crate::schema::issues::dsl::*;
|
||||
if let Some(user_ids) = msg.user_ids {
|
||||
@ -97,7 +96,7 @@ impl UpdateIssue {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Execute)]
|
||||
#[derive(derive_db_execute::Execute)]
|
||||
#[db_exec(
|
||||
result = "Issue",
|
||||
schema = "issues",
|
||||
@ -112,9 +111,9 @@ pub struct DeleteIssue {
|
||||
}
|
||||
|
||||
mod inner {
|
||||
use bitque_data::{IssuePriority, IssueStatusId, IssueType};
|
||||
use derive_db_execute::Execute;
|
||||
use diesel::prelude::*;
|
||||
use bitque_data::{IssuePriority, IssueStatusId, IssueType};
|
||||
|
||||
use crate::models::Issue;
|
||||
|
||||
@ -159,7 +158,7 @@ mod inner {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Execute)]
|
||||
#[derive(derive_db_execute::Execute)]
|
||||
#[db_exec(result = "Issue", schema = "issues")]
|
||||
pub struct CreateIssue {
|
||||
pub title: String,
|
||||
@ -171,19 +170,21 @@ pub struct CreateIssue {
|
||||
pub estimate: Option<i32>,
|
||||
pub time_spent: Option<i32>,
|
||||
pub time_remaining: Option<i32>,
|
||||
pub project_id: bitque_data::ProjectId,
|
||||
pub reporter_id: bitque_data::UserId,
|
||||
pub user_ids: Vec<bitque_data::UserId>,
|
||||
pub project_id: ProjectId,
|
||||
pub reporter_id: UserId,
|
||||
pub user_ids: Vec<UserId>,
|
||||
pub epic_id: Option<bitque_data::EpicId>,
|
||||
}
|
||||
|
||||
impl CreateIssue {
|
||||
fn execute(self, conn: &crate::DbPooledConn) -> Result<Issue, crate::DatabaseError> {
|
||||
fn execute(self, conn: &mut crate::DbPooledConn) -> Result<Issue, crate::DatabaseError> {
|
||||
use crate::schema::issues::dsl::*;
|
||||
let msg = self;
|
||||
|
||||
let pos = issues
|
||||
.select(sql("COALESCE(max(list_position), 0) + 1"))
|
||||
.select(sql::<diesel::sql_types::Integer>(
|
||||
"COALESCE(max(list_position), 0) + 1",
|
||||
))
|
||||
.get_result::<i32>(conn)
|
||||
.map_err(|e| {
|
||||
::tracing::error!("resolve new issue position failed {}", e);
|
||||
|
@ -63,47 +63,3 @@ pub trait SyncQuery {
|
||||
|
||||
fn handle(&self, pool: &DbPool) -> Self::Result;
|
||||
}
|
||||
|
||||
pub struct Guard<'l> {
|
||||
conn: &'l crate::DbPooledConn,
|
||||
tm: &'l diesel::connection::AnsiTransactionManager,
|
||||
}
|
||||
|
||||
impl<'l> Guard<'l> {
|
||||
pub fn new(conn: &'l DbPooledConn) -> Result<Self, crate::DatabaseError> {
|
||||
use diesel::connection::TransactionManager;
|
||||
use diesel::prelude::*;
|
||||
let tm = conn.transaction_manager();
|
||||
tm.begin_transaction(conn).map_err(|e| {
|
||||
::tracing::error!("{:?}", e);
|
||||
crate::DatabaseError::DatabaseConnectionLost
|
||||
})?;
|
||||
Ok(Self { conn, tm })
|
||||
}
|
||||
|
||||
pub fn run<R, F: FnOnce(&Guard) -> Result<R, crate::DatabaseError>>(
|
||||
&self,
|
||||
f: F,
|
||||
) -> Result<R, crate::DatabaseError> {
|
||||
use diesel::connection::TransactionManager;
|
||||
|
||||
let r = f(self);
|
||||
match r {
|
||||
Ok(r) => {
|
||||
self.tm.commit_transaction(self.conn).map_err(|e| {
|
||||
::tracing::error!("{:?}", e);
|
||||
crate::DatabaseError::DatabaseConnectionLost
|
||||
})?;
|
||||
Ok(r)
|
||||
}
|
||||
Err(e) => {
|
||||
::tracing::error!("{:?}", e);
|
||||
self.tm.rollback_transaction(self.conn).map_err(|e| {
|
||||
::tracing::error!("{:?}", e);
|
||||
crate::DatabaseError::DatabaseConnectionLost
|
||||
})?;
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
use diesel::prelude::*;
|
||||
use bitque_data::{BindToken, Message, MessageId, MessageType, User, UserId};
|
||||
use diesel::prelude::*;
|
||||
|
||||
use crate::users::{FindUser, LookupUser};
|
||||
use crate::{db_create, db_delete, db_load};
|
||||
|
@ -1,8 +1,8 @@
|
||||
use chrono::NaiveDateTime;
|
||||
use bitque_data::{
|
||||
EpicId, InvitationState, IssuePriority, IssueStatusId, IssueType, ProjectCategory, ProjectId,
|
||||
TimeTracking, UserId,
|
||||
};
|
||||
use chrono::NaiveDateTime;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::schema::*;
|
||||
|
@ -1,13 +1,13 @@
|
||||
#[macro_export]
|
||||
macro_rules! db_pool {
|
||||
($self: expr) => {
|
||||
&$self.pool.get().map_err(|e| {
|
||||
$self.pool.get().map_err(|e| {
|
||||
::tracing::error!("{:?}", e);
|
||||
$crate::DatabaseError::DatabaseConnectionLost
|
||||
})?
|
||||
};
|
||||
($self: expr, $pool: expr) => {
|
||||
&$pool.get().map_err(|e| {
|
||||
$pool.get().map_err(|e| {
|
||||
::tracing::error!("{:?}", e);
|
||||
$crate::DatabaseError::DatabaseConnectionLost
|
||||
})?
|
||||
@ -34,7 +34,7 @@ macro_rules! db_find {
|
||||
}
|
||||
|
||||
impl $action {
|
||||
pub fn execute(self, $conn: &$crate::DbPooledConn) -> Result<$resource, crate::DatabaseError> {
|
||||
pub fn execute(self, $conn: &mut $crate::DbPooledConn) -> Result<$resource, crate::DatabaseError> {
|
||||
use crate::schema:: $schema ::dsl::*;
|
||||
let $self = self;
|
||||
$crate::q!($q)
|
||||
@ -57,8 +57,8 @@ macro_rules! db_find {
|
||||
type Result = Result<$resource, $crate::DatabaseError>;
|
||||
|
||||
fn handle(&mut self, msg: $action, _ctx: &mut Self::Context) -> Self::Result {
|
||||
let $conn = $crate::db_pool!(self);
|
||||
msg.execute($conn)
|
||||
let mut $conn = $crate::db_pool!(self);
|
||||
msg.execute(&mut $conn)
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -75,7 +75,7 @@ macro_rules! db_load {
|
||||
}
|
||||
|
||||
impl $action {
|
||||
pub fn execute(self, conn: &$crate::DbPooledConn) -> Result<Vec<$resource>, $crate::DatabaseError> {
|
||||
pub fn execute(self, conn: &mut $crate::DbPooledConn) -> Result<Vec<$resource>, $crate::DatabaseError> {
|
||||
use crate::schema:: $schema ::dsl::*;
|
||||
let $self = self;
|
||||
$crate::q!($q)
|
||||
@ -98,9 +98,9 @@ macro_rules! db_load {
|
||||
type Result = Result<Vec<$resource>, $crate::DatabaseError>;
|
||||
|
||||
fn handle(&mut self, msg: $action, _ctx: &mut Self::Context) -> Self::Result {
|
||||
let conn = $crate::db_pool!(self);
|
||||
let mut conn = $crate::db_pool!(self);
|
||||
|
||||
msg.execute(conn)
|
||||
msg.execute(&mut conn)
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -114,7 +114,7 @@ macro_rules! db_load_field {
|
||||
}
|
||||
|
||||
impl $action {
|
||||
pub fn execute(self, conn: &$crate::DbPooledConn) -> Result<Vec<$return_type>, $crate::DatabaseError> {
|
||||
pub fn execute(self, conn: &mut $crate::DbPooledConn) -> Result<Vec<$return_type>, $crate::DatabaseError> {
|
||||
use crate::schema:: $schema ::dsl::*;
|
||||
let $self = self;
|
||||
$crate::q!($q)
|
||||
@ -137,9 +137,9 @@ macro_rules! db_load_field {
|
||||
type Result = Result<Vec<$return_type>, $crate::DatabaseError>;
|
||||
|
||||
fn handle(&mut self, msg: $action, _ctx: &mut Self::Context) -> Self::Result {
|
||||
let conn = $crate::db_pool!(self);
|
||||
let mut conn = $crate::db_pool!(self);
|
||||
|
||||
msg.execute(conn)
|
||||
msg.execute(&mut conn)
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -151,25 +151,34 @@ macro_rules! db_create {
|
||||
};
|
||||
($action: ident, $self: ident => $conn: ident => $schema: ident => $q: expr, $resource: ident, $($field: ident => $ty: ty),+) => {
|
||||
pub struct $action {
|
||||
$(pub $field : $ty),+
|
||||
$(pub $field : $ty),+
|
||||
}
|
||||
|
||||
impl $action {
|
||||
pub fn execute(self, $conn: &$crate::DbPooledConn) -> Result<$resource, crate::DatabaseError> {
|
||||
crate::Guard::new($conn)?.run(|_guard| {
|
||||
use crate::schema:: $schema ::dsl::*;
|
||||
let $self = self;
|
||||
$crate::q!($q)
|
||||
.get_result::<$resource>($conn)
|
||||
.map_err(|e| {
|
||||
pub fn execute(self, conn: &mut $crate::DbPooledConn) -> Result<$resource, crate::DatabaseError> {
|
||||
let mut res = Err(crate::DatabaseError::DatabaseConnectionLost);
|
||||
conn.transaction(|conn| {
|
||||
res = self.exec_with_transaction(conn);
|
||||
if res.is_err() {
|
||||
Err(diesel::NotFound)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}).ok();
|
||||
res
|
||||
}
|
||||
|
||||
fn exec_with_transaction(self, $conn: &mut $crate::DbPooledConn) -> Result<$resource, crate::DatabaseError> {
|
||||
use crate::schema:: $schema ::dsl::*;
|
||||
let $self = self;
|
||||
$crate::q!($q).get_result::<$resource>($conn).map_err(|e| {
|
||||
::tracing::error!("{:?}", e);
|
||||
$crate::DatabaseError::GenericFailure(
|
||||
$crate::OperationError::Create,
|
||||
$crate::ResourceKind::$resource,
|
||||
)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl actix::Message for $action {
|
||||
@ -180,9 +189,9 @@ macro_rules! db_create {
|
||||
type Result = Result<$resource, $crate::DatabaseError>;
|
||||
|
||||
fn handle(&mut self, msg: $action, _ctx: &mut Self::Context) -> Self::Result {
|
||||
let $conn = $crate::db_pool!(self);
|
||||
let mut $conn = $crate::db_pool!(self);
|
||||
|
||||
msg.execute($conn)
|
||||
msg.execute(&mut $conn)
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -199,7 +208,7 @@ macro_rules! db_update {
|
||||
}
|
||||
|
||||
impl $action {
|
||||
pub fn execute(self, $conn: &$crate::DbPooledConn) -> Result<$resource, crate::DatabaseError> {
|
||||
pub fn execute(self, $conn: &mut $crate::DbPooledConn) -> Result<$resource, crate::DatabaseError> {
|
||||
use crate::schema:: $schema ::dsl::*;
|
||||
let $self = self;
|
||||
$crate::q!($q)
|
||||
@ -222,9 +231,9 @@ macro_rules! db_update {
|
||||
type Result = Result<$resource, $crate::DatabaseError>;
|
||||
|
||||
fn handle(&mut self, msg: $action, _ctx: &mut Self::Context) -> Self::Result {
|
||||
let $conn = $crate::db_pool!(self);
|
||||
let mut $conn = $crate::db_pool!(self);
|
||||
|
||||
msg.execute ( $conn )
|
||||
msg.execute ( &mut $conn )
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -241,7 +250,7 @@ macro_rules! db_delete {
|
||||
}
|
||||
|
||||
impl $action {
|
||||
pub fn execute(self, $conn: &$crate::DbPooledConn) -> Result<usize, $crate::DatabaseError> {
|
||||
pub fn execute(self, $conn: &mut $crate::DbPooledConn) -> Result<usize, $crate::DatabaseError> {
|
||||
use $crate::schema:: $schema ::dsl::*;
|
||||
let $self = self;
|
||||
$crate::q!($q)
|
||||
@ -264,9 +273,9 @@ macro_rules! db_delete {
|
||||
type Result = Result<usize, $crate::DatabaseError>;
|
||||
|
||||
fn handle(&mut self, msg: $action, _ctx: &mut Self::Context) -> Self::Result {
|
||||
let $conn = $crate::db_pool!(self);
|
||||
let mut $conn = $crate::db_pool!(self);
|
||||
|
||||
msg.execute($conn)
|
||||
msg.execute(&mut $conn)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -1,5 +1,5 @@
|
||||
use diesel::prelude::*;
|
||||
use bitque_data::{NameString, Project, ProjectCategory, ProjectId, TimeTracking, UserId};
|
||||
use diesel::prelude::*;
|
||||
|
||||
use crate::{db_create, db_find, db_load, db_update};
|
||||
|
||||
@ -11,8 +11,8 @@ db_find! {
|
||||
}
|
||||
|
||||
mod inner {
|
||||
use diesel::prelude::*;
|
||||
use bitque_data::{NameString, Project, ProjectCategory, TimeTracking};
|
||||
use diesel::prelude::*;
|
||||
|
||||
use crate::db_create;
|
||||
|
||||
|
@ -40,13 +40,13 @@ diesel::table! {
|
||||
id -> Int4,
|
||||
name -> Text,
|
||||
email -> Text,
|
||||
state -> InvitationState,
|
||||
state -> InvitationStateMapping,
|
||||
project_id -> Int4,
|
||||
invited_by_id -> Int4,
|
||||
created_at -> Timestamp,
|
||||
updated_at -> Timestamp,
|
||||
bind_token -> Uuid,
|
||||
role -> UserRole,
|
||||
role -> UserRoleMapping,
|
||||
}
|
||||
}
|
||||
|
||||
@ -84,8 +84,8 @@ diesel::table! {
|
||||
issues (id) {
|
||||
id -> Int4,
|
||||
title -> Text,
|
||||
issue_type -> IssueType,
|
||||
priority -> IssuePriority,
|
||||
issue_type -> IssueTypeMapping,
|
||||
priority -> IssuePriorityMapping,
|
||||
list_position -> Int4,
|
||||
description -> Nullable<Text>,
|
||||
description_text -> Nullable<Text>,
|
||||
@ -111,7 +111,7 @@ diesel::table! {
|
||||
sender_id -> Int4,
|
||||
summary -> Text,
|
||||
description -> Text,
|
||||
message_type -> MessageType,
|
||||
message_type -> MessageTypeMapping,
|
||||
hyper_link -> Text,
|
||||
created_at -> Timestamp,
|
||||
updated_at -> Timestamp,
|
||||
@ -127,10 +127,10 @@ diesel::table! {
|
||||
name -> Text,
|
||||
url -> Text,
|
||||
description -> Text,
|
||||
category -> ProjectCategory,
|
||||
category -> ProjectCategoryMapping,
|
||||
created_at -> Timestamp,
|
||||
updated_at -> Timestamp,
|
||||
time_tracking -> TimeTracking,
|
||||
time_tracking -> TimeTrackingMapping,
|
||||
}
|
||||
}
|
||||
|
||||
@ -159,7 +159,7 @@ diesel::table! {
|
||||
project_id -> Int4,
|
||||
is_default -> Bool,
|
||||
is_current -> Bool,
|
||||
role -> UserRole,
|
||||
role -> UserRoleMapping,
|
||||
created_at -> Timestamp,
|
||||
updated_at -> Timestamp,
|
||||
}
|
||||
@ -172,7 +172,7 @@ diesel::table! {
|
||||
user_settings (id) {
|
||||
id -> Int4,
|
||||
user_id -> Int4,
|
||||
text_editor_mode -> TextEditorMode,
|
||||
text_editor_mode -> TextEditorModeMapping,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
use diesel::prelude::*;
|
||||
use bitque_data::{Token, UserId};
|
||||
use diesel::prelude::*;
|
||||
|
||||
use crate::{db_create, db_find, db_update};
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
use diesel::prelude::*;
|
||||
use bitque_data::{ProjectId, UserId, UserProject, UserProjectId, UserRole};
|
||||
use diesel::prelude::*;
|
||||
|
||||
use crate::{db_create, db_delete, db_find, db_load, db_update};
|
||||
|
||||
@ -26,8 +26,8 @@ db_load! {
|
||||
}
|
||||
|
||||
mod inner {
|
||||
use diesel::prelude::*;
|
||||
use bitque_data::{UserId, UserProject, UserProjectId};
|
||||
use diesel::prelude::*;
|
||||
|
||||
use crate::db_update;
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
use diesel::prelude::*;
|
||||
use bitque_data::{TextEditorMode, UserId, UserSetting};
|
||||
use diesel::prelude::*;
|
||||
|
||||
use crate::{db_find, db_update};
|
||||
|
||||
@ -29,8 +29,8 @@ db_update! {
|
||||
}
|
||||
|
||||
mod inner {
|
||||
use diesel::prelude::*;
|
||||
use bitque_data::{TextEditorMode, UserId, UserSetting};
|
||||
use diesel::prelude::*;
|
||||
|
||||
use crate::{db_create, db_update};
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
use diesel::prelude::*;
|
||||
use bitque_data::{EmailString, IssueId, ProjectId, User, UserId, UserRole, UsernameString};
|
||||
use diesel::prelude::*;
|
||||
|
||||
use crate::projects::CreateProject;
|
||||
use crate::user_projects::CreateUserProject;
|
||||
@ -120,7 +120,7 @@ db_load! {
|
||||
user_id => UserId
|
||||
}
|
||||
|
||||
fn count_matching_users(name: &str, email: &str, conn: &DbPooledConn) -> i64 {
|
||||
fn count_matching_users(name: &str, email: &str, conn: &mut DbPooledConn) -> i64 {
|
||||
use crate::schema::users::dsl;
|
||||
|
||||
q!(dsl::users
|
||||
@ -153,7 +153,6 @@ db_update! {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use diesel::connection::TransactionManager;
|
||||
use bitque_data::{Project, ProjectCategory};
|
||||
|
||||
use super::*;
|
||||
@ -166,11 +165,9 @@ mod tests {
|
||||
use crate::schema::users::dsl::users;
|
||||
|
||||
let pool = build_pool();
|
||||
let conn = &pool.get().unwrap();
|
||||
|
||||
let tm = conn.transaction_manager();
|
||||
|
||||
tm.begin_transaction(conn).unwrap();
|
||||
let mut conn = pool.get().unwrap();
|
||||
let conn = &mut conn;
|
||||
conn.begin_test_transaction().unwrap();
|
||||
|
||||
diesel::delete(user_projects).execute(conn).unwrap();
|
||||
diesel::delete(users).execute(conn).unwrap();
|
||||
@ -218,8 +215,6 @@ mod tests {
|
||||
let res2 = count_matching_users("Bar", "foo@example.com", conn);
|
||||
let res3 = count_matching_users("Foo", "foo@example.com", conn);
|
||||
|
||||
tm.rollback_transaction(conn).unwrap();
|
||||
|
||||
assert_eq!(res1, 1);
|
||||
assert_eq!(res2, 1);
|
||||
assert_eq!(res3, 1);
|
||||
|
@ -35,8 +35,11 @@ fn parse_meta(mut it: Peekable<IntoIter>) -> (Peekable<IntoIter>, Option<Attribu
|
||||
///
|
||||
///
|
||||
///
|
||||
/// Example:
|
||||
/// ```
|
||||
/// ## Example:
|
||||
///
|
||||
/// ```no_run
|
||||
/// use derive_db_execute::Execute;
|
||||
///
|
||||
/// pub struct Issue {
|
||||
/// pub id: i32,
|
||||
/// pub name: String,
|
||||
@ -53,7 +56,7 @@ fn parse_meta(mut it: Peekable<IntoIter>) -> (Peekable<IntoIter>, Option<Attribu
|
||||
/// pub struct LoadAll;
|
||||
///
|
||||
/// #[derive(Execute)]
|
||||
/// #[db_exec(schema = "issues", result = "usize", destroy = "diesel::delete(issues.find(msg.id)")]
|
||||
/// #[db_exec(schema = "issues", result = "usize", destroy = "diesel::delete(issues.find(msg.id))")]
|
||||
/// pub struct DeleteOne {
|
||||
/// pub id: i32
|
||||
/// }
|
||||
@ -124,9 +127,9 @@ pub fn derive_enum_iter(item: TokenStream) -> TokenStream {
|
||||
type Result = Result<{action_result}, crate::DatabaseError>;
|
||||
|
||||
fn handle(&mut self, msg: {name}, _ctx: &mut Self::Context) -> Self::Result {{
|
||||
let conn = crate::db_pool!(self);
|
||||
let mut conn = crate::db_pool!(self);
|
||||
|
||||
msg.execute(conn)
|
||||
msg.execute(&mut conn)
|
||||
}}
|
||||
}}
|
||||
|
||||
@ -151,18 +154,18 @@ fn build_create_exec(
|
||||
impl {name} {{
|
||||
pub fn execute(
|
||||
self,
|
||||
conn: &crate::DbPooledConn,
|
||||
conn: &mut crate::DbPooledConn,
|
||||
) -> Result<{action_result}, crate::DatabaseError> {{
|
||||
crate::Guard::new(conn)?.run(|_guard| {{
|
||||
conn.transaction(|conn| {{
|
||||
use crate::schema::{schema}::dsl::*;
|
||||
let msg = self;
|
||||
crate::q!({query}).get_result(conn).map_err(|e| {{
|
||||
::tracing::error!("{{:?}}", e);
|
||||
crate::DatabaseError::GenericFailure(
|
||||
crate::OperationError::Create,
|
||||
crate::ResourceKind::{resource},
|
||||
)
|
||||
}})
|
||||
crate::q!({query}).get_result(conn)
|
||||
}}).map_err(|e| {{
|
||||
::tracing::error!("{{:?}}", e);
|
||||
crate::DatabaseError::GenericFailure(
|
||||
crate::OperationError::Create,
|
||||
crate::ResourceKind::{resource},
|
||||
)
|
||||
}})
|
||||
}}
|
||||
}}
|
||||
@ -187,7 +190,7 @@ fn build_find_exec(
|
||||
impl {name} {{
|
||||
pub fn execute(
|
||||
self,
|
||||
conn: &crate::DbPooledConn,
|
||||
conn: &mut crate::DbPooledConn,
|
||||
) -> Result<{action_result}, crate::DatabaseError> {{
|
||||
use crate::schema::{schema}::dsl::*;
|
||||
let msg = self;
|
||||
@ -221,7 +224,7 @@ fn build_load_exec(
|
||||
impl {name} {{
|
||||
pub fn execute(
|
||||
self,
|
||||
conn: &crate::DbPooledConn,
|
||||
conn: &mut crate::DbPooledConn,
|
||||
) -> Result<{action_result}, crate::DatabaseError> {{
|
||||
use crate::schema::{schema}::dsl::*;
|
||||
let msg = self;
|
||||
@ -255,7 +258,7 @@ fn build_update_exec(
|
||||
impl {name} {{
|
||||
pub fn execute(
|
||||
self,
|
||||
conn: &crate::DbPooledConn,
|
||||
conn: &mut crate::DbPooledConn,
|
||||
) -> Result<{action_result}, crate::DatabaseError> {{
|
||||
use crate::schema::{schema}::dsl::*;
|
||||
let msg = self;
|
||||
@ -289,7 +292,7 @@ fn build_destroy_exec(
|
||||
impl {name} {{
|
||||
pub fn execute(
|
||||
self,
|
||||
conn: &crate::DbPooledConn,
|
||||
conn: &mut crate::DbPooledConn,
|
||||
) -> Result<{action_result}, crate::DatabaseError> {{
|
||||
use crate::schema::{schema}::dsl::*;
|
||||
let msg = self;
|
||||
|
@ -27,7 +27,7 @@ fn consume_ident(mut it: Peekable<IntoIter>, name: &str) -> Peekable<IntoIter> {
|
||||
it
|
||||
}
|
||||
|
||||
pub(in crate) fn codegen(mut it: Peekable<IntoIter>) -> Result<String, String> {
|
||||
pub(crate) fn codegen(mut it: Peekable<IntoIter>) -> Result<String, String> {
|
||||
let name = it
|
||||
.next()
|
||||
.expect("Expect to struct name but nothing was found");
|
||||
|
@ -1,16 +1,26 @@
|
||||
[package]
|
||||
name = "derive_enum_sql"
|
||||
version = "0.1.0"
|
||||
authors = ["Adrian Wozniak <adrian.wozniak@ita-prog.pl>"]
|
||||
edition = "2018"
|
||||
description = "JIRS (Simplified JIRA in Rust) shared data types"
|
||||
repository = "https://gitlab.com/adrian.wozniak/bitque"
|
||||
license = "MPL-2.0"
|
||||
#license-file = "../LICENSE"
|
||||
|
||||
[lib]
|
||||
name = "derive_enum_sql"
|
||||
path = "./src/lib.rs"
|
||||
proc-macro = true
|
||||
name = "diesel-derive-enum"
|
||||
version = "2.0.1"
|
||||
description = "Derive diesel boilerplate for using enums in databases"
|
||||
authors = ["Alex Whitney <adwhit@fastmail.com>"]
|
||||
repository = "http://github.com/adwhit/diesel-derive-enum"
|
||||
homepage = "http://github.com/adwhit/diesel-derive-enum"
|
||||
keywords = ["diesel", "postgres", "sqlite", "mysql", "sql"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
readme = "README.md"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
quote = "1"
|
||||
syn = "1"
|
||||
heck = "0.4.0"
|
||||
proc-macro2 = "1"
|
||||
|
||||
[features]
|
||||
postgres = []
|
||||
sqlite = []
|
||||
mysql = []
|
||||
|
||||
[lib]
|
||||
name = "diesel_derive_enum"
|
||||
proc-macro = true
|
||||
|
@ -1,155 +1,500 @@
|
||||
#![recursion_limit = "1024"]
|
||||
|
||||
extern crate proc_macro;
|
||||
|
||||
use proc_macro::{TokenStream, TokenTree};
|
||||
use heck::{ToKebabCase, ToLowerCamelCase, ToShoutySnakeCase, ToSnakeCase, ToUpperCamelCase};
|
||||
use proc_macro::TokenStream;
|
||||
use proc_macro2::{Ident, Span};
|
||||
use quote::quote;
|
||||
use syn::*;
|
||||
|
||||
fn to_lower_case(s: &str) -> String {
|
||||
let mut lower = String::new();
|
||||
for (idx, c) in s.chars().enumerate() {
|
||||
if idx > 0 && c.is_uppercase() {
|
||||
lower.push('_');
|
||||
}
|
||||
lower.push_str(c.to_lowercase().to_string().as_str());
|
||||
}
|
||||
lower
|
||||
}
|
||||
/// Implement the traits necessary for inserting the enum directly into a
|
||||
/// database
|
||||
///
|
||||
/// # Attributes
|
||||
///
|
||||
/// ## Type attributes
|
||||
///
|
||||
/// * `#[ExistingTypePath = "crate::schema::sql_types::NewEnum"]` specifies the
|
||||
/// path to a corresponding diesel type that was already created by the diesel
|
||||
/// CLI. If omitted, the type will be generated by this macro. *Note*: Only
|
||||
/// applies to `postgres`, will error if specified for other databases
|
||||
/// * `#[DieselType = "NewEnumMapping"]` specifies the name for the diesel type
|
||||
/// to create. If omitted, uses `<enum name>Mapping`. *Note*: Cannot be
|
||||
/// specified alongside `ExistingTypePath`
|
||||
/// * `#[DbValueStyle = "snake_case"]` specifies a renaming style from each of
|
||||
/// the rust enum variants to each of the database variants. Either
|
||||
/// `camelCase`, `kebab-case`, `PascalCase`, `SCREAMING_SNAKE_CASE`,
|
||||
/// `snake_case`, `verbatim`. If omitted, uses `snake_case`.
|
||||
///
|
||||
/// ## Variant attributes
|
||||
///
|
||||
/// * `#[db_rename = "variant"]` specifies the db name for a specific variant.
|
||||
#[proc_macro_derive(
|
||||
DbEnum,
|
||||
attributes(PgType, DieselType, ExistingTypePath, DbValueStyle, db_rename)
|
||||
)]
|
||||
pub fn derive(input: TokenStream) -> TokenStream {
|
||||
let input: DeriveInput = parse_macro_input!(input as DeriveInput);
|
||||
|
||||
fn into_str(name: &str, variants: &[String]) -> String {
|
||||
let mut code = format!(
|
||||
r#"
|
||||
#[cfg(feature = "backend")]
|
||||
impl diesel::serialize::ToSql<{name}Type, diesel::pg::Pg> for {name} {{
|
||||
fn to_sql<W: std::io::Write>(&self, out: &mut diesel::serialize::Output<W, diesel::pg::Pg>) -> diesel::serialize::Result {{
|
||||
match *self {{
|
||||
"#,
|
||||
name = name,
|
||||
);
|
||||
|
||||
for variant in variants {
|
||||
let lower = to_lower_case(&variant);
|
||||
code.push_str(
|
||||
format!(
|
||||
" {name}::{variant} => out.write_all(b\"{lower}\")?,\n",
|
||||
variant = variant,
|
||||
name = name,
|
||||
lower = lower
|
||||
)
|
||||
.as_str(),
|
||||
);
|
||||
}
|
||||
code.push_str(" };\n Ok(diesel::serialize::IsNull::No)\n }\n}");
|
||||
code
|
||||
}
|
||||
|
||||
fn from_str(name: &str, variants: &[String]) -> String {
|
||||
let mut code = format!(
|
||||
r#"
|
||||
#[cfg(feature = "backend")]
|
||||
impl {name} {{
|
||||
fn from_diesel_bytes(bytes: Option<&[u8]>) -> diesel::deserialize::Result<{name}> {{
|
||||
match diesel::not_none!(bytes) {{
|
||||
"#,
|
||||
name = name,
|
||||
);
|
||||
|
||||
for variant in variants {
|
||||
let lower = to_lower_case(&variant);
|
||||
code.push_str(
|
||||
format!(
|
||||
" b\"{lower}\" => Ok({name}::{variant}),\n",
|
||||
variant = variant,
|
||||
name = name,
|
||||
lower = lower
|
||||
)
|
||||
.as_str(),
|
||||
);
|
||||
let existing_mapping_path = val_from_attrs(&input.attrs, "ExistingTypePath");
|
||||
if !cfg!(feature = "postgres") && existing_mapping_path.is_some() {
|
||||
panic!("ExistingTypePath attribute only applies when the 'postgres' feature is enabled");
|
||||
}
|
||||
|
||||
code.push_str(format!(" _ => Ok({name}::default()),", name = name).as_str());
|
||||
code.push_str(" }\n }\n}");
|
||||
code.push_str(
|
||||
format!(
|
||||
r#"
|
||||
#[cfg(feature = "backend")]
|
||||
impl diesel::deserialize::FromSql<{name}Type, diesel::pg::Pg> for {name} {{
|
||||
fn from_sql(bytes: Option<&[u8]>) -> deserialize::Result<Self> {{
|
||||
{name}::from_diesel_bytes(bytes)
|
||||
}}
|
||||
}}
|
||||
// we could allow a default value here but... I'm not very keen
|
||||
// let existing_mapping_path = existing_mapping_path
|
||||
// .unwrap_or_else(|| format!("crate::schema::sql_types::{}", input.ident));
|
||||
|
||||
#[cfg(feature = "backend")]
|
||||
impl diesel::deserialize::FromSql<diesel::sql_types::Text, diesel::pg::Pg> for {name} {{
|
||||
fn from_sql(bytes: Option<&[u8]>) -> deserialize::Result<Self> {{
|
||||
{name}::from_diesel_bytes(bytes)
|
||||
}}
|
||||
}}
|
||||
"#,
|
||||
name = name
|
||||
let pg_internal_type = val_from_attrs(&input.attrs, "PgType");
|
||||
|
||||
if existing_mapping_path.is_some() && pg_internal_type.is_some() {
|
||||
panic!("Cannot specify both `ExistingTypePath` and `PgType` attributes");
|
||||
}
|
||||
|
||||
let pg_internal_type = pg_internal_type.unwrap_or(input.ident.to_string().to_snake_case());
|
||||
|
||||
let new_diesel_mapping = val_from_attrs(&input.attrs, "DieselType");
|
||||
if existing_mapping_path.is_some() && new_diesel_mapping.is_some() {
|
||||
panic!("Cannot specify both `ExistingTypePath` and `DieselType` attributes");
|
||||
}
|
||||
let new_diesel_mapping = new_diesel_mapping.unwrap_or_else(|| format!("{}Type", input.ident));
|
||||
|
||||
// Maintain backwards compatibility by defaulting to snake case.
|
||||
let case_style =
|
||||
val_from_attrs(&input.attrs, "DbValueStyle").unwrap_or_else(|| "snake_case".to_string());
|
||||
let case_style = CaseStyle::from_string(&case_style);
|
||||
|
||||
let existing_mapping_path = existing_mapping_path.map(|v| {
|
||||
v.parse::<proc_macro2::TokenStream>()
|
||||
.expect("ExistingTypePath is not a valid token")
|
||||
});
|
||||
let new_diesel_mapping = Ident::new(new_diesel_mapping.as_ref(), Span::call_site());
|
||||
if let Data::Enum(syn::DataEnum {
|
||||
variants: data_variants,
|
||||
..
|
||||
}) = input.data
|
||||
{
|
||||
generate_derive_enum_impls(
|
||||
&existing_mapping_path,
|
||||
&new_diesel_mapping,
|
||||
&pg_internal_type,
|
||||
case_style,
|
||||
&input.ident,
|
||||
&data_variants,
|
||||
)
|
||||
.as_str(),
|
||||
);
|
||||
code
|
||||
} else {
|
||||
syn::Error::new(
|
||||
Span::call_site(),
|
||||
"derive(DbEnum) can only be applied to enums",
|
||||
)
|
||||
.to_compile_error()
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
#[proc_macro_derive(EnumSql)]
|
||||
pub fn derive_enum_sql(item: TokenStream) -> TokenStream {
|
||||
let mut it = item.into_iter().peekable();
|
||||
while let Some(token) = it.peek() {
|
||||
if let TokenTree::Ident(_) = token {
|
||||
break;
|
||||
} else {
|
||||
it.next();
|
||||
}
|
||||
}
|
||||
if let Some(TokenTree::Ident(ident)) = it.next() {
|
||||
if ident.to_string().as_str() != "pub" {
|
||||
panic!("Expect to find keyword pub but was found {:?}", ident)
|
||||
}
|
||||
} else {
|
||||
panic!("Expect to find keyword pub but nothing was found")
|
||||
}
|
||||
if let Some(TokenTree::Ident(ident)) = it.next() {
|
||||
if ident.to_string().as_str() != "enum" {
|
||||
panic!("Expect to find keyword struct but was found {:?}", ident)
|
||||
}
|
||||
} else {
|
||||
panic!("Expect to find keyword struct but nothing was found")
|
||||
}
|
||||
let name = it
|
||||
.next()
|
||||
.expect("Expect to struct name but nothing was found")
|
||||
.to_string();
|
||||
|
||||
let mut variants = vec![];
|
||||
if let Some(TokenTree::Group(group)) = it.next() {
|
||||
for token in group.stream() {
|
||||
if let TokenTree::Ident(ident) = token {
|
||||
variants.push(ident.to_string())
|
||||
fn val_from_attrs(attrs: &[Attribute], attr_name: &str) -> Option<String> {
|
||||
for attr in attrs {
|
||||
if attr.path.is_ident(attr_name) {
|
||||
match attr.parse_meta().ok()? {
|
||||
Meta::NameValue(MetaNameValue {
|
||||
lit: Lit::Str(lit_str),
|
||||
..
|
||||
}) => return Some(lit_str.value()),
|
||||
_ => panic!(
|
||||
"Attribute '{}' must have form: {} = \"value\"",
|
||||
attr_name, attr_name
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Defines the casing for the database representation. Follows serde naming
|
||||
/// convention.
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
enum CaseStyle {
|
||||
Camel,
|
||||
Kebab,
|
||||
Pascal,
|
||||
Upper,
|
||||
ScreamingSnake,
|
||||
Snake,
|
||||
Verbatim,
|
||||
}
|
||||
|
||||
impl CaseStyle {
|
||||
fn from_string(name: &str) -> Self {
|
||||
match name {
|
||||
"camelCase" => CaseStyle::Camel,
|
||||
"kebab-case" => CaseStyle::Kebab,
|
||||
"PascalCase" => CaseStyle::Pascal,
|
||||
"SCREAMING_SNAKE_CASE" => CaseStyle::ScreamingSnake,
|
||||
"UPPERCASE" => CaseStyle::Upper,
|
||||
"snake_case" => CaseStyle::Snake,
|
||||
"verbatim" | "verbatimcase" => CaseStyle::Verbatim,
|
||||
s => panic!("unsupported casing: `{}`", s),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_derive_enum_impls(
|
||||
existing_mapping_path: &Option<proc_macro2::TokenStream>,
|
||||
new_diesel_mapping: &Ident,
|
||||
pg_internal_type: &str,
|
||||
case_style: CaseStyle,
|
||||
enum_ty: &Ident,
|
||||
variants: &syn::punctuated::Punctuated<Variant, syn::token::Comma>,
|
||||
) -> TokenStream {
|
||||
let modname = Ident::new(&format!("db_enum_impl_{}", enum_ty), Span::call_site());
|
||||
let variant_ids: Vec<proc_macro2::TokenStream> = variants
|
||||
.iter()
|
||||
.map(|variant| {
|
||||
if let Fields::Unit = variant.fields {
|
||||
let id = &variant.ident;
|
||||
quote! {
|
||||
#enum_ty::#id
|
||||
}
|
||||
} else {
|
||||
panic!("Variants must be fieldless")
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
let variants_db: Vec<String> = variants
|
||||
.iter()
|
||||
.map(|variant| {
|
||||
val_from_attrs(&variant.attrs, "db_rename")
|
||||
.unwrap_or_else(|| stylize_value(&variant.ident.to_string(), case_style))
|
||||
})
|
||||
.collect();
|
||||
let variants_db_bytes: Vec<LitByteStr> = variants_db
|
||||
.iter()
|
||||
.map(|variant_str| LitByteStr::new(variant_str.as_bytes(), Span::call_site()))
|
||||
.collect();
|
||||
|
||||
let common = generate_common(enum_ty, &variant_ids, &variants_db, &variants_db_bytes);
|
||||
let (diesel_mapping_def, diesel_mapping_use) =
|
||||
// Skip this part if we already have an existing mapping
|
||||
if existing_mapping_path.is_some() {
|
||||
(None, None)
|
||||
} else {
|
||||
let new_diesel_mapping_def = generate_new_diesel_mapping(new_diesel_mapping, pg_internal_type);
|
||||
let common_impls_on_new_diesel_mapping =
|
||||
generate_common_impls("e! { #new_diesel_mapping }, enum_ty);
|
||||
(
|
||||
Some(quote! {
|
||||
#new_diesel_mapping_def
|
||||
#common_impls_on_new_diesel_mapping
|
||||
}),
|
||||
Some(quote! {
|
||||
pub use self::#modname::#new_diesel_mapping;
|
||||
}),
|
||||
)
|
||||
};
|
||||
|
||||
let pg_impl = if cfg!(feature = "postgres") {
|
||||
match existing_mapping_path {
|
||||
Some(path) => {
|
||||
let common_impls_on_existing_diesel_mapping = generate_common_impls(path, enum_ty);
|
||||
let postgres_impl = generate_postgres_impl(path, enum_ty, true);
|
||||
Some(quote! {
|
||||
#common_impls_on_existing_diesel_mapping
|
||||
#postgres_impl
|
||||
})
|
||||
}
|
||||
None => Some(generate_postgres_impl(
|
||||
"e! { #new_diesel_mapping },
|
||||
enum_ty,
|
||||
false,
|
||||
)),
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let mysql_impl = if cfg!(feature = "mysql") {
|
||||
Some(generate_mysql_impl(new_diesel_mapping, enum_ty))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let sqlite_impl = if cfg!(feature = "sqlite") {
|
||||
Some(generate_sqlite_impl(new_diesel_mapping, enum_ty))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let imports = quote! {
|
||||
use super::*;
|
||||
use diesel::{
|
||||
backend::{self, Backend},
|
||||
deserialize::{self, FromSql},
|
||||
expression::AsExpression,
|
||||
internal::derives::as_expression::Bound,
|
||||
query_builder::{bind_collector::RawBytesBindCollector, QueryId},
|
||||
row::Row,
|
||||
serialize::{self, IsNull, Output, ToSql},
|
||||
sql_types::*,
|
||||
Queryable,
|
||||
};
|
||||
use std::io::Write;
|
||||
};
|
||||
|
||||
let quoted = quote! {
|
||||
#diesel_mapping_use
|
||||
#[allow(non_snake_case)]
|
||||
mod #modname {
|
||||
#imports
|
||||
|
||||
#common
|
||||
#diesel_mapping_def
|
||||
#pg_impl
|
||||
#mysql_impl
|
||||
#sqlite_impl
|
||||
}
|
||||
};
|
||||
|
||||
quoted.into()
|
||||
}
|
||||
|
||||
fn stylize_value(value: &str, style: CaseStyle) -> String {
|
||||
match style {
|
||||
CaseStyle::Camel => value.to_lower_camel_case(),
|
||||
CaseStyle::Kebab => value.to_kebab_case(),
|
||||
CaseStyle::Pascal => value.to_upper_camel_case(),
|
||||
CaseStyle::Upper => value.to_uppercase(),
|
||||
CaseStyle::ScreamingSnake => value.to_shouty_snake_case(),
|
||||
CaseStyle::Snake => value.to_snake_case(),
|
||||
CaseStyle::Verbatim => value.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_common(
|
||||
enum_ty: &Ident,
|
||||
variants_rs: &[proc_macro2::TokenStream],
|
||||
variants_db: &[String],
|
||||
variants_db_bytes: &[LitByteStr],
|
||||
) -> proc_macro2::TokenStream {
|
||||
quote! {
|
||||
fn db_str_representation(e: &#enum_ty) -> &'static str {
|
||||
match *e {
|
||||
#(#variants_rs => #variants_db,)*
|
||||
}
|
||||
}
|
||||
|
||||
fn from_db_binary_representation(bytes: &[u8]) -> deserialize::Result<#enum_ty> {
|
||||
match bytes {
|
||||
#(#variants_db_bytes => Ok(#variants_rs),)*
|
||||
v => Err(format!("Unrecognized enum variant: '{}'",
|
||||
String::from_utf8_lossy(v)).into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_new_diesel_mapping(
|
||||
new_diesel_mapping: &Ident,
|
||||
pg_internal_type: &str,
|
||||
) -> proc_macro2::TokenStream {
|
||||
// Note - we only generate a new mapping for mysql and sqlite, postgres
|
||||
// should already have one
|
||||
quote! {
|
||||
#[derive(SqlType, Clone)]
|
||||
#[diesel(mysql_type(name = "Enum"))]
|
||||
#[diesel(sqlite_type(name = "Text"))]
|
||||
#[diesel(postgres_type(name = #pg_internal_type))]
|
||||
pub struct #new_diesel_mapping;
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_common_impls(
|
||||
diesel_mapping: &proc_macro2::TokenStream,
|
||||
enum_ty: &Ident,
|
||||
) -> proc_macro2::TokenStream {
|
||||
quote! {
|
||||
|
||||
// NOTE: at some point this impl will no longer be necessary
|
||||
// for diesel-cli schemas
|
||||
// See https://github.com/adwhit/diesel-derive-enum/issues/10
|
||||
// and https://github.com/adwhit/diesel-derive-enum/pull/79
|
||||
impl QueryId for #diesel_mapping {
|
||||
type QueryId = #diesel_mapping;
|
||||
const HAS_STATIC_QUERY_ID: bool = true;
|
||||
}
|
||||
|
||||
impl AsExpression<#diesel_mapping> for #enum_ty {
|
||||
type Expression = Bound<#diesel_mapping, Self>;
|
||||
|
||||
fn as_expression(self) -> Self::Expression {
|
||||
Bound::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsExpression<Nullable<#diesel_mapping>> for #enum_ty {
|
||||
type Expression = Bound<Nullable<#diesel_mapping>, Self>;
|
||||
|
||||
fn as_expression(self) -> Self::Expression {
|
||||
Bound::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> AsExpression<#diesel_mapping> for &'a #enum_ty {
|
||||
type Expression = Bound<#diesel_mapping, Self>;
|
||||
|
||||
fn as_expression(self) -> Self::Expression {
|
||||
Bound::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> AsExpression<Nullable<#diesel_mapping>> for &'a #enum_ty {
|
||||
type Expression = Bound<Nullable<#diesel_mapping>, Self>;
|
||||
|
||||
fn as_expression(self) -> Self::Expression {
|
||||
Bound::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> AsExpression<#diesel_mapping> for &'a &'b #enum_ty {
|
||||
type Expression = Bound<#diesel_mapping, Self>;
|
||||
|
||||
fn as_expression(self) -> Self::Expression {
|
||||
Bound::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> AsExpression<Nullable<#diesel_mapping>> for &'a &'b #enum_ty {
|
||||
type Expression = Bound<Nullable<#diesel_mapping>, Self>;
|
||||
|
||||
fn as_expression(self) -> Self::Expression {
|
||||
Bound::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<DB> ToSql<Nullable<#diesel_mapping>, DB> for #enum_ty
|
||||
where
|
||||
DB: Backend,
|
||||
Self: ToSql<#diesel_mapping, DB>,
|
||||
{
|
||||
fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, DB>) -> serialize::Result {
|
||||
ToSql::<#diesel_mapping, DB>::to_sql(self, out)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_postgres_impl(
|
||||
diesel_mapping: &proc_macro2::TokenStream,
|
||||
enum_ty: &Ident,
|
||||
with_clone: bool,
|
||||
) -> proc_macro2::TokenStream {
|
||||
// If the type was generated by postgres, we have to manually add a clone impl,
|
||||
// if generated by 'us' it has already been done
|
||||
let clone_impl = if with_clone {
|
||||
Some(quote! {
|
||||
impl Clone for #diesel_mapping {
|
||||
fn clone(&self) -> Self {
|
||||
#diesel_mapping
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
quote! {
|
||||
mod pg_impl {
|
||||
use super::*;
|
||||
use diesel::pg::{Pg, PgValue};
|
||||
|
||||
#clone_impl
|
||||
|
||||
impl FromSql<#diesel_mapping, Pg> for #enum_ty {
|
||||
fn from_sql(raw: PgValue) -> deserialize::Result<Self> {
|
||||
from_db_binary_representation(raw.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl ToSql<#diesel_mapping, Pg> for #enum_ty
|
||||
{
|
||||
fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Pg>) -> serialize::Result {
|
||||
out.write_all(db_str_representation(self).as_bytes())?;
|
||||
Ok(IsNull::No)
|
||||
}
|
||||
}
|
||||
|
||||
impl Queryable<#diesel_mapping, Pg> for #enum_ty {
|
||||
type Row = Self;
|
||||
|
||||
fn build(row: Self::Row) -> deserialize::Result<Self> {
|
||||
Ok(row)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_mysql_impl(diesel_mapping: &Ident, enum_ty: &Ident) -> proc_macro2::TokenStream {
|
||||
quote! {
|
||||
mod mysql_impl {
|
||||
use super::*;
|
||||
use diesel;
|
||||
use diesel::mysql::{Mysql, MysqlValue};
|
||||
|
||||
impl FromSql<#diesel_mapping, Mysql> for #enum_ty {
|
||||
fn from_sql(raw: MysqlValue) -> deserialize::Result<Self> {
|
||||
from_db_binary_representation(raw.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl ToSql<#diesel_mapping, Mysql> for #enum_ty
|
||||
{
|
||||
fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Mysql>) -> serialize::Result {
|
||||
out.write_all(db_str_representation(self).as_bytes())?;
|
||||
Ok(IsNull::No)
|
||||
}
|
||||
}
|
||||
|
||||
impl Queryable<#diesel_mapping, Mysql> for #enum_ty {
|
||||
type Row = Self;
|
||||
|
||||
fn build(row: Self::Row) -> deserialize::Result<Self> {
|
||||
Ok(row)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_sqlite_impl(diesel_mapping: &Ident, enum_ty: &Ident) -> proc_macro2::TokenStream {
|
||||
quote! {
|
||||
mod sqlite_impl {
|
||||
use super::*;
|
||||
use diesel;
|
||||
use diesel::sql_types;
|
||||
use diesel::sqlite::Sqlite;
|
||||
|
||||
impl FromSql<#diesel_mapping, Sqlite> for #enum_ty {
|
||||
fn from_sql(value: backend::RawValue<Sqlite>) -> deserialize::Result<Self> {
|
||||
let bytes = <Vec<u8> as FromSql<sql_types::Binary, Sqlite>>::from_sql(value)?;
|
||||
from_db_binary_representation(bytes.as_slice())
|
||||
}
|
||||
}
|
||||
|
||||
impl ToSql<#diesel_mapping, Sqlite> for #enum_ty {
|
||||
fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Sqlite>) -> serialize::Result {
|
||||
<str as ToSql<sql_types::Text, Sqlite>>::to_sql(db_str_representation(self), out)
|
||||
}
|
||||
}
|
||||
|
||||
impl Queryable<#diesel_mapping, Sqlite> for #enum_ty {
|
||||
type Row = Self;
|
||||
|
||||
fn build(row: Self::Row) -> deserialize::Result<Self> {
|
||||
Ok(row)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
panic!("Enum variants group expected");
|
||||
}
|
||||
if variants.is_empty() {
|
||||
panic!("Enum cannot be empty")
|
||||
}
|
||||
|
||||
let mut code = format!(
|
||||
r#"
|
||||
#[cfg(feature = "backend")]
|
||||
#[derive(diesel::SqlType)]
|
||||
#[postgres(type_name = "{name}Type")]
|
||||
pub struct {name}Type;
|
||||
|
||||
#[cfg(feature = "backend")]
|
||||
impl diesel::query_builder::QueryId for {name}Type {{
|
||||
type QueryId = {name};
|
||||
}}
|
||||
"#,
|
||||
name = name
|
||||
);
|
||||
|
||||
code.push_str(from_str(&name, &variants).as_str());
|
||||
code.push_str(into_str(&name, &variants).as_str());
|
||||
|
||||
code.parse().unwrap()
|
||||
}
|
||||
|
@ -17,6 +17,5 @@ actix = { version = "0.13.0" }
|
||||
actix-files = { version = "0.6.2" }
|
||||
bitque-config = { workspace = true, features = ["local-storage"] }
|
||||
bytes = { version = "1.4.0" }
|
||||
common = { workspace = true }
|
||||
futures = { version = "0.3.8" }
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
|
@ -17,7 +17,6 @@ actix = { version = "0.13.0" }
|
||||
bincode = { version = "*" }
|
||||
bitque-config = { workspace = true, features = ["hi"] }
|
||||
bitque-data = { workspace = true, features = ["backend"] }
|
||||
common = { workspace = true }
|
||||
flate2 = { version = "*" }
|
||||
lazy_static = { version = "*" }
|
||||
serde = { version = "*" }
|
||||
|
@ -82,9 +82,11 @@ impl HighlightActor {
|
||||
|
||||
let mut res = Vec::with_capacity(code.split_ascii_whitespace().count());
|
||||
for line in code.lines() {
|
||||
res.extend(hi.highlight_line(line, self.syntax_set.as_ref()).map_err(|_e| {
|
||||
HighlightError::UnknownLanguage
|
||||
})?.iter());
|
||||
res.extend(
|
||||
hi.highlight_line(line, self.syntax_set.as_ref())
|
||||
.map_err(|_e| HighlightError::UnknownLanguage)?
|
||||
.iter(),
|
||||
);
|
||||
}
|
||||
Ok(res)
|
||||
}
|
||||
|
@ -15,7 +15,6 @@ path = "./src/lib.rs"
|
||||
[dependencies]
|
||||
actix = { version = "0.13.0" }
|
||||
bitque-config = { workspace = true, features = ["mail", "web"] }
|
||||
common = { workspace = true }
|
||||
dotenv = { version = "*" }
|
||||
futures = { version = "*" }
|
||||
lettre = { version = "0.10.0-rc.3" }
|
||||
|
@ -20,11 +20,13 @@ default = ["local-storage"]
|
||||
[dependencies]
|
||||
actix = { version = "0.13.0" }
|
||||
actix-multipart = { version = "*" }
|
||||
actix-web = { version = "4" }
|
||||
actix-web-actors = { version = "4" }
|
||||
amazon-actor = { workspace = true, optional = true }
|
||||
bincode = { version = "*" }
|
||||
bitque-config = { workspace = true, features = ["mail", "web", "local-storage"] }
|
||||
bitque-data = { workspace = true, features = ["backend"] }
|
||||
common = { workspace = true }
|
||||
bytes = { version = "1" }
|
||||
database-actor = { workspace = true }
|
||||
filesystem-actor = { workspace = true, optional = true }
|
||||
futures = { version = "0.3.8" }
|
||||
@ -34,5 +36,6 @@ openssl-sys = { version = "*", features = ["vendored"] }
|
||||
serde = { version = "*" }
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
toml = { version = "*" }
|
||||
tracing = { version = "0.1.37" }
|
||||
uuid = { version = "1.3.0", features = ["serde", "v4", "v5"] }
|
||||
websocket-actor = { workspace = true }
|
||||
|
@ -2,10 +2,10 @@ use std::io::Write;
|
||||
|
||||
use actix::Addr;
|
||||
use actix_multipart::{Field, Multipart};
|
||||
use actix_web::http::header::ContentDisposition;
|
||||
use actix_web::web::Data;
|
||||
use actix_web::{post, web, Error, HttpResponse};
|
||||
use common::*;
|
||||
use bitque_data::msg::{WsMsg, WsMsgUser};
|
||||
use bitque_data::{User, UserId};
|
||||
use database_actor::authorize_user::AuthorizeUser;
|
||||
use database_actor::user_projects::CurrentUserProject;
|
||||
use database_actor::users::UpdateAvatarUrl;
|
||||
@ -13,11 +13,12 @@ use database_actor::DbExecutor;
|
||||
#[cfg(feature = "local-storage")]
|
||||
use futures::executor::block_on;
|
||||
use futures::{StreamExt, TryStreamExt};
|
||||
use bitque_data::msg::{WsMsg, WsMsgUser};
|
||||
use bitque_data::{User, UserId};
|
||||
use tracing::error;
|
||||
use websocket_actor::server::InnerMsg::BroadcastToChannel;
|
||||
use websocket_actor::server::WsServer;
|
||||
|
||||
use crate::ServiceError;
|
||||
|
||||
#[cfg(feature = "aws-s3")]
|
||||
#[post("/")]
|
||||
pub async fn upload(
|
||||
@ -31,10 +32,7 @@ pub async fn upload(
|
||||
let mut avatar_url: Option<String> = None;
|
||||
|
||||
while let Ok(Some(field)) = payload.try_next().await {
|
||||
let disposition: ContentDisposition = match field.content_disposition() {
|
||||
Some(d) => d,
|
||||
_ => continue,
|
||||
};
|
||||
let disposition = field.content_disposition();
|
||||
if !disposition.is_form_data() {
|
||||
return Ok(HttpResponse::BadRequest().finish());
|
||||
}
|
||||
@ -48,7 +46,7 @@ pub async fn upload(
|
||||
crate::handlers::upload_avatar_image::handle_image(
|
||||
id,
|
||||
field,
|
||||
disposition,
|
||||
disposition.clone(),
|
||||
fs.clone(),
|
||||
amazon.clone(),
|
||||
)
|
||||
@ -95,10 +93,7 @@ pub async fn upload(
|
||||
let mut avatar_url: Option<String> = None;
|
||||
|
||||
while let Ok(Some(field)) = payload.try_next().await {
|
||||
let disposition: ContentDisposition = match field.content_disposition() {
|
||||
Some(d) => d,
|
||||
_ => continue,
|
||||
};
|
||||
let disposition = field.content_disposition();
|
||||
if !disposition.is_form_data() {
|
||||
return Ok(HttpResponse::BadRequest().finish());
|
||||
}
|
||||
@ -107,15 +102,10 @@ pub async fn upload(
|
||||
user_id = Some(handle_token(field, db.clone()).await?);
|
||||
}
|
||||
Some("avatar") => {
|
||||
let id = user_id.ok_or_else(|| HttpResponse::Unauthorized().finish())?;
|
||||
let Some(id) = user_id else { return Ok(HttpResponse::Unauthorized().finish()); };
|
||||
avatar_url = Some(
|
||||
crate::handlers::upload_avatar_image::handle_image(
|
||||
id,
|
||||
field,
|
||||
disposition,
|
||||
fs.clone(),
|
||||
)
|
||||
.await?,
|
||||
crate::handlers::upload_avatar_image::handle_image(id, field, fs.clone())
|
||||
.await?,
|
||||
);
|
||||
}
|
||||
_ => continue,
|
||||
@ -134,12 +124,16 @@ pub async fn upload(
|
||||
match (user_id, avatar_url) {
|
||||
(user_id, Some(avatar_url)) => {
|
||||
let user = update_user_avatar(user_id, avatar_url.clone(), db).await?;
|
||||
ws.send(BroadcastToChannel(
|
||||
project_id,
|
||||
WsMsg::User(WsMsgUser::AvatarUrlChanged(user.id, avatar_url)),
|
||||
))
|
||||
.await
|
||||
.map_err(|_| HttpResponse::UnprocessableEntity().finish())?;
|
||||
if ws
|
||||
.send(BroadcastToChannel(
|
||||
project_id,
|
||||
WsMsg::User(WsMsgUser::AvatarUrlChanged(user.id, avatar_url)),
|
||||
))
|
||||
.await
|
||||
.is_err()
|
||||
{
|
||||
return Ok(HttpResponse::UnprocessableEntity().finish());
|
||||
};
|
||||
Ok(HttpResponse::NoContent().finish())
|
||||
}
|
||||
_ => Ok(HttpResponse::UnprocessableEntity().finish()),
|
||||
@ -162,42 +156,41 @@ async fn update_user_avatar(
|
||||
|
||||
Ok(Err(e)) => {
|
||||
::tracing::error!("{:?}", e);
|
||||
Err(actix_web::Error::from(
|
||||
HttpResponse::Unauthorized().finish(),
|
||||
))
|
||||
Err(ServiceError::Unauthorized.into())
|
||||
}
|
||||
Err(e) => {
|
||||
::tracing::error!("{:?}", e);
|
||||
Err(actix_web::Error::from(
|
||||
HttpResponse::Unauthorized().finish(),
|
||||
))
|
||||
Err(ServiceError::Unauthorized.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_token(
|
||||
mut field: Field,
|
||||
db: Data<Addr<DbExecutor>>,
|
||||
) -> Result<UserId, actix_web::Error> {
|
||||
async fn handle_token(mut field: Field, db: Data<Addr<DbExecutor>>) -> Result<UserId, Error> {
|
||||
let mut f: Vec<u8> = vec![];
|
||||
while let Some(chunk) = field.next().await {
|
||||
let data = chunk.unwrap();
|
||||
f = web::block(move || f.write_all(&data).map(|_| f)).await?;
|
||||
f = web::block(move || {
|
||||
if let Err(e) = f.write_all(&data) {
|
||||
error!("{e}");
|
||||
}
|
||||
f
|
||||
})
|
||||
.await?;
|
||||
}
|
||||
let access_token = String::from_utf8(f)
|
||||
.unwrap_or_default()
|
||||
.parse::<uuid::Uuid>()
|
||||
.map_err(|_| HttpResponse::Unauthorized().finish())?;
|
||||
.map_err(|_| ServiceError::Unauthorized)?;
|
||||
match db.send(AuthorizeUser { access_token }).await {
|
||||
Ok(Ok(user)) => Ok(user.id),
|
||||
|
||||
Ok(Err(e)) => {
|
||||
::tracing::error!("{:?}", e);
|
||||
Err(HttpResponse::Unauthorized().finish().into())
|
||||
Err(ServiceError::Unauthorized.into())
|
||||
}
|
||||
Err(e) => {
|
||||
::tracing::error!("{:?}", e);
|
||||
Err(HttpResponse::Unauthorized().finish().into())
|
||||
Err(ServiceError::Unauthorized.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,19 +1,21 @@
|
||||
use actix_web::HttpResponse;
|
||||
use common::*;
|
||||
use std::fmt::{Display, Formatter};
|
||||
|
||||
use actix_web::body::BoxBody;
|
||||
use actix_web::{HttpResponse, ResponseError};
|
||||
use bitque_data::msg::WsError;
|
||||
use bitque_data::ErrorResponse;
|
||||
|
||||
const TOKEN_NOT_FOUND: &str = "Token not found";
|
||||
const DATABASE_CONNECTION_FAILED: &str = "Database connection failed";
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum HighlightError {
|
||||
UnknownLanguage,
|
||||
UnknownTheme,
|
||||
ResultUnserializable,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ServiceError {
|
||||
Unauthorized,
|
||||
DatabaseConnectionLost,
|
||||
@ -30,6 +32,18 @@ impl ServiceError {
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for ServiceError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str("")
|
||||
}
|
||||
}
|
||||
|
||||
impl ResponseError for ServiceError {
|
||||
fn error_response(&self) -> HttpResponse<BoxBody> {
|
||||
self.clone().into()
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<HttpResponse> for ServiceError {
|
||||
fn into(self) -> HttpResponse {
|
||||
match self {
|
||||
|
@ -1,22 +1,20 @@
|
||||
use actix::Addr;
|
||||
use actix_multipart::Field;
|
||||
use actix_web::http::header::ContentDisposition;
|
||||
use actix_web::web::Data;
|
||||
use actix_web::Error;
|
||||
use common::*;
|
||||
use futures::StreamExt;
|
||||
use bitque_data::UserId;
|
||||
use futures::StreamExt;
|
||||
use tokio::sync::broadcast::{Receiver, Sender};
|
||||
use tracing::error;
|
||||
|
||||
#[cfg(all(feature = "local-storage", feature = "aws-s3"))]
|
||||
pub(crate) async fn handle_image(
|
||||
user_id: UserId,
|
||||
mut field: Field,
|
||||
disposition: ContentDisposition,
|
||||
fs: Data<Addr<filesystem_actor::FileSystemExecutor>>,
|
||||
amazon: Data<Addr<amazon_actor::AmazonExecutor>>,
|
||||
) -> Result<String, Error> {
|
||||
let filename = disposition.get_filename().unwrap();
|
||||
let filename = field.content_disposition().get_filename().unwrap();
|
||||
let system_file_name = format!("{}-{}", user_id, filename);
|
||||
|
||||
let (sender, receiver) = tokio::sync::broadcast::channel(64);
|
||||
@ -46,10 +44,9 @@ pub(crate) async fn handle_image(
|
||||
pub(crate) async fn handle_image(
|
||||
user_id: UserId,
|
||||
mut field: Field,
|
||||
disposition: ContentDisposition,
|
||||
amazon: Data<Addr<amazon_actor::AmazonExecutor>>,
|
||||
) -> Result<String, Error> {
|
||||
let filename = disposition.get_filename().unwrap();
|
||||
let filename = field.content_disposition().get_filename().unwrap();
|
||||
let system_file_name = format!("{}-{}", user_id, filename);
|
||||
|
||||
let (sender, receiver) = tokio::sync::broadcast::channel(64);
|
||||
@ -73,10 +70,9 @@ pub(crate) async fn handle_image(
|
||||
pub(crate) async fn handle_image(
|
||||
user_id: UserId,
|
||||
mut field: Field,
|
||||
disposition: ContentDisposition,
|
||||
fs: Data<Addr<filesystem_actor::FileSystemExecutor>>,
|
||||
) -> Result<String, Error> {
|
||||
let filename = disposition.get_filename().unwrap();
|
||||
let filename = field.content_disposition().get_filename().unwrap();
|
||||
let system_file_name = format!("{}-{}", user_id, filename);
|
||||
|
||||
let (sender, _receiver) = tokio::sync::broadcast::channel(64);
|
||||
@ -97,11 +93,11 @@ pub(crate) async fn handle_image(
|
||||
}
|
||||
|
||||
/// Read file from client
|
||||
async fn read_form_data(field: &mut Field, sender: Sender<common::bytes::Bytes>) {
|
||||
async fn read_form_data(field: &mut Field, sender: Sender<bytes::Bytes>) {
|
||||
while let Some(chunk) = field.next().await {
|
||||
let data = chunk.unwrap();
|
||||
if let Err(err) = sender.send(data) {
|
||||
log::error!("{:?}", err);
|
||||
error!("{:?}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,12 @@
|
||||
extern crate core;
|
||||
|
||||
use actix::Addr;
|
||||
use actix_web::web::Data;
|
||||
use actix_web::{HttpRequest, HttpResponse};
|
||||
use common::*;
|
||||
use bitque_data::User;
|
||||
use database_actor::authorize_user::AuthorizeUser;
|
||||
use database_actor::DbExecutor;
|
||||
pub use errors::*;
|
||||
use bitque_data::User;
|
||||
|
||||
use crate::middleware::authorize::token_from_headers;
|
||||
|
||||
|
@ -1,10 +1,6 @@
|
||||
use actix_web::http::header::{self};
|
||||
use actix_web::http::HeaderMap;
|
||||
use common::*;
|
||||
use actix_web::http::header::{self, HeaderMap};
|
||||
|
||||
pub fn token_from_headers(
|
||||
headers: &HeaderMap,
|
||||
) -> std::result::Result<uuid::Uuid, crate::errors::ServiceError> {
|
||||
pub fn token_from_headers(headers: &HeaderMap) -> Result<uuid::Uuid, crate::errors::ServiceError> {
|
||||
headers
|
||||
.get(header::AUTHORIZATION)
|
||||
.ok_or(crate::errors::ServiceError::Unauthorized)
|
||||
|
@ -1 +0,0 @@
|
||||
../.env
|
@ -27,8 +27,8 @@ derive_enum_primitive = { workspace = true }
|
||||
dotenv = { version = "*" }
|
||||
futures = "0.3.6"
|
||||
js-sys = { version = "*", default-features = false }
|
||||
seed = { version = "0.10.0" }
|
||||
serde = { version = "*" }
|
||||
seed = { version = "0" }
|
||||
serde = { version = "1", features = [] }
|
||||
serde_json = { version = "*" }
|
||||
tracing = { version = "0.1.37" }
|
||||
uuid = { version = "1.3.0", features = ["serde"] }
|
||||
|
@ -1 +0,0 @@
|
||||
../LICENSE
|
@ -1,5 +1,4 @@
|
||||
use bitque_data::{EpicId, IssueStatusId, WsMsg};
|
||||
use seed::prelude::WebSocketMessage;
|
||||
|
||||
use crate::components::styled_md_editor::MdEditorMode as TabMode;
|
||||
use crate::FieldId;
|
||||
|
@ -1,3 +1,4 @@
|
||||
mod events;
|
||||
pub mod styled_avatar;
|
||||
pub mod styled_button;
|
||||
pub mod styled_checkbox;
|
||||
@ -18,4 +19,3 @@ pub mod styled_select_child;
|
||||
pub mod styled_textarea;
|
||||
pub mod styled_tip;
|
||||
pub mod styled_tooltip;
|
||||
mod events;
|
||||
|
@ -1,5 +1,5 @@
|
||||
use seed::*;
|
||||
use seed::prelude::*;
|
||||
use seed::*;
|
||||
use web_sys::File;
|
||||
|
||||
use crate::{FieldId, Msg};
|
||||
|
@ -1,5 +1,5 @@
|
||||
use seed::*;
|
||||
use seed::prelude::*;
|
||||
use seed::*;
|
||||
|
||||
use crate::Msg;
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
use seed::*;
|
||||
use seed::prelude::*;
|
||||
use seed::*;
|
||||
|
||||
use crate::components::styled_icon::{Icon, StyledIcon};
|
||||
use crate::Msg;
|
||||
|
@ -1,11 +1,11 @@
|
||||
#![feature(type_ascription, trait_alias, drain_filter)]
|
||||
|
||||
use bitque_data::msg::WsMsgSession;
|
||||
use bitque_data::*;
|
||||
pub use changes::*;
|
||||
pub use components::*;
|
||||
pub use fields::*;
|
||||
pub use images::*;
|
||||
use bitque_data::msg::WsMsgSession;
|
||||
use bitque_data::*;
|
||||
use seed::prelude::*;
|
||||
use web_sys::File;
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
use bitque_data::{IssueFieldId, IssuePriority};
|
||||
use derive_enum_iter::EnumIter;
|
||||
use derive_enum_primitive::EnumPrimitive;
|
||||
use bitque_data::{IssueFieldId, IssuePriority};
|
||||
use seed::prelude::*;
|
||||
|
||||
use crate::components::styled_date_time_input::*;
|
||||
|
@ -1,8 +1,8 @@
|
||||
use comments::*;
|
||||
use bitque_data::{
|
||||
CommentFieldId, IssueFieldId, IssuePriority, IssueStatus, IssueType, TimeTracking,
|
||||
UpdateIssuePayload, User,
|
||||
};
|
||||
use comments::*;
|
||||
use seed::prelude::*;
|
||||
use seed::*;
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
use chrono::NaiveDateTime;
|
||||
use bitque_data::{Issue, IssueStatus};
|
||||
use chrono::NaiveDateTime;
|
||||
use seed::prelude::*;
|
||||
use seed::*;
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
use seed::*;
|
||||
use seed::prelude::*;
|
||||
|
||||
use bitque_data::{Issue, IssueId};
|
||||
use seed::prelude::*;
|
||||
use seed::*;
|
||||
|
||||
use crate::components::styled_icon::*;
|
||||
use crate::components::styled_link::*;
|
||||
|
@ -1,7 +1,7 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use chrono::NaiveDateTime;
|
||||
use bitque_data::*;
|
||||
use chrono::NaiveDateTime;
|
||||
|
||||
use crate::shared::drag::DragState;
|
||||
|
||||
|
@ -1,14 +1,13 @@
|
||||
use seed::*;
|
||||
use seed::prelude::*;
|
||||
|
||||
use bitque_data::*;
|
||||
use seed::prelude::*;
|
||||
use seed::*;
|
||||
|
||||
use crate::{match_page, Model, Msg};
|
||||
use crate::components::styled_avatar::*;
|
||||
use crate::components::styled_button::{ButtonVariant, StyledButton};
|
||||
use crate::components::styled_icon::*;
|
||||
use crate::model::PageContent;
|
||||
use crate::pages::project_page::{events, StatusIssueIds};
|
||||
use crate::{match_page, Model, Msg};
|
||||
|
||||
#[inline(always)]
|
||||
pub fn project_board_lists(model: &Model) -> Node<Msg> {
|
||||
|
@ -1,7 +1,7 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use chrono::Datelike;
|
||||
use bitque_data::Issue;
|
||||
use chrono::Datelike;
|
||||
use seed::prelude::*;
|
||||
use seed::*;
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub use init_load_sets::*;
|
||||
use bitque_data::msg::{
|
||||
WsError, WsMsgComment, WsMsgEpic, WsMsgIssue, WsMsgIssueStatus, WsMsgMessage, WsMsgProject,
|
||||
WsMsgSession, WsMsgUser,
|
||||
};
|
||||
use bitque_data::*;
|
||||
pub use init_load_sets::*;
|
||||
use seed::prelude::*;
|
||||
|
||||
use crate::model::*;
|
||||
|
@ -14,11 +14,12 @@ path = "./src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
actix = { version = "0.13.0" }
|
||||
actix-web = { version = "4" }
|
||||
actix-web-actors = { version = "4" }
|
||||
async-trait = { version = "*" }
|
||||
bincode = { version = "*" }
|
||||
bitque-config = { workspace = true, features = ["websocket"] }
|
||||
bitque-data = { workspace = true, features = ["backend"] }
|
||||
common = { workspace = true }
|
||||
comrak = { version = "*" }
|
||||
database-actor = { workspace = true }
|
||||
flate2 = { version = "*" }
|
||||
@ -31,4 +32,5 @@ openssl-sys = { version = "*", features = ["vendored"] }
|
||||
serde = { version = "*" }
|
||||
syntect = { version = "*" }
|
||||
toml = { version = "*" }
|
||||
tracing = { version = "0.1.37" }
|
||||
uuid = { version = "1.3.0", features = ["serde", "v4", "v5"] }
|
||||
|
@ -1,10 +1,10 @@
|
||||
use actix::AsyncContext;
|
||||
use bitque_data::msg::{WsError, WsMsgSession};
|
||||
use bitque_data::{Token, WsMsg};
|
||||
use database_actor::authorize_user::AuthorizeUser;
|
||||
use database_actor::tokens::{CreateBindToken, FindBindToken};
|
||||
use database_actor::users::LookupUser;
|
||||
use futures::executor::block_on;
|
||||
use bitque_data::msg::{WsError, WsMsgSession};
|
||||
use bitque_data::{Token, WsMsg};
|
||||
use mail_actor::welcome::Welcome;
|
||||
|
||||
use crate::server::InnerMsg;
|
||||
|
@ -1,10 +1,10 @@
|
||||
use database_actor::invitations;
|
||||
use database_actor::messages::CreateMessageReceiver;
|
||||
use futures::executor::block_on;
|
||||
use bitque_data::msg::{WsMsgInvitation, WsMsgMessage};
|
||||
use bitque_data::{
|
||||
EmailString, InvitationId, InvitationToken, MessageType, UserRole, UsernameString, WsMsg,
|
||||
};
|
||||
use database_actor::invitations;
|
||||
use database_actor::messages::CreateMessageReceiver;
|
||||
use futures::executor::block_on;
|
||||
|
||||
use crate::handlers::{LoadInvitedUsers, RemoveInvitedUser};
|
||||
use crate::server::InnerMsg;
|
||||
|
@ -1,6 +1,6 @@
|
||||
use database_actor::issue_statuses;
|
||||
use bitque_data::msg::WsMsgIssueStatus;
|
||||
use bitque_data::{IssueStatusId, Position, TitleString, WsMsg};
|
||||
use database_actor::issue_statuses;
|
||||
|
||||
use crate::{db_or_debug_and_return, AsyncHandler, WebSocketActor, WsResult};
|
||||
|
||||
|
@ -1,9 +1,11 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use bitque_data::msg::{IssueSync, WsMsgIssue, WsMsgProject};
|
||||
use bitque_data::{
|
||||
CreateIssuePayload, IssueAssignee, IssueFieldId, IssueId, PayloadVariant, WsMsg,
|
||||
};
|
||||
use database_actor::issue_assignees::LoadAssignees;
|
||||
use database_actor::issues::{LoadProjectIssues, UpdateIssue};
|
||||
use bitque_data::msg::{IssueSync, WsMsgIssue, WsMsgProject};
|
||||
use bitque_data::{CreateIssuePayload, IssueAssignee, IssueFieldId, IssueId, PayloadVariant, WsMsg};
|
||||
|
||||
use crate::{db_or_debug_and_return, AsyncHandler, WebSocketActor, WsResult};
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
use database_actor::messages;
|
||||
use bitque_data::msg::WsMsgMessage;
|
||||
use bitque_data::MessageId;
|
||||
use database_actor::messages;
|
||||
|
||||
use crate::{db_or_debug_and_return, AsyncHandler, WebSocketActor, WsResult};
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
use database_actor as db;
|
||||
use bitque_data::msg::WsMsgProject;
|
||||
use bitque_data::{UpdateProjectPayload, UserProject, WsMsg};
|
||||
use database_actor as db;
|
||||
|
||||
use crate::handlers::{LoadIssues, LoadProjectUsers};
|
||||
use crate::{db_or_debug_and_return, AsyncHandler, WebSocketActor, WsResult};
|
||||
|
@ -1,5 +1,5 @@
|
||||
use database_actor as db;
|
||||
use bitque_data::{UserProjectId, WsMsg};
|
||||
use database_actor as db;
|
||||
|
||||
use crate::{db_or_debug_and_return, AsyncHandler, WebSocketActor, WsResult};
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
use database_actor::users::Register as DbRegister;
|
||||
use database_actor::{self};
|
||||
use bitque_data::msg::{WsMsgInvitation, WsMsgProject, WsMsgSession, WsMsgUser};
|
||||
use bitque_data::{UserId, UserProject, UserRole, WsMsg};
|
||||
use database_actor::users::Register as DbRegister;
|
||||
use database_actor::{self};
|
||||
|
||||
use crate::handlers::auth::Authenticate;
|
||||
use crate::handlers::user_settings;
|
||||
|
@ -2,15 +2,14 @@ use actix::{Actor, ActorContext, Addr, AsyncContext, Handler, Recipient, StreamH
|
||||
use actix_web::web::{self, Data};
|
||||
use actix_web::{get, Error, HttpRequest, HttpResponse};
|
||||
use actix_web_actors::ws;
|
||||
use ::tracing::*;
|
||||
use common::{actix_web, actix_web_actors};
|
||||
use bitque_data::msg::{WsMsgInvitation, WsMsgSession};
|
||||
use bitque_data::{Project, User, UserProject, WsMsg};
|
||||
use database_actor::projects::LoadCurrentProject;
|
||||
use database_actor::user_projects::CurrentUserProject;
|
||||
use database_actor::DbExecutor;
|
||||
use futures::executor::block_on as wait;
|
||||
use bitque_data::msg::{WsMsgInvitation, WsMsgSession};
|
||||
use bitque_data::{Project, User, UserProject, WsMsg};
|
||||
use mail_actor::MailExecutor;
|
||||
use tracing::*;
|
||||
|
||||
use crate::handlers::*;
|
||||
use crate::server::{InnerMsg, WsServer};
|
||||
|
@ -1,7 +1,7 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use actix::{Actor, Context, Recipient};
|
||||
use ::tracing::*;
|
||||
use actix::{Actor, Context, Recipient};
|
||||
use bitque_data::{ProjectId, UserId, WsMsg};
|
||||
|
||||
#[derive(Debug, actix::Message)]
|
||||
@ -110,10 +110,7 @@ impl WsServer {
|
||||
|
||||
fn send_to_recipients(&self, recipients: &[Recipient<InnerMsg>], msg: &WsMsg) {
|
||||
for recipient in recipients.iter() {
|
||||
match recipient.do_send(InnerMsg::Transfer(msg.clone())) {
|
||||
Ok(_) => ::tracing::debug!("msg sent"),
|
||||
Err(e) => ::tracing::error!("{}", e),
|
||||
};
|
||||
recipient.do_send(InnerMsg::Transfer(msg.clone()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1 +1 @@
|
||||
DROP TYPE IF EXISTS "ProjectCategory" CASCADE;
|
||||
DROP TYPE IF EXISTS "ProjectCategoryMapping" CASCADE;
|
||||
|
@ -1,5 +1,5 @@
|
||||
DROP TYPE IF EXISTS "ProjectCategory" CASCADE;
|
||||
CREATE TYPE "ProjectCategory" as ENUM (
|
||||
DROP TYPE IF EXISTS "ProjectCategoryMapping" CASCADE;
|
||||
CREATE TYPE "ProjectCategoryMapping" as ENUM (
|
||||
'software',
|
||||
'marketing',
|
||||
'business'
|
||||
|
@ -1 +1 @@
|
||||
DROP TYPE IF EXISTS "IssuePriority" CASCADE;
|
||||
DROP TYPE IF EXISTS "IssuePriorityMapping" CASCADE;
|
||||
|
@ -1,5 +1,5 @@
|
||||
DROP TYPE IF EXISTS "IssuePriority" CASCADE;
|
||||
CREATE TYPE "IssuePriority" as ENUM (
|
||||
DROP TYPE IF EXISTS "IssuePriorityMapping" CASCADE;
|
||||
CREATE TYPE "IssuePriorityMapping" as ENUM (
|
||||
'highest',
|
||||
'high',
|
||||
'medium',
|
||||
|
@ -1 +1 @@
|
||||
DROP TYPE IF EXISTS "IssueType" CASCADE;
|
||||
DROP TYPE IF EXISTS "IssueTypeMapping" CASCADE;
|
||||
|
@ -1,5 +1,5 @@
|
||||
DROP TYPE IF EXISTS "IssueType" CASCADE;
|
||||
CREATE TYPE "IssueType" AS ENUM (
|
||||
DROP TYPE IF EXISTS "IssueTypeMapping" CASCADE;
|
||||
CREATE TYPE "IssueTypeMapping" AS ENUM (
|
||||
'task',
|
||||
'bug',
|
||||
'story'
|
||||
|
@ -1 +1 @@
|
||||
DROP TYPE IF EXISTS "IssueStatus" CASCADE;
|
||||
DROP TYPE IF EXISTS "IssueStatusMapping" CASCADE;
|
||||
|
@ -1,5 +1,5 @@
|
||||
DROP TYPE IF EXISTS "IssueStatus" CASCADE;
|
||||
CREATE TYPE "IssueStatus" AS ENUM (
|
||||
DROP TYPE IF EXISTS "IssueStatusMapping" CASCADE;
|
||||
CREATE TYPE "IssueStatusMapping" AS ENUM (
|
||||
'backlog',
|
||||
'selected',
|
||||
'in_progress',
|
||||
|
@ -1,9 +1,9 @@
|
||||
CREATE TABLE issues (
|
||||
id serial primary key not null,
|
||||
title text not null,
|
||||
issue_type "IssueType" NOT NULL DEFAULT 'task',
|
||||
status "IssueStatus" NOT NULL DEFAULT 'backlog',
|
||||
priority "IssuePriority" NOT NULL DEFAULT 'low',
|
||||
issue_type "IssueTypeMapping" NOT NULL DEFAULT 'task',
|
||||
status "IssueStatusMapping" NOT NULL DEFAULT 'backlog',
|
||||
priority "IssuePriorityMapping" NOT NULL DEFAULT 'low',
|
||||
list_position double precision not null default 0,
|
||||
description text,
|
||||
description_text text,
|
||||
|
@ -4,8 +4,8 @@ DROP DEFAULT;
|
||||
|
||||
ALTER TABLE projects
|
||||
ALTER COLUMN category
|
||||
SET DATA TYPE "ProjectCategory"
|
||||
USING category::text::"ProjectCategory";
|
||||
SET DATA TYPE "ProjectCategoryMapping"
|
||||
USING category::text::"ProjectCategoryMapping";
|
||||
|
||||
ALTER TABLE projects
|
||||
ALTER COLUMN category
|
||||
|
@ -1,2 +1,2 @@
|
||||
ALTER TABLE IF EXISTS users DROP COLUMN role;
|
||||
DROP TYPE IF EXISTS "UserRole";
|
||||
DROP TYPE IF EXISTS "UserRoleMapping";
|
||||
|
@ -1,8 +1,8 @@
|
||||
DROP TYPE IF EXISTS "UserRole" CASCADE;
|
||||
CREATE TYPE "UserRole" AS ENUM (
|
||||
DROP TYPE IF EXISTS "UserRoleMapping" CASCADE;
|
||||
CREATE TYPE "UserRoleMapping" AS ENUM (
|
||||
'user',
|
||||
'manager',
|
||||
'owner'
|
||||
);
|
||||
|
||||
ALTER TABLE users ADD COLUMN role "UserRole" DEFAULT 'user' NOT NULL;
|
||||
ALTER TABLE users ADD COLUMN role "UserRoleMapping" DEFAULT 'user' NOT NULL;
|
||||
|
@ -1,2 +1,2 @@
|
||||
drop TABLE IF EXISTS invitations CASCADE;
|
||||
drop TYPE IF EXISTS "InvitationState" CASCADE;
|
||||
drop TYPE IF EXISTS "InvitationStateMapping" CASCADE;
|
||||
|
@ -1,4 +1,4 @@
|
||||
create type "InvitationState" AS ENUM (
|
||||
create type "InvitationStateMapping" AS ENUM (
|
||||
'sent',
|
||||
'accepted',
|
||||
'revoked'
|
||||
@ -8,7 +8,7 @@ create table invitations (
|
||||
id serial primary key not null,
|
||||
name text not null,
|
||||
email text not null,
|
||||
state "InvitationState" not null default 'sent',
|
||||
state "InvitationStateMapping" not null default 'sent',
|
||||
project_id integer not null references projects (id),
|
||||
invited_by_id integer not null references users (id),
|
||||
created_at timestamp not null default now(),
|
||||
|
@ -1,3 +1,3 @@
|
||||
alter TABLE projects drop COLUMN time_tracking;
|
||||
|
||||
drop TYPE IF EXISTS "TimeTracking";
|
||||
drop TYPE IF EXISTS "TimeTrackingMapping";
|
||||
|
@ -1,7 +1,7 @@
|
||||
CREATE TYPE "TimeTracking" AS ENUM (
|
||||
CREATE TYPE "TimeTrackingMapping" AS ENUM (
|
||||
'untracked',
|
||||
'fibonacci',
|
||||
'hourly'
|
||||
);
|
||||
|
||||
ALTER TABLE projects ADD COLUMN time_tracking "TimeTracking" NOT NULL DEFAULT 'untracked';
|
||||
ALTER TABLE projects ADD COLUMN time_tracking "TimeTrackingMapping" NOT NULL DEFAULT 'untracked';
|
||||
|
@ -1,13 +1,13 @@
|
||||
DROP TYPE IF EXISTS "IssueStatus" CASCADE;
|
||||
CREATE TYPE "IssueStatus" AS ENUM (
|
||||
DROP TYPE IF EXISTS "IssueStatusMapping" CASCADE;
|
||||
CREATE TYPE "IssueStatusMapping" AS ENUM (
|
||||
'backlog',
|
||||
'selected',
|
||||
'in_progress',
|
||||
'done'
|
||||
);
|
||||
ALTER TABLE issues ADD COLUMN status "IssueStatus";
|
||||
ALTER TABLE issues ADD COLUMN status "IssueStatusMapping";
|
||||
UPDATE issues
|
||||
SET status = issue_statuses.name :: "IssueStatus"
|
||||
SET status = issue_statuses.name :: "IssueStatusMapping"
|
||||
FROM issue_statuses
|
||||
WHERE issue_statuses.id = issues.issue_status_id;
|
||||
|
||||
|
@ -34,4 +34,4 @@ WHERE issue_statuses.name = issues.status :: text AND issues.project_id = issue_
|
||||
ALTER TABLE issues DROP COLUMN status;
|
||||
ALTER TABLE issues ALTER COLUMN issue_status_id SET NOT NULL;
|
||||
|
||||
DROP TYPE IF EXISTS "IssueStatus";
|
||||
DROP TYPE IF EXISTS "IssueStatusMapping";
|
||||
|
@ -1,6 +1,6 @@
|
||||
BEGIN;
|
||||
|
||||
ALTER TABLE users ADD COLUMN role "UserRole" DEFAULT 'user' NOT NULL;
|
||||
ALTER TABLE users ADD COLUMN role "UserRoleMapping" DEFAULT 'user' NOT NULL;
|
||||
ALTER TABLE users ADD COLUMN project_id int;
|
||||
|
||||
UPDATE users
|
||||
|
@ -7,7 +7,7 @@ CREATE TABLE user_projects (
|
||||
project_id int not null references projects (id),
|
||||
is_default bool not null default false,
|
||||
is_current bool not null default false,
|
||||
role "UserRole" not null default 'user',
|
||||
role "UserRoleMapping" not null default 'user',
|
||||
created_at timestamp not null default now(),
|
||||
updated_at timestamp not null default now()
|
||||
);
|
||||
|
@ -1 +1 @@
|
||||
ALTER TABLE invitations ADD COLUMN role "UserRole" NOT NULL DEFAULT 'user';
|
||||
ALTER TABLE invitations ADD COLUMN role "UserRoleMapping" NOT NULL DEFAULT 'user';
|
||||
|
@ -1,4 +1,4 @@
|
||||
ALTER TABLE messages
|
||||
ALTER COLUMN message_type
|
||||
SET DATA TYPE text;
|
||||
DROP TYPE "MessageType";
|
||||
DROP TYPE "MessageTypeMapping";
|
||||
|
@ -1,4 +1,4 @@
|
||||
CREATE TYPE "MessageType" AS ENUM (
|
||||
CREATE TYPE "MessageTypeMapping" AS ENUM (
|
||||
'received_invitation',
|
||||
'assigned_to_issue',
|
||||
'mention'
|
||||
@ -6,5 +6,5 @@ CREATE TYPE "MessageType" AS ENUM (
|
||||
|
||||
ALTER TABLE messages
|
||||
ALTER COLUMN message_type
|
||||
SET DATA TYPE "MessageType"
|
||||
USING message_type::text::"MessageType";
|
||||
SET DATA TYPE "MessageTypeMapping"
|
||||
USING message_type::text::"MessageTypeMapping";
|
||||
|
@ -7,8 +7,8 @@ UPDATE "issues"
|
||||
SET "issue_type" = 'task'
|
||||
WHERE "issue_type" = 'epic';
|
||||
|
||||
DROP TYPE IF EXISTS "IssueType" CASCADE;
|
||||
CREATE TYPE "IssueType" AS ENUM (
|
||||
DROP TYPE IF EXISTS "IssueTypeMapping" CASCADE;
|
||||
CREATE TYPE "IssueTypeMapping" AS ENUM (
|
||||
'task',
|
||||
'bug',
|
||||
'story'
|
||||
@ -16,5 +16,5 @@ CREATE TYPE "IssueType" AS ENUM (
|
||||
|
||||
ALTER TABLE "issues"
|
||||
ALTER COLUMN "issue_type"
|
||||
SET DATA TYPE "IssueType"
|
||||
USING "issue_type"::"IssueType";
|
||||
SET DATA TYPE "IssueTypeMapping"
|
||||
USING "issue_type"::"IssueTypeMapping";
|
||||
|
@ -3,8 +3,8 @@ ALTER TABLE "issues"
|
||||
SET DATA TYPE TEXT
|
||||
USING "issue_type"::TEXT;
|
||||
|
||||
DROP TYPE IF EXISTS "IssueType" CASCADE;
|
||||
CREATE TYPE "IssueType" AS ENUM (
|
||||
DROP TYPE IF EXISTS "IssueTypeMapping" CASCADE;
|
||||
CREATE TYPE "IssueTypeMapping" AS ENUM (
|
||||
'task',
|
||||
'bug',
|
||||
'story',
|
||||
@ -13,5 +13,5 @@ CREATE TYPE "IssueType" AS ENUM (
|
||||
|
||||
ALTER TABLE "issues"
|
||||
ALTER COLUMN "issue_type"
|
||||
SET DATA TYPE "IssueType"
|
||||
USING "issue_type"::"IssueType";
|
||||
SET DATA TYPE "IssueTypeMapping"
|
||||
USING "issue_type"::"IssueTypeMapping";
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user