Upgrade and organize

This commit is contained in:
Adrian Woźniak 2023-04-01 22:31:57 +02:00
parent cad12e7a76
commit a192a1584e
104 changed files with 1404 additions and 815 deletions

497
Cargo.lock generated
View File

@ -79,10 +79,12 @@ dependencies = [
"ahash 0.8.3", "ahash 0.8.3",
"base64 0.21.0", "base64 0.21.0",
"bitflags 1.3.2", "bitflags 1.3.2",
"brotli",
"bytes", "bytes",
"bytestring", "bytestring",
"derive_more", "derive_more",
"encoding_rs", "encoding_rs",
"flate2",
"futures-core", "futures-core",
"h2", "h2",
"http", "http",
@ -100,6 +102,17 @@ dependencies = [
"tokio", "tokio",
"tokio-util", "tokio-util",
"tracing", "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]] [[package]]
@ -159,6 +172,7 @@ version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15265b6b8e2347670eb363c47fc8c75208b4a4994b27192f345fcbe707804f3e" checksum = "15265b6b8e2347670eb363c47fc8c75208b4a4994b27192f345fcbe707804f3e"
dependencies = [ dependencies = [
"actix-macros",
"futures-core", "futures-core",
"tokio", "tokio",
] ]
@ -210,15 +224,18 @@ checksum = "cd3cb42f9566ab176e1ef0b8b3a896529062b4efc6be0123046095914c4c1c96"
dependencies = [ dependencies = [
"actix-codec", "actix-codec",
"actix-http", "actix-http",
"actix-macros",
"actix-router", "actix-router",
"actix-rt", "actix-rt",
"actix-server", "actix-server",
"actix-service", "actix-service",
"actix-utils", "actix-utils",
"actix-web-codegen",
"ahash 0.7.6", "ahash 0.7.6",
"bytes", "bytes",
"bytestring", "bytestring",
"cfg-if 1.0.0", "cfg-if",
"cookie",
"derive_more", "derive_more",
"encoding_rs", "encoding_rs",
"futures-core", "futures-core",
@ -240,6 +257,36 @@ dependencies = [
"url", "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]] [[package]]
name = "actix_derive" name = "actix_derive"
version = "0.6.0" version = "0.6.0"
@ -274,7 +321,7 @@ version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f"
dependencies = [ dependencies = [
"cfg-if 1.0.0", "cfg-if",
"getrandom", "getrandom",
"once_cell", "once_cell",
"version_check 0.9.4", "version_check 0.9.4",
@ -289,6 +336,21 @@ dependencies = [
"memchr", "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]] [[package]]
name = "amazon-actor" name = "amazon-actor"
version = "0.1.0" version = "0.1.0"
@ -296,7 +358,6 @@ dependencies = [
"actix", "actix",
"bitque-config", "bitque-config",
"bytes", "bytes",
"common",
"futures", "futures",
"libc", "libc",
"openssl-sys", "openssl-sys",
@ -305,6 +366,7 @@ dependencies = [
"rusoto_signature", "rusoto_signature",
"serde", "serde",
"tokio", "tokio",
"tracing",
"uuid 1.3.0", "uuid 1.3.0",
] ]
@ -478,10 +540,11 @@ name = "bitque"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"actix", "actix",
"actix-rt",
"actix-web",
"amazon-actor", "amazon-actor",
"bitque-config", "bitque-config",
"bitque-data", "bitque-data",
"common",
"database-actor", "database-actor",
"dotenv", "dotenv",
"filesystem-actor", "filesystem-actor",
@ -494,6 +557,8 @@ dependencies = [
"serde_json", "serde_json",
"tokio", "tokio",
"toml", "toml",
"tracing",
"tracing-subscriber",
"web-actor", "web-actor",
"websocket-actor", "websocket-actor",
] ]
@ -516,7 +581,7 @@ dependencies = [
"actix", "actix",
"chrono", "chrono",
"diesel 2.0.3", "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-more",
"diesel-derive-newtype", "diesel-derive-newtype",
"serde", "serde",
@ -525,38 +590,12 @@ dependencies = [
"uuid 1.3.0", "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]] [[package]]
name = "bitquec" name = "bitquec"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"actix", "actix",
"clap", "clap",
"common",
"termion 2.0.1", "termion 2.0.1",
"tui", "tui",
] ]
@ -579,6 +618,27 @@ dependencies = [
"generic-array", "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]] [[package]]
name = "bumpalo" name = "bumpalo"
version = "3.12.0" version = "3.12.0"
@ -617,12 +677,9 @@ name = "cc"
version = "1.0.79" version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
dependencies = [
[[package]] "jobserver",
name = "cfg-if" ]
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
@ -708,10 +765,6 @@ dependencies = [
"unicode-width", "unicode-width",
] ]
[[package]]
name = "common"
version = "0.1.0"
[[package]] [[package]]
name = "comrak" name = "comrak"
version = "0.18.0" version = "0.18.0"
@ -746,22 +799,23 @@ dependencies = [
"windows-sys 0.45.0", "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]] [[package]]
name = "convert_case" name = "convert_case"
version = "0.4.0" version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" 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]] [[package]]
name = "core-foundation" name = "core-foundation"
version = "0.9.3" version = "0.9.3"
@ -793,7 +847,7 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
dependencies = [ dependencies = [
"cfg-if 1.0.0", "cfg-if",
] ]
[[package]] [[package]]
@ -802,7 +856,7 @@ version = "0.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf2b3e8478797446514c91ef04bafcb59faba183e621ad488df88983cc14128c" checksum = "cf2b3e8478797446514c91ef04bafcb59faba183e621ad488df88983cc14128c"
dependencies = [ dependencies = [
"cfg-if 1.0.0", "cfg-if",
"crossbeam-utils", "crossbeam-utils",
] ]
@ -812,7 +866,7 @@ version = "0.8.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b"
dependencies = [ dependencies = [
"cfg-if 1.0.0", "cfg-if",
] ]
[[package]] [[package]]
@ -951,7 +1005,6 @@ dependencies = [
"bitque-data", "bitque-data",
"byteorder", "byteorder",
"chrono", "chrono",
"common",
"derive_db_execute", "derive_db_execute",
"diesel 2.0.3", "diesel 2.0.3",
"dotenv", "dotenv",
@ -985,10 +1038,6 @@ version = "0.1.0"
name = "derive_enum_primitive" name = "derive_enum_primitive"
version = "0.1.0" version = "0.1.0"
[[package]]
name = "derive_enum_sql"
version = "0.1.0"
[[package]] [[package]]
name = "derive_more" name = "derive_more"
version = "0.99.17" version = "0.99.17"
@ -1041,6 +1090,16 @@ dependencies = [
"uuid 1.3.0", "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]] [[package]]
name = "diesel-derive-enum" name = "diesel-derive-enum"
version = "2.0.1" version = "2.0.1"
@ -1132,7 +1191,7 @@ version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1"
dependencies = [ dependencies = [
"cfg-if 1.0.0", "cfg-if",
"dirs-sys-next", "dirs-sys-next",
] ]
@ -1195,12 +1254,6 @@ version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2153bd83ebc09db15bcbdc3e2194d901804952e3dc96967e1cd3b0c5c32d112" checksum = "e2153bd83ebc09db15bcbdc3e2194d901804952e3dc96967e1cd3b0c5c32d112"
[[package]]
name = "enclose"
version = "1.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1056f553da426e9c025a662efa48b52e62e0a3a7648aa2d15aeaaf7f0d329357"
[[package]] [[package]]
name = "encoding" name = "encoding"
version = "0.2.33" version = "0.2.33"
@ -1271,7 +1324,7 @@ version = "0.8.32"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394"
dependencies = [ dependencies = [
"cfg-if 1.0.0", "cfg-if",
] ]
[[package]] [[package]]
@ -1348,7 +1401,6 @@ dependencies = [
"actix-files", "actix-files",
"bitque-config", "bitque-config",
"bytes", "bytes",
"common",
"futures", "futures",
"tokio", "tokio",
] ]
@ -1504,59 +1556,9 @@ version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
dependencies = [ dependencies = [
"cfg-if 1.0.0", "cfg-if",
"js-sys",
"libc", "libc",
"wasi 0.11.0+wasi-snapshot-preview1", "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]] [[package]]
@ -1619,7 +1621,6 @@ dependencies = [
"bincode", "bincode",
"bitque-config", "bitque-config",
"bitque-data", "bitque-data",
"common",
"flate2", "flate2",
"lazy_static", "lazy_static",
"serde", "serde",
@ -1782,7 +1783,7 @@ version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
dependencies = [ dependencies = [
"cfg-if 1.0.0", "cfg-if",
] ]
[[package]] [[package]]
@ -1823,6 +1824,15 @@ version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
[[package]]
name = "jobserver"
version = "0.1.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "js-sys" name = "js-sys"
version = "0.3.61" version = "0.3.61"
@ -1967,7 +1977,7 @@ version = "0.4.17"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
dependencies = [ dependencies = [
"cfg-if 1.0.0", "cfg-if",
] ]
[[package]] [[package]]
@ -1976,7 +1986,6 @@ version = "0.1.0"
dependencies = [ dependencies = [
"actix", "actix",
"bitque-config", "bitque-config",
"common",
"dotenv", "dotenv",
"futures", "futures",
"lettre 0.10.3", "lettre 0.10.3",
@ -1995,6 +2004,15 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" 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]] [[package]]
name = "md-5" name = "md-5"
version = "0.9.1" version = "0.9.1"
@ -2012,12 +2030,6 @@ version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "memory_units"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8452105ba047068f40ff7093dd1d9da90898e63dd61736462e9cdda6a90ad3c3"
[[package]] [[package]]
name = "mime" name = "mime"
version = "0.3.17" version = "0.3.17"
@ -2089,6 +2101,16 @@ dependencies = [
"minimal-lexical", "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]] [[package]]
name = "num-bigint" name = "num-bigint"
version = "0.4.3" version = "0.4.3"
@ -2176,7 +2198,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "518915b97df115dd36109bfa429a48b8f737bd05508cf9588977b599648926d2" checksum = "518915b97df115dd36109bfa429a48b8f737bd05508cf9588977b599648926d2"
dependencies = [ dependencies = [
"bitflags 1.3.2", "bitflags 1.3.2",
"cfg-if 1.0.0", "cfg-if",
"foreign-types", "foreign-types",
"libc", "libc",
"once_cell", "once_cell",
@ -2224,6 +2246,12 @@ dependencies = [
"vcpkg", "vcpkg",
] ]
[[package]]
name = "overload"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
[[package]] [[package]]
name = "parking_lot" name = "parking_lot"
version = "0.12.1" version = "0.12.1"
@ -2240,7 +2268,7 @@ version = "0.9.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521"
dependencies = [ dependencies = [
"cfg-if 1.0.0", "cfg-if",
"libc", "libc",
"redox_syscall 0.2.16", "redox_syscall 0.2.16",
"smallvec", "smallvec",
@ -2623,6 +2651,15 @@ dependencies = [
"regex-syntax", "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]] [[package]]
name = "regex-syntax" name = "regex-syntax"
version = "0.6.29" version = "0.6.29"
@ -2793,12 +2830,6 @@ dependencies = [
"parking_lot", "parking_lot",
] ]
[[package]]
name = "scoped-tls"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
[[package]] [[package]]
name = "scopeguard" name = "scopeguard"
version = "1.1.0" version = "1.1.0"
@ -2834,28 +2865,6 @@ dependencies = [
"libc", "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]] [[package]]
name = "semver" name = "semver"
version = "1.0.17" version = "1.0.17"
@ -2929,7 +2938,7 @@ version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3"
dependencies = [ dependencies = [
"cfg-if 1.0.0", "cfg-if",
"cpufeatures", "cpufeatures",
"digest 0.10.6", "digest 0.10.6",
] ]
@ -2947,12 +2956,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800"
dependencies = [ dependencies = [
"block-buffer 0.9.0", "block-buffer 0.9.0",
"cfg-if 1.0.0", "cfg-if",
"cpufeatures", "cpufeatures",
"digest 0.9.0", "digest 0.9.0",
"opaque-debug", "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]] [[package]]
name = "shell-words" name = "shell-words"
version = "1.1.0" version = "1.1.0"
@ -3039,12 +3057,6 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "spin"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
[[package]] [[package]]
name = "strsim" name = "strsim"
version = "0.10.0" version = "0.10.0"
@ -3153,7 +3165,7 @@ version = "3.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998"
dependencies = [ dependencies = [
"cfg-if 1.0.0", "cfg-if",
"fastrand", "fastrand",
"redox_syscall 0.3.5", "redox_syscall 0.3.5",
"rustix 0.37.5", "rustix 0.37.5",
@ -3223,6 +3235,16 @@ dependencies = [
"syn 2.0.12", "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]] [[package]]
name = "time" name = "time"
version = "0.1.45" version = "0.1.45"
@ -3376,7 +3398,7 @@ version = "0.1.37"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
dependencies = [ dependencies = [
"cfg-if 1.0.0", "cfg-if",
"log", "log",
"pin-project-lite", "pin-project-lite",
"tracing-attributes", "tracing-attributes",
@ -3401,6 +3423,37 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a"
dependencies = [ dependencies = [
"once_cell", "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]] [[package]]
@ -3532,6 +3585,12 @@ dependencies = [
"sha1_smol", "sha1_smol",
] ]
[[package]]
name = "valuable"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
[[package]] [[package]]
name = "vcpkg" name = "vcpkg"
version = "0.2.15" version = "0.2.15"
@ -3588,7 +3647,7 @@ version = "0.2.84"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b"
dependencies = [ dependencies = [
"cfg-if 1.0.0", "cfg-if",
"wasm-bindgen-macro", "wasm-bindgen-macro",
] ]
@ -3607,18 +3666,6 @@ dependencies = [
"wasm-bindgen-shared", "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]] [[package]]
name = "wasm-bindgen-macro" name = "wasm-bindgen-macro"
version = "0.2.84" version = "0.2.84"
@ -3648,41 +3695,19 @@ version = "0.2.84"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" 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]] [[package]]
name = "web-actor" name = "web-actor"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"actix", "actix",
"actix-multipart", "actix-multipart",
"actix-web",
"actix-web-actors",
"amazon-actor", "amazon-actor",
"bincode", "bincode",
"bitque-config", "bitque-config",
"bitque-data", "bitque-data",
"common", "bytes",
"database-actor", "database-actor",
"filesystem-actor", "filesystem-actor",
"futures", "futures",
@ -3692,30 +3717,22 @@ dependencies = [
"serde", "serde",
"tokio", "tokio",
"toml", "toml",
"tracing",
"uuid 1.3.0", "uuid 1.3.0",
"websocket-actor", "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]] [[package]]
name = "websocket-actor" name = "websocket-actor"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"actix", "actix",
"actix-web",
"actix-web-actors",
"async-trait", "async-trait",
"bincode", "bincode",
"bitque-config", "bitque-config",
"bitque-data", "bitque-data",
"common",
"comrak", "comrak",
"database-actor", "database-actor",
"flate2", "flate2",
@ -3728,22 +3745,10 @@ dependencies = [
"serde", "serde",
"syntect", "syntect",
"toml", "toml",
"tracing",
"uuid 1.3.0", "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]] [[package]]
name = "winapi" name = "winapi"
version = "0.3.9" version = "0.3.9"
@ -3960,3 +3965,33 @@ name = "zeroize"
version = "1.6.0" version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" 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",
]

View File

@ -10,7 +10,6 @@
[workspace] [workspace]
members = [ members = [
"./crates/common",
"./crates/bitque-cli", "./crates/bitque-cli",
"./crates/bitque-server", "./crates/bitque-server",
"./crates/bitque-config", "./crates/bitque-config",
@ -27,11 +26,14 @@ members = [
"./crates/amazon-actor", "./crates/amazon-actor",
"./crates/filesystem-actor", "./crates/filesystem-actor",
# Client # Client
"./crates/web" # "./crates/web"
]
exclude = [
"crates/bitque-cli",
"crates/web",
] ]
[workspace.dependencies] [workspace.dependencies]
common = { path = "./crates/common" }
bitque-cli = { path = "./crates/bitque-cli" } bitque-cli = { path = "./crates/bitque-cli" }
bitque-server = { path = "./crates/bitque-server" } bitque-server = { path = "./crates/bitque-server" }
bitque-config = { path = "./crates/bitque-config" } bitque-config = { path = "./crates/bitque-config" }

View File

@ -15,8 +15,7 @@ path = "./src/lib.rs"
[dependencies] [dependencies]
actix = { version = "0.13.0" } actix = { version = "0.13.0" }
bitque-config = { workspace = true, features = ["mail", "web", "local-storage"] } bitque-config = { workspace = true, features = ["mail", "web", "local-storage"] }
bytes = { version = "1.0.0" } bytes = { version = "1" }
common = { workspace = true }
futures = { version = "0.3.8" } futures = { version = "0.3.8" }
libc = { version = "0.2.0", default-features = false } libc = { version = "0.2.0", default-features = false }
openssl-sys = { version = "*", features = ["vendored"] } openssl-sys = { version = "*", features = ["vendored"] }
@ -25,4 +24,5 @@ rusoto_s3 = { version = "0.48.0" }
rusoto_signature = { version = "0.48.0" } rusoto_signature = { version = "0.48.0" }
serde = { version = "*" } serde = { version = "*" }
tokio = { version = "1", features = ["full"] } tokio = { version = "1", features = ["full"] }
tracing = { version = "0.1.37" }
uuid = { version = "1.3.0", features = ["serde", "v4", "v5"] } uuid = { version = "1.3.0", features = ["serde", "v4", "v5"] }

View File

@ -1,4 +1,3 @@
extern crate common;
use rusoto_s3::{PutObjectRequest, S3Client, S3}; use rusoto_s3::{PutObjectRequest, S3Client, S3};
#[derive(Debug)] #[derive(Debug)]
@ -21,7 +20,7 @@ impl actix::Actor for AmazonExecutor {
#[derive(actix::Message)] #[derive(actix::Message)]
#[rtype(result = "Result<String, AmazonError>")] #[rtype(result = "Result<String, AmazonError>")]
pub struct S3PutObject { pub struct S3PutObject {
pub source: tokio::sync::broadcast::Receiver<common::bytes::Bytes>, pub source: tokio::sync::broadcast::Receiver<bytes::Bytes>,
pub file_name: String, pub file_name: String,
} }
@ -40,7 +39,7 @@ impl actix::Handler<S3PutObject> for AmazonExecutor {
.expect("Failed to start amazon agent") .expect("Failed to start amazon agent")
.block_on(async { .block_on(async {
let s3 = bitque_config::amazon::config(); let s3 = bitque_config::amazon::config();
::tracing::debug!("{:?}", s3); tracing::debug!("{:?}", s3);
// TODO: Unable to upload as stream because there is no size_hint // TODO: Unable to upload as stream because there is no size_hint
// let stream = source // let stream = source
@ -50,10 +49,9 @@ impl actix::Handler<S3PutObject> for AmazonExecutor {
// use common::bytes::Buf; // use common::bytes::Buf;
// ::bytes::Bytes::from(b.bytes()) // ::bytes::Bytes::from(b.bytes())
// }); // });
use common::bytes::Buf;
let mut v: Vec<u8> = vec![]; let mut v: Vec<u8> = vec![];
while let Ok(b) = source.recv().await { while let Ok(b) = source.recv().await {
v.extend_from_slice(b.bytes()) v.extend_from_slice(&b)
} }
let client = S3Client::new(s3.region()); let client = S3Client::new(s3.region());

View File

@ -7,6 +7,5 @@ edition = "2018"
[dependencies] [dependencies]
actix = { version = "0.13.0" } actix = { version = "0.13.0" }
clap = { version = "4.1.13" } clap = { version = "4.1.13" }
common = { workspace = true }
termion = { version = "*" } termion = { version = "*" }
tui = { version = "0.19.0", features = ["termion"] } tui = { version = "0.19.0", features = ["termion"] }

View File

@ -5,12 +5,11 @@ use std::sync::{mpsc, Arc};
use std::time::Duration; use std::time::Duration;
use termion::event::Key; use termion::event::Key;
use termion::input::MouseTerminal; use termion::screen::IntoAlternateScreen;
use termion::raw::IntoRawMode;
use termion::screen::AlternateScreen;
use tui::backend::TermionBackend; use tui::backend::TermionBackend;
use tui::layout::{Constraint, Direction, Layout}; use tui::layout::{Constraint, Direction, Layout};
use tui::style::{Color, Style}; use tui::style::{Color, Style};
use tui::text::{Span, Spans};
use tui::widgets::{Block, Borders, Tabs}; use tui::widgets::{Block, Borders, Tabs};
use tui::Terminal; use tui::Terminal;
@ -126,9 +125,7 @@ struct App<'a> {
fn main() -> Result<(), Box<dyn Error>> { fn main() -> Result<(), Box<dyn Error>> {
// Terminal initialization // Terminal initialization
let stdout = io::stdout().into_raw_mode()?; let stdout = io::stdout().into_alternate_screen().unwrap();
let stdout = MouseTerminal::from(stdout);
let stdout = AlternateScreen::from(stdout);
let backend = TermionBackend::new(stdout); let backend = TermionBackend::new(stdout);
let mut terminal = Terminal::new(backend)?; let mut terminal = Terminal::new(backend)?;
terminal.hide_cursor()?; terminal.hide_cursor()?;
@ -142,7 +139,7 @@ fn main() -> Result<(), Box<dyn Error>> {
// Main loop // Main loop
loop { loop {
terminal.draw(|mut f| { terminal.draw(|f| {
let size = f.size(); let size = f.size();
let chunks = Layout::default() let chunks = Layout::default()
.direction(Direction::Vertical) .direction(Direction::Vertical)
@ -152,12 +149,17 @@ fn main() -> Result<(), Box<dyn Error>> {
let block = Block::default().style(Style::default().bg(Color::White)); let block = Block::default().style(Style::default().bg(Color::White));
f.render_widget(block, size); f.render_widget(block, size);
let tabs = Tabs::default() let tabs = Tabs::new(
.block(Block::default().borders(Borders::ALL).title("Tabs")) app.tabs
.titles(&app.tabs.titles) .titles
.select(app.tabs.index) .iter()
.style(Style::default().fg(Color::Cyan)) .map(|s| Spans::from(vec![Span::styled(*s, Style::default())]))
.highlight_style(Style::default().fg(Color::Yellow)); .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]); f.render_widget(tabs, chunks[0]);
let inner = match app.tabs.index { let inner = match app.tabs.index {
0 => Block::default().title("Inner 0").borders(Borders::ALL), 0 => Block::default().title("Inner 0").borders(Borders::ALL),

View File

@ -21,6 +21,7 @@ actix = { version = "0.13.0", optional = true }
chrono = { version = "*", features = ["serde"] } chrono = { version = "*", features = ["serde"] }
diesel = { version = "2.0.3", features = ["postgres", "numeric", "uuid", "r2d2"], optional = true } diesel = { version = "2.0.3", features = ["postgres", "numeric", "uuid", "r2d2"], optional = true }
diesel-derive-enum = { version = "2.0.1", features = ["postgres"] } 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-more = { version = "1.1.3" }
diesel-derive-newtype = { version = "2.0.0-rc.0", optional = true } diesel-derive-newtype = { version = "2.0.0-rc.0", optional = true }
serde = { version = "*" } serde = { version = "*" }

View File

@ -2,15 +2,15 @@ use std::cmp::Ordering;
use chrono::NaiveDateTime; use chrono::NaiveDateTime;
#[cfg(feature = "backend")] #[cfg(feature = "backend")]
use diesel_derive_enum::DbEnum;
#[cfg(feature = "backend")]
use diesel::*; use diesel::*;
#[cfg(feature = "backend")]
use diesel_derive_enum::DbEnum;
pub use fields::*; pub use fields::*;
pub use msg::WsMsg; pub use msg::WsMsg;
pub use payloads::*; pub use payloads::*;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use uuid::Uuid;
use strum::*; use strum::*;
use uuid::Uuid;
pub mod fields; pub mod fields;
pub mod msg; pub mod msg;
@ -52,7 +52,18 @@ pub type EndsAt = NaiveDateTime;
#[cfg_attr(feature = "backend", derive(DbEnum))] #[cfg_attr(feature = "backend", derive(DbEnum))]
#[derive( #[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")] #[strum(serialize_all = "snake_case")]
pub enum IssueType { pub enum IssueType {
@ -69,7 +80,18 @@ impl Default for IssueType {
#[cfg_attr(feature = "backend", derive(DbEnum))] #[cfg_attr(feature = "backend", derive(DbEnum))]
#[derive( #[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")] #[strum(serialize_all = "snake_case")]
pub enum IssuePriority { pub enum IssuePriority {
@ -87,7 +109,19 @@ impl Default for IssuePriority {
} }
#[cfg_attr(feature = "backend", derive(DbEnum))] #[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")] #[strum(serialize_all = "snake_case")]
pub enum UserRole { pub enum UserRole {
User, User,
@ -117,8 +151,20 @@ impl Default for UserRole {
} }
#[cfg_attr(feature = "backend", derive(DbEnum))] #[cfg_attr(feature = "backend", derive(DbEnum))]
#[cfg_attr(feature = "backend", PgType = "ProjectCategoryMapping")]
#[derive( #[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")] #[strum(serialize_all = "snake_case")]
pub enum ProjectCategory { pub enum ProjectCategory {
@ -134,8 +180,20 @@ impl Default for ProjectCategory {
} }
#[cfg_attr(feature = "backend", derive(DbEnum))] #[cfg_attr(feature = "backend", derive(DbEnum))]
#[cfg_attr(feature = "backend", PgType = "InvitationStateMapping")]
#[derive( #[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")] #[strum(serialize_all = "snake_case")]
pub enum InvitationState { pub enum InvitationState {
@ -151,8 +209,20 @@ impl Default for InvitationState {
} }
#[cfg_attr(feature = "backend", derive(DbEnum))] #[cfg_attr(feature = "backend", derive(DbEnum))]
#[cfg_attr(feature = "backend", PgType = "TimeTrackingMapping")]
#[derive( #[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")] #[strum(serialize_all = "snake_case")]
pub enum TimeTracking { pub enum TimeTracking {
@ -311,8 +381,19 @@ pub struct IssueAssignee {
} }
#[cfg_attr(feature = "backend", derive(DbEnum))] #[cfg_attr(feature = "backend", derive(DbEnum))]
#[cfg_attr(feature = "backend", PgType = "MessageTypeMapping")]
#[derive( #[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")] #[strum(serialize_all = "snake_case")]
pub enum MessageType { pub enum MessageType {
@ -391,9 +472,21 @@ pub struct HighlightedCode {
#[cfg_attr(feature = "backend", derive(DbEnum))] #[cfg_attr(feature = "backend", derive(DbEnum))]
#[derive( #[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")] #[strum(serialize_all = "snake_case")]
#[cfg_attr(feature = "backend", PgType = "TextEditorModeMapping")]
#[repr(C)] #[repr(C)]
pub enum TextEditorMode { pub enum TextEditorMode {
MdOnly, MdOnly,

View File

@ -15,10 +15,11 @@ default = ["local-storage"]
[dependencies] [dependencies]
actix = { version = "0" } actix = { version = "0" }
actix-rt = { version = "2" }
actix-web = { version = "4" }
amazon-actor = { workspace = true, optional = true } amazon-actor = { workspace = true, optional = true }
bitque-config = { workspace = true, features = ["web", "websocket", "local-storage", "hi", "database"] } bitque-config = { workspace = true, features = ["web", "websocket", "local-storage", "hi", "database"] }
bitque-data = { workspace = true, features = ["backend"] } bitque-data = { workspace = true, features = ["backend"] }
common = { workspace = true }
database-actor = { workspace = true } database-actor = { workspace = true }
dotenv = { version = "*" } dotenv = { version = "*" }
filesystem-actor = { workspace = true, optional = true } filesystem-actor = { workspace = true, optional = true }
@ -31,5 +32,7 @@ serde = { version = "*", features = ["derive"] }
serde_json = { version = ">=0.8.0, <2.0" } serde_json = { version = ">=0.8.0, <2.0" }
tokio = { version = "1", features = ["full"] } tokio = { version = "1", features = ["full"] }
toml = { version = "0.7.3" } 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"] } web-actor = { workspace = true, features = ["local-storage"] }
websocket-actor = { workspace = true } websocket-actor = { workspace = true }

View File

@ -1 +0,0 @@
../LICENSE

View File

@ -1,5 +1,4 @@
use actix_web::HttpResponse; use actix_web::HttpResponse;
use common::*;
use bitque_data::msg::WsError; use bitque_data::msg::WsError;
use bitque_data::ErrorResponse; use bitque_data::ErrorResponse;

View File

@ -1,11 +1,9 @@
#![feature(async_closure)] #![feature(async_closure)]
#![recursion_limit = "256"] #![recursion_limit = "256"]
extern crate common;
use actix::Actor; use actix::Actor;
use actix_web::{App, HttpServer}; use actix_web::{App, HttpServer};
use common::*; use tracing_subscriber::util::SubscriberInitExt;
pub mod errors; pub mod errors;
@ -19,7 +17,10 @@ macro_rules! featured {
#[actix_rt::main] #[actix_rt::main]
async fn main() -> Result<(), String> { async fn main() -> Result<(), String> {
dotenv::dotenv().ok(); 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(); let web_config = bitque_config::web::Configuration::read();
@ -53,12 +54,12 @@ async fn main() -> Result<(), String> {
// data step // data step
let app = app let app = app
.data(ws_server.clone()) .app_data(ws_server.clone())
.data(db_addr.clone()) .app_data(db_addr.clone())
.data(mail_addr.clone()) .app_data(mail_addr.clone())
.data(hi_addr.clone()) .app_data(hi_addr.clone())
.data(database_actor::build_pool()); .app_data(database_actor::build_pool());
featured! { app, "local-storage", app.data(fs_addr.clone()) }; featured! { app, "local-storage", app.app_data(fs_addr.clone()) };
featured! { app, "aws-s3", app.data(amazon_addr.clone()) }; featured! { app, "aws-s3", app.data(amazon_addr.clone()) };
// services step // services step

View File

@ -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]

View File

@ -21,7 +21,6 @@ bitque-config = { workspace = true, features = ["database"] }
bitque-data = { workspace = true, features = ["backend"] } bitque-data = { workspace = true, features = ["backend"] }
byteorder = { version = "1.0" } byteorder = { version = "1.0" }
chrono = { version = "0.4", features = ["serde"] } chrono = { version = "0.4", features = ["serde"] }
common = { workspace = true }
derive_db_execute = { workspace = true } derive_db_execute = { workspace = true }
diesel = { version = "2.0.3", features = ["postgres", "numeric", "uuid", "r2d2", "chrono"] } diesel = { version = "2.0.3", features = ["postgres", "numeric", "uuid", "r2d2", "chrono"] }
dotenv = { version = "*" } dotenv = { version = "*" }

View 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,
+// );

View File

@ -1,5 +1,5 @@
use diesel::prelude::*;
use bitque_data::User; use bitque_data::User;
use diesel::prelude::*;
use crate::db_find; use crate::db_find;
use crate::tokens::FindAccessToken; use crate::tokens::FindAccessToken;

View File

@ -1,5 +1,5 @@
use diesel::prelude::*;
use bitque_data::{Comment, CommentId, IssueId, UserId}; use bitque_data::{Comment, CommentId, IssueId, UserId};
use diesel::prelude::*;
use crate::{db_create, db_delete, db_load, db_update}; use crate::{db_create, db_delete, db_load, db_update};

View File

@ -1,10 +1,9 @@
use derive_db_execute::Execute;
use diesel::prelude::*;
use bitque_data::{DescriptionString, EndsAt, Epic, EpicId, ProjectId, StartsAt}; use bitque_data::{DescriptionString, EndsAt, Epic, EpicId, ProjectId, StartsAt};
use diesel::prelude::*;
use crate::{db_create, db_delete, db_load, db_update}; 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)")] #[db_exec(schema = "epics", result = "Epic", find = "epics.find(msg.epic_id)")]
pub struct FindEpic { pub struct FindEpic {
pub epic_id: EpicId, pub epic_id: EpicId,

View File

@ -1,15 +1,15 @@
use actix::{Handler, Message}; use actix::{Handler, Message};
use diesel::prelude::*;
use bitque_data::{ use bitque_data::{
EmailString, Invitation, InvitationId, InvitationState, InvitationToken, ProjectId, Token, EmailString, Invitation, InvitationId, InvitationState, InvitationToken, ProjectId, Token,
User, UserId, UserRole, UsernameString, User, UserId, UserRole, UsernameString,
}; };
use diesel::prelude::*;
use crate::tokens::CreateBindToken; use crate::tokens::CreateBindToken;
use crate::users::{LookupUser, Register}; use crate::users::{LookupUser, Register};
use crate::{ use crate::{
db_create, db_delete, db_find, db_load, db_pool, db_update, DbExecutor, DbPooledConn, db_create, db_delete, db_find, db_load, db_pool, db_update, DatabaseError, DbExecutor,
InvitationError, DbPooledConn, InvitationError,
}; };
db_find! { db_find! {
@ -80,12 +80,12 @@ impl Handler<RevokeInvitation> for DbExecutor {
type Result = Result<(), crate::DatabaseError>; type Result = Result<(), crate::DatabaseError>;
fn handle(&mut self, msg: RevokeInvitation, _ctx: &mut Self::Context) -> Self::Result { fn handle(&mut self, msg: RevokeInvitation, _ctx: &mut Self::Context) -> Self::Result {
let conn = db_pool!(self); let mut conn = db_pool!(self);
UpdateInvitationState { UpdateInvitationState {
id: msg.id, id: msg.id,
state: InvitationState::Revoked, state: InvitationState::Revoked,
} }
.execute(conn)?; .execute(&mut conn)?;
Ok(()) Ok(())
} }
} }
@ -95,63 +95,75 @@ pub struct AcceptInvitation {
} }
impl AcceptInvitation { impl AcceptInvitation {
pub fn execute(self, conn: &DbPooledConn) -> Result<Token, crate::DatabaseError> { pub fn execute(self, conn: &mut DbPooledConn) -> Result<Token, crate::DatabaseError> {
crate::Guard::new(conn)?.run::<Token, _>(|_guard| { let mut res = Err(DatabaseError::DatabaseConnectionLost);
let invitation = crate::invitations::FindByBindToken { conn.transaction(|conn| {
token: self.invitation_token, res = self.exec_in_transaction(conn);
if res.is_err() {
Err(diesel::NotFound)
} else {
Ok(())
} }
.execute(conn)?; })
.ok();
res
}
if invitation.state == InvitationState::Revoked { fn exec_in_transaction(self, conn: &mut DbPooledConn) -> Result<Token, crate::DatabaseError> {
return Err(crate::DatabaseError::Invitation( let invitation = FindByBindToken {
InvitationError::InvitationRevoked, token: self.invitation_token,
)); }
} .execute(conn)?;
crate::invitations::UpdateInvitationState { if invitation.state == InvitationState::Revoked {
id: invitation.id, return Err(crate::DatabaseError::Invitation(
state: InvitationState::Accepted, InvitationError::InvitationRevoked,
} ));
.execute(conn)?; }
UpdateInvitationState { UpdateInvitationState {
id: invitation.id, id: invitation.id,
state: InvitationState::Accepted, state: InvitationState::Accepted,
} }
.execute(conn)?; .execute(conn)?;
match { UpdateInvitationState {
Register { id: invitation.id,
name: invitation.name.clone(), state: InvitationState::Accepted,
email: invitation.email.clone(), }
project_id: Some(invitation.project_id), .execute(conn)?;
role: UserRole::User,
}
.execute(conn)
} {
Ok(_) => (),
Err(crate::DatabaseError::User(crate::UserError::InvalidPair(..))) => (),
Err(e) => return Err(e),
};
let user: User = LookupUser { match {
Register {
name: invitation.name.clone(), name: invitation.name.clone(),
email: invitation.email.clone(), email: invitation.email.clone(),
project_id: Some(invitation.project_id),
role: UserRole::User,
} }
.execute(conn)?; .execute(conn)
CreateBindToken { user_id: user.id }.execute(conn)?; } {
Ok(_) => (),
Err(crate::DatabaseError::User(crate::UserError::InvalidPair(..))) => (),
Err(e) => return Err(e),
};
crate::user_projects::CreateUserProject { let user: User = LookupUser {
user_id: user.id, name: invitation.name.clone(),
project_id: invitation.project_id, email: invitation.email.clone(),
is_current: false, }
is_default: false, .execute(conn)?;
role: invitation.role, CreateBindToken { user_id: user.id }.execute(conn)?;
}
.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>; type Result = Result<Token, crate::DatabaseError>;
fn handle(&mut self, msg: AcceptInvitation, _ctx: &mut Self::Context) -> Self::Result { 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)
} }
} }

View File

@ -1,6 +1,6 @@
use diesel::prelude::*;
use diesel::dsl::not;
use bitque_data::{IssueAssignee, IssueId, UserId}; use bitque_data::{IssueAssignee, IssueId, UserId};
use diesel::dsl::not;
use diesel::prelude::*;
use crate::{db_create, db_delete, db_load, db_load_field}; use crate::{db_create, db_delete, db_load, db_load_field};

View File

@ -1,5 +1,5 @@
use diesel::prelude::*;
use bitque_data::{IssueStatus, IssueStatusId, Position, ProjectId, TitleString}; use bitque_data::{IssueStatus, IssueStatusId, Position, ProjectId, TitleString};
use diesel::prelude::*;
use crate::{db_create, db_delete, db_load, db_update}; use crate::{db_create, db_delete, db_load, db_update};

View File

@ -1,11 +1,10 @@
use derive_db_execute::Execute; use bitque_data::{IssueId, IssuePriority, IssueStatusId, IssueType, ProjectId, UserId};
use diesel::dsl::sql; use diesel::dsl::sql;
use diesel::prelude::*; use diesel::prelude::*;
use bitque_data::{IssueId, IssuePriority, IssueStatusId, IssueType, ProjectId, UserId};
use crate::models::Issue; use crate::models::Issue;
#[derive(Default, Execute)] #[derive(derive_db_execute::Execute, Default)]
#[db_exec( #[db_exec(
result = "Issue", result = "Issue",
schema = "issues", schema = "issues",
@ -15,7 +14,7 @@ pub struct LoadIssue {
pub issue_id: IssueId, pub issue_id: IssueId,
} }
#[derive(Execute)] #[derive(derive_db_execute::Execute)]
#[db_exec( #[db_exec(
result = "Issue", result = "Issue",
schema = "issues", schema = "issues",
@ -25,7 +24,7 @@ pub struct LoadProjectIssues {
pub project_id: ProjectId, pub project_id: ProjectId,
} }
#[derive(Default, Execute)] #[derive(derive_db_execute::Execute, Default)]
#[db_exec(result = "Issue", schema = "issues")] #[db_exec(result = "Issue", schema = "issues")]
pub struct UpdateIssue { pub struct UpdateIssue {
pub issue_id: bitque_data::IssueId, pub issue_id: bitque_data::IssueId,
@ -46,7 +45,7 @@ pub struct UpdateIssue {
} }
impl 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; let msg = self;
use crate::schema::issues::dsl::*; use crate::schema::issues::dsl::*;
if let Some(user_ids) = msg.user_ids { if let Some(user_ids) = msg.user_ids {
@ -97,7 +96,7 @@ impl UpdateIssue {
} }
} }
#[derive(Execute)] #[derive(derive_db_execute::Execute)]
#[db_exec( #[db_exec(
result = "Issue", result = "Issue",
schema = "issues", schema = "issues",
@ -112,9 +111,9 @@ pub struct DeleteIssue {
} }
mod inner { mod inner {
use bitque_data::{IssuePriority, IssueStatusId, IssueType};
use derive_db_execute::Execute; use derive_db_execute::Execute;
use diesel::prelude::*; use diesel::prelude::*;
use bitque_data::{IssuePriority, IssueStatusId, IssueType};
use crate::models::Issue; use crate::models::Issue;
@ -159,7 +158,7 @@ mod inner {
} }
} }
#[derive(Execute)] #[derive(derive_db_execute::Execute)]
#[db_exec(result = "Issue", schema = "issues")] #[db_exec(result = "Issue", schema = "issues")]
pub struct CreateIssue { pub struct CreateIssue {
pub title: String, pub title: String,
@ -171,19 +170,21 @@ pub struct CreateIssue {
pub estimate: Option<i32>, pub estimate: Option<i32>,
pub time_spent: Option<i32>, pub time_spent: Option<i32>,
pub time_remaining: Option<i32>, pub time_remaining: Option<i32>,
pub project_id: bitque_data::ProjectId, pub project_id: ProjectId,
pub reporter_id: bitque_data::UserId, pub reporter_id: UserId,
pub user_ids: Vec<bitque_data::UserId>, pub user_ids: Vec<UserId>,
pub epic_id: Option<bitque_data::EpicId>, pub epic_id: Option<bitque_data::EpicId>,
} }
impl CreateIssue { 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::*; use crate::schema::issues::dsl::*;
let msg = self; let msg = self;
let pos = issues 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) .get_result::<i32>(conn)
.map_err(|e| { .map_err(|e| {
::tracing::error!("resolve new issue position failed {}", e); ::tracing::error!("resolve new issue position failed {}", e);

View File

@ -63,47 +63,3 @@ pub trait SyncQuery {
fn handle(&self, pool: &DbPool) -> Self::Result; 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)
}
}
}
}

View File

@ -1,5 +1,5 @@
use diesel::prelude::*;
use bitque_data::{BindToken, Message, MessageId, MessageType, User, UserId}; use bitque_data::{BindToken, Message, MessageId, MessageType, User, UserId};
use diesel::prelude::*;
use crate::users::{FindUser, LookupUser}; use crate::users::{FindUser, LookupUser};
use crate::{db_create, db_delete, db_load}; use crate::{db_create, db_delete, db_load};

View File

@ -1,8 +1,8 @@
use chrono::NaiveDateTime;
use bitque_data::{ use bitque_data::{
EpicId, InvitationState, IssuePriority, IssueStatusId, IssueType, ProjectCategory, ProjectId, EpicId, InvitationState, IssuePriority, IssueStatusId, IssueType, ProjectCategory, ProjectId,
TimeTracking, UserId, TimeTracking, UserId,
}; };
use chrono::NaiveDateTime;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::schema::*; use crate::schema::*;

View File

@ -1,13 +1,13 @@
#[macro_export] #[macro_export]
macro_rules! db_pool { macro_rules! db_pool {
($self: expr) => { ($self: expr) => {
&$self.pool.get().map_err(|e| { $self.pool.get().map_err(|e| {
::tracing::error!("{:?}", e); ::tracing::error!("{:?}", e);
$crate::DatabaseError::DatabaseConnectionLost $crate::DatabaseError::DatabaseConnectionLost
})? })?
}; };
($self: expr, $pool: expr) => { ($self: expr, $pool: expr) => {
&$pool.get().map_err(|e| { $pool.get().map_err(|e| {
::tracing::error!("{:?}", e); ::tracing::error!("{:?}", e);
$crate::DatabaseError::DatabaseConnectionLost $crate::DatabaseError::DatabaseConnectionLost
})? })?
@ -34,7 +34,7 @@ macro_rules! db_find {
} }
impl $action { 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::*; use crate::schema:: $schema ::dsl::*;
let $self = self; let $self = self;
$crate::q!($q) $crate::q!($q)
@ -57,8 +57,8 @@ macro_rules! db_find {
type Result = Result<$resource, $crate::DatabaseError>; type Result = Result<$resource, $crate::DatabaseError>;
fn handle(&mut self, msg: $action, _ctx: &mut Self::Context) -> Self::Result { 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)
} }
} }
}; };
@ -75,7 +75,7 @@ macro_rules! db_load {
} }
impl $action { 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::*; use crate::schema:: $schema ::dsl::*;
let $self = self; let $self = self;
$crate::q!($q) $crate::q!($q)
@ -98,9 +98,9 @@ macro_rules! db_load {
type Result = Result<Vec<$resource>, $crate::DatabaseError>; type Result = Result<Vec<$resource>, $crate::DatabaseError>;
fn handle(&mut self, msg: $action, _ctx: &mut Self::Context) -> Self::Result { 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 { 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::*; use crate::schema:: $schema ::dsl::*;
let $self = self; let $self = self;
$crate::q!($q) $crate::q!($q)
@ -137,9 +137,9 @@ macro_rules! db_load_field {
type Result = Result<Vec<$return_type>, $crate::DatabaseError>; type Result = Result<Vec<$return_type>, $crate::DatabaseError>;
fn handle(&mut self, msg: $action, _ctx: &mut Self::Context) -> Self::Result { 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),+) => { ($action: ident, $self: ident => $conn: ident => $schema: ident => $q: expr, $resource: ident, $($field: ident => $ty: ty),+) => {
pub struct $action { pub struct $action {
$(pub $field : $ty),+ $(pub $field : $ty),+
} }
impl $action { 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> {
crate::Guard::new($conn)?.run(|_guard| { let mut res = Err(crate::DatabaseError::DatabaseConnectionLost);
use crate::schema:: $schema ::dsl::*; conn.transaction(|conn| {
let $self = self; res = self.exec_with_transaction(conn);
$crate::q!($q) if res.is_err() {
.get_result::<$resource>($conn) Err(diesel::NotFound)
.map_err(|e| { } 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); ::tracing::error!("{:?}", e);
$crate::DatabaseError::GenericFailure( $crate::DatabaseError::GenericFailure(
$crate::OperationError::Create, $crate::OperationError::Create,
$crate::ResourceKind::$resource, $crate::ResourceKind::$resource,
) )
}) })
}) }
}
} }
impl actix::Message for $action { impl actix::Message for $action {
@ -180,9 +189,9 @@ macro_rules! db_create {
type Result = Result<$resource, $crate::DatabaseError>; type Result = Result<$resource, $crate::DatabaseError>;
fn handle(&mut self, msg: $action, _ctx: &mut Self::Context) -> Self::Result { 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 { 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::*; use crate::schema:: $schema ::dsl::*;
let $self = self; let $self = self;
$crate::q!($q) $crate::q!($q)
@ -222,9 +231,9 @@ macro_rules! db_update {
type Result = Result<$resource, $crate::DatabaseError>; type Result = Result<$resource, $crate::DatabaseError>;
fn handle(&mut self, msg: $action, _ctx: &mut Self::Context) -> Self::Result { 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 { 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::*; use $crate::schema:: $schema ::dsl::*;
let $self = self; let $self = self;
$crate::q!($q) $crate::q!($q)
@ -264,9 +273,9 @@ macro_rules! db_delete {
type Result = Result<usize, $crate::DatabaseError>; type Result = Result<usize, $crate::DatabaseError>;
fn handle(&mut self, msg: $action, _ctx: &mut Self::Context) -> Self::Result { 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)
} }
} }
}; };

View File

@ -1,5 +1,5 @@
use diesel::prelude::*;
use bitque_data::{NameString, Project, ProjectCategory, ProjectId, TimeTracking, UserId}; use bitque_data::{NameString, Project, ProjectCategory, ProjectId, TimeTracking, UserId};
use diesel::prelude::*;
use crate::{db_create, db_find, db_load, db_update}; use crate::{db_create, db_find, db_load, db_update};
@ -11,8 +11,8 @@ db_find! {
} }
mod inner { mod inner {
use diesel::prelude::*;
use bitque_data::{NameString, Project, ProjectCategory, TimeTracking}; use bitque_data::{NameString, Project, ProjectCategory, TimeTracking};
use diesel::prelude::*;
use crate::db_create; use crate::db_create;

View File

@ -40,13 +40,13 @@ diesel::table! {
id -> Int4, id -> Int4,
name -> Text, name -> Text,
email -> Text, email -> Text,
state -> InvitationState, state -> InvitationStateMapping,
project_id -> Int4, project_id -> Int4,
invited_by_id -> Int4, invited_by_id -> Int4,
created_at -> Timestamp, created_at -> Timestamp,
updated_at -> Timestamp, updated_at -> Timestamp,
bind_token -> Uuid, bind_token -> Uuid,
role -> UserRole, role -> UserRoleMapping,
} }
} }
@ -84,8 +84,8 @@ diesel::table! {
issues (id) { issues (id) {
id -> Int4, id -> Int4,
title -> Text, title -> Text,
issue_type -> IssueType, issue_type -> IssueTypeMapping,
priority -> IssuePriority, priority -> IssuePriorityMapping,
list_position -> Int4, list_position -> Int4,
description -> Nullable<Text>, description -> Nullable<Text>,
description_text -> Nullable<Text>, description_text -> Nullable<Text>,
@ -111,7 +111,7 @@ diesel::table! {
sender_id -> Int4, sender_id -> Int4,
summary -> Text, summary -> Text,
description -> Text, description -> Text,
message_type -> MessageType, message_type -> MessageTypeMapping,
hyper_link -> Text, hyper_link -> Text,
created_at -> Timestamp, created_at -> Timestamp,
updated_at -> Timestamp, updated_at -> Timestamp,
@ -127,10 +127,10 @@ diesel::table! {
name -> Text, name -> Text,
url -> Text, url -> Text,
description -> Text, description -> Text,
category -> ProjectCategory, category -> ProjectCategoryMapping,
created_at -> Timestamp, created_at -> Timestamp,
updated_at -> Timestamp, updated_at -> Timestamp,
time_tracking -> TimeTracking, time_tracking -> TimeTrackingMapping,
} }
} }
@ -159,7 +159,7 @@ diesel::table! {
project_id -> Int4, project_id -> Int4,
is_default -> Bool, is_default -> Bool,
is_current -> Bool, is_current -> Bool,
role -> UserRole, role -> UserRoleMapping,
created_at -> Timestamp, created_at -> Timestamp,
updated_at -> Timestamp, updated_at -> Timestamp,
} }
@ -172,7 +172,7 @@ diesel::table! {
user_settings (id) { user_settings (id) {
id -> Int4, id -> Int4,
user_id -> Int4, user_id -> Int4,
text_editor_mode -> TextEditorMode, text_editor_mode -> TextEditorModeMapping,
} }
} }

View File

@ -1,5 +1,5 @@
use diesel::prelude::*;
use bitque_data::{Token, UserId}; use bitque_data::{Token, UserId};
use diesel::prelude::*;
use crate::{db_create, db_find, db_update}; use crate::{db_create, db_find, db_update};

View File

@ -1,5 +1,5 @@
use diesel::prelude::*;
use bitque_data::{ProjectId, UserId, UserProject, UserProjectId, UserRole}; use bitque_data::{ProjectId, UserId, UserProject, UserProjectId, UserRole};
use diesel::prelude::*;
use crate::{db_create, db_delete, db_find, db_load, db_update}; use crate::{db_create, db_delete, db_find, db_load, db_update};
@ -26,8 +26,8 @@ db_load! {
} }
mod inner { mod inner {
use diesel::prelude::*;
use bitque_data::{UserId, UserProject, UserProjectId}; use bitque_data::{UserId, UserProject, UserProjectId};
use diesel::prelude::*;
use crate::db_update; use crate::db_update;

View File

@ -1,5 +1,5 @@
use diesel::prelude::*;
use bitque_data::{TextEditorMode, UserId, UserSetting}; use bitque_data::{TextEditorMode, UserId, UserSetting};
use diesel::prelude::*;
use crate::{db_find, db_update}; use crate::{db_find, db_update};
@ -29,8 +29,8 @@ db_update! {
} }
mod inner { mod inner {
use diesel::prelude::*;
use bitque_data::{TextEditorMode, UserId, UserSetting}; use bitque_data::{TextEditorMode, UserId, UserSetting};
use diesel::prelude::*;
use crate::{db_create, db_update}; use crate::{db_create, db_update};

View File

@ -1,5 +1,5 @@
use diesel::prelude::*;
use bitque_data::{EmailString, IssueId, ProjectId, User, UserId, UserRole, UsernameString}; use bitque_data::{EmailString, IssueId, ProjectId, User, UserId, UserRole, UsernameString};
use diesel::prelude::*;
use crate::projects::CreateProject; use crate::projects::CreateProject;
use crate::user_projects::CreateUserProject; use crate::user_projects::CreateUserProject;
@ -120,7 +120,7 @@ db_load! {
user_id => UserId 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; use crate::schema::users::dsl;
q!(dsl::users q!(dsl::users
@ -153,7 +153,6 @@ db_update! {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use diesel::connection::TransactionManager;
use bitque_data::{Project, ProjectCategory}; use bitque_data::{Project, ProjectCategory};
use super::*; use super::*;
@ -166,11 +165,9 @@ mod tests {
use crate::schema::users::dsl::users; use crate::schema::users::dsl::users;
let pool = build_pool(); let pool = build_pool();
let conn = &pool.get().unwrap(); let mut conn = pool.get().unwrap();
let conn = &mut conn;
let tm = conn.transaction_manager(); conn.begin_test_transaction().unwrap();
tm.begin_transaction(conn).unwrap();
diesel::delete(user_projects).execute(conn).unwrap(); diesel::delete(user_projects).execute(conn).unwrap();
diesel::delete(users).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 res2 = count_matching_users("Bar", "foo@example.com", conn);
let res3 = count_matching_users("Foo", "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!(res1, 1);
assert_eq!(res2, 1); assert_eq!(res2, 1);
assert_eq!(res3, 1); assert_eq!(res3, 1);

View File

@ -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 struct Issue {
/// pub id: i32, /// pub id: i32,
/// pub name: String, /// pub name: String,
@ -53,7 +56,7 @@ fn parse_meta(mut it: Peekable<IntoIter>) -> (Peekable<IntoIter>, Option<Attribu
/// pub struct LoadAll; /// pub struct LoadAll;
/// ///
/// #[derive(Execute)] /// #[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 struct DeleteOne {
/// pub id: i32 /// pub id: i32
/// } /// }
@ -124,9 +127,9 @@ pub fn derive_enum_iter(item: TokenStream) -> TokenStream {
type Result = Result<{action_result}, crate::DatabaseError>; type Result = Result<{action_result}, crate::DatabaseError>;
fn handle(&mut self, msg: {name}, _ctx: &mut Self::Context) -> Self::Result {{ 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} {{ impl {name} {{
pub fn execute( pub fn execute(
self, self,
conn: &crate::DbPooledConn, conn: &mut crate::DbPooledConn,
) -> Result<{action_result}, crate::DatabaseError> {{ ) -> Result<{action_result}, crate::DatabaseError> {{
crate::Guard::new(conn)?.run(|_guard| {{ conn.transaction(|conn| {{
use crate::schema::{schema}::dsl::*; use crate::schema::{schema}::dsl::*;
let msg = self; let msg = self;
crate::q!({query}).get_result(conn).map_err(|e| {{ crate::q!({query}).get_result(conn)
::tracing::error!("{{:?}}", e); }}).map_err(|e| {{
crate::DatabaseError::GenericFailure( ::tracing::error!("{{:?}}", e);
crate::OperationError::Create, crate::DatabaseError::GenericFailure(
crate::ResourceKind::{resource}, crate::OperationError::Create,
) crate::ResourceKind::{resource},
}}) )
}}) }})
}} }}
}} }}
@ -187,7 +190,7 @@ fn build_find_exec(
impl {name} {{ impl {name} {{
pub fn execute( pub fn execute(
self, self,
conn: &crate::DbPooledConn, conn: &mut crate::DbPooledConn,
) -> Result<{action_result}, crate::DatabaseError> {{ ) -> Result<{action_result}, crate::DatabaseError> {{
use crate::schema::{schema}::dsl::*; use crate::schema::{schema}::dsl::*;
let msg = self; let msg = self;
@ -221,7 +224,7 @@ fn build_load_exec(
impl {name} {{ impl {name} {{
pub fn execute( pub fn execute(
self, self,
conn: &crate::DbPooledConn, conn: &mut crate::DbPooledConn,
) -> Result<{action_result}, crate::DatabaseError> {{ ) -> Result<{action_result}, crate::DatabaseError> {{
use crate::schema::{schema}::dsl::*; use crate::schema::{schema}::dsl::*;
let msg = self; let msg = self;
@ -255,7 +258,7 @@ fn build_update_exec(
impl {name} {{ impl {name} {{
pub fn execute( pub fn execute(
self, self,
conn: &crate::DbPooledConn, conn: &mut crate::DbPooledConn,
) -> Result<{action_result}, crate::DatabaseError> {{ ) -> Result<{action_result}, crate::DatabaseError> {{
use crate::schema::{schema}::dsl::*; use crate::schema::{schema}::dsl::*;
let msg = self; let msg = self;
@ -289,7 +292,7 @@ fn build_destroy_exec(
impl {name} {{ impl {name} {{
pub fn execute( pub fn execute(
self, self,
conn: &crate::DbPooledConn, conn: &mut crate::DbPooledConn,
) -> Result<{action_result}, crate::DatabaseError> {{ ) -> Result<{action_result}, crate::DatabaseError> {{
use crate::schema::{schema}::dsl::*; use crate::schema::{schema}::dsl::*;
let msg = self; let msg = self;

View File

@ -27,7 +27,7 @@ fn consume_ident(mut it: Peekable<IntoIter>, name: &str) -> Peekable<IntoIter> {
it 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 let name = it
.next() .next()
.expect("Expect to struct name but nothing was found"); .expect("Expect to struct name but nothing was found");

View File

@ -1,16 +1,26 @@
[package] [package]
name = "derive_enum_sql" name = "diesel-derive-enum"
version = "0.1.0" version = "2.0.1"
authors = ["Adrian Wozniak <adrian.wozniak@ita-prog.pl>"] description = "Derive diesel boilerplate for using enums in databases"
edition = "2018" authors = ["Alex Whitney <adwhit@fastmail.com>"]
description = "JIRS (Simplified JIRA in Rust) shared data types" repository = "http://github.com/adwhit/diesel-derive-enum"
repository = "https://gitlab.com/adrian.wozniak/bitque" homepage = "http://github.com/adwhit/diesel-derive-enum"
license = "MPL-2.0" keywords = ["diesel", "postgres", "sqlite", "mysql", "sql"]
#license-file = "../LICENSE" license = "MIT OR Apache-2.0"
readme = "README.md"
[lib] edition = "2021"
name = "derive_enum_sql"
path = "./src/lib.rs"
proc-macro = true
[dependencies] [dependencies]
quote = "1"
syn = "1"
heck = "0.4.0"
proc-macro2 = "1"
[features]
postgres = []
sqlite = []
mysql = []
[lib]
name = "diesel_derive_enum"
proc-macro = true

View File

@ -1,155 +1,500 @@
#![recursion_limit = "1024"]
extern crate proc_macro; 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 { /// Implement the traits necessary for inserting the enum directly into a
let mut lower = String::new(); /// database
for (idx, c) in s.chars().enumerate() { ///
if idx > 0 && c.is_uppercase() { /// # Attributes
lower.push('_'); ///
} /// ## Type attributes
lower.push_str(c.to_lowercase().to_string().as_str()); ///
} /// * `#[ExistingTypePath = "crate::schema::sql_types::NewEnum"]` specifies the
lower /// 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 existing_mapping_path = val_from_attrs(&input.attrs, "ExistingTypePath");
let mut code = format!( if !cfg!(feature = "postgres") && existing_mapping_path.is_some() {
r#" panic!("ExistingTypePath attribute only applies when the 'postgres' feature is enabled");
#[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(),
);
} }
code.push_str(format!(" _ => Ok({name}::default()),", name = name).as_str()); // we could allow a default value here but... I'm not very keen
code.push_str(" }\n }\n}"); // let existing_mapping_path = existing_mapping_path
code.push_str( // .unwrap_or_else(|| format!("crate::schema::sql_types::{}", input.ident));
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)
}}
}}
#[cfg(feature = "backend")] let pg_internal_type = val_from_attrs(&input.attrs, "PgType");
impl diesel::deserialize::FromSql<diesel::sql_types::Text, diesel::pg::Pg> for {name} {{
fn from_sql(bytes: Option<&[u8]>) -> deserialize::Result<Self> {{ if existing_mapping_path.is_some() && pg_internal_type.is_some() {
{name}::from_diesel_bytes(bytes) panic!("Cannot specify both `ExistingTypePath` and `PgType` attributes");
}} }
}}
"#, let pg_internal_type = pg_internal_type.unwrap_or(input.ident.to_string().to_snake_case());
name = name
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(), } else {
); syn::Error::new(
code Span::call_site(),
"derive(DbEnum) can only be applied to enums",
)
.to_compile_error()
.into()
}
} }
#[proc_macro_derive(EnumSql)] fn val_from_attrs(attrs: &[Attribute], attr_name: &str) -> Option<String> {
pub fn derive_enum_sql(item: TokenStream) -> TokenStream { for attr in attrs {
let mut it = item.into_iter().peekable(); if attr.path.is_ident(attr_name) {
while let Some(token) = it.peek() { match attr.parse_meta().ok()? {
if let TokenTree::Ident(_) = token { Meta::NameValue(MetaNameValue {
break; lit: Lit::Str(lit_str),
} else { ..
it.next(); }) => return Some(lit_str.value()),
} _ => panic!(
} "Attribute '{}' must have form: {} = \"value\"",
if let Some(TokenTree::Ident(ident)) = it.next() { attr_name, attr_name
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") None
} }
if let Some(TokenTree::Ident(ident)) = it.next() {
if ident.to_string().as_str() != "enum" { /// Defines the casing for the database representation. Follows serde naming
panic!("Expect to find keyword struct but was found {:?}", ident) /// convention.
} #[derive(Copy, Clone, Debug, PartialEq)]
} else { enum CaseStyle {
panic!("Expect to find keyword struct but nothing was found") Camel,
} Kebab,
let name = it Pascal,
.next() Upper,
.expect("Expect to struct name but nothing was found") ScreamingSnake,
.to_string(); Snake,
Verbatim,
let mut variants = vec![]; }
if let Some(TokenTree::Group(group)) = it.next() {
for token in group.stream() { impl CaseStyle {
if let TokenTree::Ident(ident) = token { fn from_string(name: &str) -> Self {
variants.push(ident.to_string()) 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(&quote! { #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(
&quote! { #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()
} }

View File

@ -17,6 +17,5 @@ actix = { version = "0.13.0" }
actix-files = { version = "0.6.2" } actix-files = { version = "0.6.2" }
bitque-config = { workspace = true, features = ["local-storage"] } bitque-config = { workspace = true, features = ["local-storage"] }
bytes = { version = "1.4.0" } bytes = { version = "1.4.0" }
common = { workspace = true }
futures = { version = "0.3.8" } futures = { version = "0.3.8" }
tokio = { version = "1", features = ["full"] } tokio = { version = "1", features = ["full"] }

View File

@ -17,7 +17,6 @@ actix = { version = "0.13.0" }
bincode = { version = "*" } bincode = { version = "*" }
bitque-config = { workspace = true, features = ["hi"] } bitque-config = { workspace = true, features = ["hi"] }
bitque-data = { workspace = true, features = ["backend"] } bitque-data = { workspace = true, features = ["backend"] }
common = { workspace = true }
flate2 = { version = "*" } flate2 = { version = "*" }
lazy_static = { version = "*" } lazy_static = { version = "*" }
serde = { version = "*" } serde = { version = "*" }

View File

@ -82,9 +82,11 @@ impl HighlightActor {
let mut res = Vec::with_capacity(code.split_ascii_whitespace().count()); let mut res = Vec::with_capacity(code.split_ascii_whitespace().count());
for line in code.lines() { for line in code.lines() {
res.extend(hi.highlight_line(line, self.syntax_set.as_ref()).map_err(|_e| { res.extend(
HighlightError::UnknownLanguage hi.highlight_line(line, self.syntax_set.as_ref())
})?.iter()); .map_err(|_e| HighlightError::UnknownLanguage)?
.iter(),
);
} }
Ok(res) Ok(res)
} }

View File

@ -15,7 +15,6 @@ path = "./src/lib.rs"
[dependencies] [dependencies]
actix = { version = "0.13.0" } actix = { version = "0.13.0" }
bitque-config = { workspace = true, features = ["mail", "web"] } bitque-config = { workspace = true, features = ["mail", "web"] }
common = { workspace = true }
dotenv = { version = "*" } dotenv = { version = "*" }
futures = { version = "*" } futures = { version = "*" }
lettre = { version = "0.10.0-rc.3" } lettre = { version = "0.10.0-rc.3" }

View File

@ -20,11 +20,13 @@ default = ["local-storage"]
[dependencies] [dependencies]
actix = { version = "0.13.0" } actix = { version = "0.13.0" }
actix-multipart = { version = "*" } actix-multipart = { version = "*" }
actix-web = { version = "4" }
actix-web-actors = { version = "4" }
amazon-actor = { workspace = true, optional = true } amazon-actor = { workspace = true, optional = true }
bincode = { version = "*" } bincode = { version = "*" }
bitque-config = { workspace = true, features = ["mail", "web", "local-storage"] } bitque-config = { workspace = true, features = ["mail", "web", "local-storage"] }
bitque-data = { workspace = true, features = ["backend"] } bitque-data = { workspace = true, features = ["backend"] }
common = { workspace = true } bytes = { version = "1" }
database-actor = { workspace = true } database-actor = { workspace = true }
filesystem-actor = { workspace = true, optional = true } filesystem-actor = { workspace = true, optional = true }
futures = { version = "0.3.8" } futures = { version = "0.3.8" }
@ -34,5 +36,6 @@ openssl-sys = { version = "*", features = ["vendored"] }
serde = { version = "*" } serde = { version = "*" }
tokio = { version = "1", features = ["full"] } tokio = { version = "1", features = ["full"] }
toml = { version = "*" } toml = { version = "*" }
tracing = { version = "0.1.37" }
uuid = { version = "1.3.0", features = ["serde", "v4", "v5"] } uuid = { version = "1.3.0", features = ["serde", "v4", "v5"] }
websocket-actor = { workspace = true } websocket-actor = { workspace = true }

View File

@ -2,10 +2,10 @@ use std::io::Write;
use actix::Addr; use actix::Addr;
use actix_multipart::{Field, Multipart}; use actix_multipart::{Field, Multipart};
use actix_web::http::header::ContentDisposition;
use actix_web::web::Data; use actix_web::web::Data;
use actix_web::{post, web, Error, HttpResponse}; 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::authorize_user::AuthorizeUser;
use database_actor::user_projects::CurrentUserProject; use database_actor::user_projects::CurrentUserProject;
use database_actor::users::UpdateAvatarUrl; use database_actor::users::UpdateAvatarUrl;
@ -13,11 +13,12 @@ use database_actor::DbExecutor;
#[cfg(feature = "local-storage")] #[cfg(feature = "local-storage")]
use futures::executor::block_on; use futures::executor::block_on;
use futures::{StreamExt, TryStreamExt}; use futures::{StreamExt, TryStreamExt};
use bitque_data::msg::{WsMsg, WsMsgUser}; use tracing::error;
use bitque_data::{User, UserId};
use websocket_actor::server::InnerMsg::BroadcastToChannel; use websocket_actor::server::InnerMsg::BroadcastToChannel;
use websocket_actor::server::WsServer; use websocket_actor::server::WsServer;
use crate::ServiceError;
#[cfg(feature = "aws-s3")] #[cfg(feature = "aws-s3")]
#[post("/")] #[post("/")]
pub async fn upload( pub async fn upload(
@ -31,10 +32,7 @@ pub async fn upload(
let mut avatar_url: Option<String> = None; let mut avatar_url: Option<String> = None;
while let Ok(Some(field)) = payload.try_next().await { while let Ok(Some(field)) = payload.try_next().await {
let disposition: ContentDisposition = match field.content_disposition() { let disposition = field.content_disposition();
Some(d) => d,
_ => continue,
};
if !disposition.is_form_data() { if !disposition.is_form_data() {
return Ok(HttpResponse::BadRequest().finish()); return Ok(HttpResponse::BadRequest().finish());
} }
@ -48,7 +46,7 @@ pub async fn upload(
crate::handlers::upload_avatar_image::handle_image( crate::handlers::upload_avatar_image::handle_image(
id, id,
field, field,
disposition, disposition.clone(),
fs.clone(), fs.clone(),
amazon.clone(), amazon.clone(),
) )
@ -95,10 +93,7 @@ pub async fn upload(
let mut avatar_url: Option<String> = None; let mut avatar_url: Option<String> = None;
while let Ok(Some(field)) = payload.try_next().await { while let Ok(Some(field)) = payload.try_next().await {
let disposition: ContentDisposition = match field.content_disposition() { let disposition = field.content_disposition();
Some(d) => d,
_ => continue,
};
if !disposition.is_form_data() { if !disposition.is_form_data() {
return Ok(HttpResponse::BadRequest().finish()); return Ok(HttpResponse::BadRequest().finish());
} }
@ -107,15 +102,10 @@ pub async fn upload(
user_id = Some(handle_token(field, db.clone()).await?); user_id = Some(handle_token(field, db.clone()).await?);
} }
Some("avatar") => { 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( avatar_url = Some(
crate::handlers::upload_avatar_image::handle_image( crate::handlers::upload_avatar_image::handle_image(id, field, fs.clone())
id, .await?,
field,
disposition,
fs.clone(),
)
.await?,
); );
} }
_ => continue, _ => continue,
@ -134,12 +124,16 @@ pub async fn upload(
match (user_id, avatar_url) { match (user_id, avatar_url) {
(user_id, Some(avatar_url)) => { (user_id, Some(avatar_url)) => {
let user = update_user_avatar(user_id, avatar_url.clone(), db).await?; let user = update_user_avatar(user_id, avatar_url.clone(), db).await?;
ws.send(BroadcastToChannel( if ws
project_id, .send(BroadcastToChannel(
WsMsg::User(WsMsgUser::AvatarUrlChanged(user.id, avatar_url)), project_id,
)) WsMsg::User(WsMsgUser::AvatarUrlChanged(user.id, avatar_url)),
.await ))
.map_err(|_| HttpResponse::UnprocessableEntity().finish())?; .await
.is_err()
{
return Ok(HttpResponse::UnprocessableEntity().finish());
};
Ok(HttpResponse::NoContent().finish()) Ok(HttpResponse::NoContent().finish())
} }
_ => Ok(HttpResponse::UnprocessableEntity().finish()), _ => Ok(HttpResponse::UnprocessableEntity().finish()),
@ -162,42 +156,41 @@ async fn update_user_avatar(
Ok(Err(e)) => { Ok(Err(e)) => {
::tracing::error!("{:?}", e); ::tracing::error!("{:?}", e);
Err(actix_web::Error::from( Err(ServiceError::Unauthorized.into())
HttpResponse::Unauthorized().finish(),
))
} }
Err(e) => { Err(e) => {
::tracing::error!("{:?}", e); ::tracing::error!("{:?}", e);
Err(actix_web::Error::from( Err(ServiceError::Unauthorized.into())
HttpResponse::Unauthorized().finish(),
))
} }
} }
} }
async fn handle_token( async fn handle_token(mut field: Field, db: Data<Addr<DbExecutor>>) -> Result<UserId, Error> {
mut field: Field,
db: Data<Addr<DbExecutor>>,
) -> Result<UserId, actix_web::Error> {
let mut f: Vec<u8> = vec![]; let mut f: Vec<u8> = vec![];
while let Some(chunk) = field.next().await { while let Some(chunk) = field.next().await {
let data = chunk.unwrap(); 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) let access_token = String::from_utf8(f)
.unwrap_or_default() .unwrap_or_default()
.parse::<uuid::Uuid>() .parse::<uuid::Uuid>()
.map_err(|_| HttpResponse::Unauthorized().finish())?; .map_err(|_| ServiceError::Unauthorized)?;
match db.send(AuthorizeUser { access_token }).await { match db.send(AuthorizeUser { access_token }).await {
Ok(Ok(user)) => Ok(user.id), Ok(Ok(user)) => Ok(user.id),
Ok(Err(e)) => { Ok(Err(e)) => {
::tracing::error!("{:?}", e); ::tracing::error!("{:?}", e);
Err(HttpResponse::Unauthorized().finish().into()) Err(ServiceError::Unauthorized.into())
} }
Err(e) => { Err(e) => {
::tracing::error!("{:?}", e); ::tracing::error!("{:?}", e);
Err(HttpResponse::Unauthorized().finish().into()) Err(ServiceError::Unauthorized.into())
} }
} }
} }

View File

@ -1,19 +1,21 @@
use actix_web::HttpResponse; use std::fmt::{Display, Formatter};
use common::*;
use actix_web::body::BoxBody;
use actix_web::{HttpResponse, ResponseError};
use bitque_data::msg::WsError; use bitque_data::msg::WsError;
use bitque_data::ErrorResponse; use bitque_data::ErrorResponse;
const TOKEN_NOT_FOUND: &str = "Token not found"; const TOKEN_NOT_FOUND: &str = "Token not found";
const DATABASE_CONNECTION_FAILED: &str = "Database connection failed"; const DATABASE_CONNECTION_FAILED: &str = "Database connection failed";
#[derive(Debug)] #[derive(Debug, Copy, Clone)]
pub enum HighlightError { pub enum HighlightError {
UnknownLanguage, UnknownLanguage,
UnknownTheme, UnknownTheme,
ResultUnserializable, ResultUnserializable,
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub enum ServiceError { pub enum ServiceError {
Unauthorized, Unauthorized,
DatabaseConnectionLost, 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 { impl Into<HttpResponse> for ServiceError {
fn into(self) -> HttpResponse { fn into(self) -> HttpResponse {
match self { match self {

View File

@ -1,22 +1,20 @@
use actix::Addr; use actix::Addr;
use actix_multipart::Field; use actix_multipart::Field;
use actix_web::http::header::ContentDisposition;
use actix_web::web::Data; use actix_web::web::Data;
use actix_web::Error; use actix_web::Error;
use common::*;
use futures::StreamExt;
use bitque_data::UserId; use bitque_data::UserId;
use futures::StreamExt;
use tokio::sync::broadcast::{Receiver, Sender}; use tokio::sync::broadcast::{Receiver, Sender};
use tracing::error;
#[cfg(all(feature = "local-storage", feature = "aws-s3"))] #[cfg(all(feature = "local-storage", feature = "aws-s3"))]
pub(crate) async fn handle_image( pub(crate) async fn handle_image(
user_id: UserId, user_id: UserId,
mut field: Field, mut field: Field,
disposition: ContentDisposition,
fs: Data<Addr<filesystem_actor::FileSystemExecutor>>, fs: Data<Addr<filesystem_actor::FileSystemExecutor>>,
amazon: Data<Addr<amazon_actor::AmazonExecutor>>, amazon: Data<Addr<amazon_actor::AmazonExecutor>>,
) -> Result<String, Error> { ) -> 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 system_file_name = format!("{}-{}", user_id, filename);
let (sender, receiver) = tokio::sync::broadcast::channel(64); let (sender, receiver) = tokio::sync::broadcast::channel(64);
@ -46,10 +44,9 @@ pub(crate) async fn handle_image(
pub(crate) async fn handle_image( pub(crate) async fn handle_image(
user_id: UserId, user_id: UserId,
mut field: Field, mut field: Field,
disposition: ContentDisposition,
amazon: Data<Addr<amazon_actor::AmazonExecutor>>, amazon: Data<Addr<amazon_actor::AmazonExecutor>>,
) -> Result<String, Error> { ) -> 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 system_file_name = format!("{}-{}", user_id, filename);
let (sender, receiver) = tokio::sync::broadcast::channel(64); let (sender, receiver) = tokio::sync::broadcast::channel(64);
@ -73,10 +70,9 @@ pub(crate) async fn handle_image(
pub(crate) async fn handle_image( pub(crate) async fn handle_image(
user_id: UserId, user_id: UserId,
mut field: Field, mut field: Field,
disposition: ContentDisposition,
fs: Data<Addr<filesystem_actor::FileSystemExecutor>>, fs: Data<Addr<filesystem_actor::FileSystemExecutor>>,
) -> Result<String, Error> { ) -> 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 system_file_name = format!("{}-{}", user_id, filename);
let (sender, _receiver) = tokio::sync::broadcast::channel(64); let (sender, _receiver) = tokio::sync::broadcast::channel(64);
@ -97,11 +93,11 @@ pub(crate) async fn handle_image(
} }
/// Read file from client /// 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 { while let Some(chunk) = field.next().await {
let data = chunk.unwrap(); let data = chunk.unwrap();
if let Err(err) = sender.send(data) { if let Err(err) = sender.send(data) {
log::error!("{:?}", err); error!("{:?}", err);
} }
} }
} }

View File

@ -1,11 +1,12 @@
extern crate core;
use actix::Addr; use actix::Addr;
use actix_web::web::Data; use actix_web::web::Data;
use actix_web::{HttpRequest, HttpResponse}; use actix_web::{HttpRequest, HttpResponse};
use common::*; use bitque_data::User;
use database_actor::authorize_user::AuthorizeUser; use database_actor::authorize_user::AuthorizeUser;
use database_actor::DbExecutor; use database_actor::DbExecutor;
pub use errors::*; pub use errors::*;
use bitque_data::User;
use crate::middleware::authorize::token_from_headers; use crate::middleware::authorize::token_from_headers;

View File

@ -1,10 +1,6 @@
use actix_web::http::header::{self}; use actix_web::http::header::{self, HeaderMap};
use actix_web::http::HeaderMap;
use common::*;
pub fn token_from_headers( pub fn token_from_headers(headers: &HeaderMap) -> Result<uuid::Uuid, crate::errors::ServiceError> {
headers: &HeaderMap,
) -> std::result::Result<uuid::Uuid, crate::errors::ServiceError> {
headers headers
.get(header::AUTHORIZATION) .get(header::AUTHORIZATION)
.ok_or(crate::errors::ServiceError::Unauthorized) .ok_or(crate::errors::ServiceError::Unauthorized)

View File

@ -1 +0,0 @@
../.env

View File

@ -27,8 +27,8 @@ derive_enum_primitive = { workspace = true }
dotenv = { version = "*" } dotenv = { version = "*" }
futures = "0.3.6" futures = "0.3.6"
js-sys = { version = "*", default-features = false } js-sys = { version = "*", default-features = false }
seed = { version = "0.10.0" } seed = { version = "0" }
serde = { version = "*" } serde = { version = "1", features = [] }
serde_json = { version = "*" } serde_json = { version = "*" }
tracing = { version = "0.1.37" } tracing = { version = "0.1.37" }
uuid = { version = "1.3.0", features = ["serde"] } uuid = { version = "1.3.0", features = ["serde"] }

View File

@ -1 +0,0 @@
../LICENSE

View File

@ -1,5 +1,4 @@
use bitque_data::{EpicId, IssueStatusId, WsMsg}; use bitque_data::{EpicId, IssueStatusId, WsMsg};
use seed::prelude::WebSocketMessage;
use crate::components::styled_md_editor::MdEditorMode as TabMode; use crate::components::styled_md_editor::MdEditorMode as TabMode;
use crate::FieldId; use crate::FieldId;

View File

@ -1,3 +1,4 @@
mod events;
pub mod styled_avatar; pub mod styled_avatar;
pub mod styled_button; pub mod styled_button;
pub mod styled_checkbox; pub mod styled_checkbox;
@ -18,4 +19,3 @@ pub mod styled_select_child;
pub mod styled_textarea; pub mod styled_textarea;
pub mod styled_tip; pub mod styled_tip;
pub mod styled_tooltip; pub mod styled_tooltip;
mod events;

View File

@ -1,5 +1,5 @@
use seed::*;
use seed::prelude::*; use seed::prelude::*;
use seed::*;
use web_sys::File; use web_sys::File;
use crate::{FieldId, Msg}; use crate::{FieldId, Msg};

View File

@ -1,5 +1,5 @@
use seed::*;
use seed::prelude::*; use seed::prelude::*;
use seed::*;
use crate::Msg; use crate::Msg;

View File

@ -1,5 +1,5 @@
use seed::*;
use seed::prelude::*; use seed::prelude::*;
use seed::*;
use crate::components::styled_icon::{Icon, StyledIcon}; use crate::components::styled_icon::{Icon, StyledIcon};
use crate::Msg; use crate::Msg;

View File

@ -1,11 +1,11 @@
#![feature(type_ascription, trait_alias, drain_filter)] #![feature(type_ascription, trait_alias, drain_filter)]
use bitque_data::msg::WsMsgSession;
use bitque_data::*;
pub use changes::*; pub use changes::*;
pub use components::*; pub use components::*;
pub use fields::*; pub use fields::*;
pub use images::*; pub use images::*;
use bitque_data::msg::WsMsgSession;
use bitque_data::*;
use seed::prelude::*; use seed::prelude::*;
use web_sys::File; use web_sys::File;

View File

@ -1,6 +1,6 @@
use bitque_data::{IssueFieldId, IssuePriority};
use derive_enum_iter::EnumIter; use derive_enum_iter::EnumIter;
use derive_enum_primitive::EnumPrimitive; use derive_enum_primitive::EnumPrimitive;
use bitque_data::{IssueFieldId, IssuePriority};
use seed::prelude::*; use seed::prelude::*;
use crate::components::styled_date_time_input::*; use crate::components::styled_date_time_input::*;

View File

@ -1,8 +1,8 @@
use comments::*;
use bitque_data::{ use bitque_data::{
CommentFieldId, IssueFieldId, IssuePriority, IssueStatus, IssueType, TimeTracking, CommentFieldId, IssueFieldId, IssuePriority, IssueStatus, IssueType, TimeTracking,
UpdateIssuePayload, User, UpdateIssuePayload, User,
}; };
use comments::*;
use seed::prelude::*; use seed::prelude::*;
use seed::*; use seed::*;

View File

@ -1,5 +1,5 @@
use chrono::NaiveDateTime;
use bitque_data::{Issue, IssueStatus}; use bitque_data::{Issue, IssueStatus};
use chrono::NaiveDateTime;
use seed::prelude::*; use seed::prelude::*;
use seed::*; use seed::*;

View File

@ -1,7 +1,6 @@
use seed::*;
use seed::prelude::*;
use bitque_data::{Issue, IssueId}; use bitque_data::{Issue, IssueId};
use seed::prelude::*;
use seed::*;
use crate::components::styled_icon::*; use crate::components::styled_icon::*;
use crate::components::styled_link::*; use crate::components::styled_link::*;

View File

@ -1,7 +1,7 @@
use std::collections::HashMap; use std::collections::HashMap;
use chrono::NaiveDateTime;
use bitque_data::*; use bitque_data::*;
use chrono::NaiveDateTime;
use crate::shared::drag::DragState; use crate::shared::drag::DragState;

View File

@ -1,14 +1,13 @@
use seed::*;
use seed::prelude::*;
use bitque_data::*; use bitque_data::*;
use seed::prelude::*;
use seed::*;
use crate::{match_page, Model, Msg};
use crate::components::styled_avatar::*; use crate::components::styled_avatar::*;
use crate::components::styled_button::{ButtonVariant, StyledButton}; use crate::components::styled_button::{ButtonVariant, StyledButton};
use crate::components::styled_icon::*; use crate::components::styled_icon::*;
use crate::model::PageContent; use crate::model::PageContent;
use crate::pages::project_page::{events, StatusIssueIds}; use crate::pages::project_page::{events, StatusIssueIds};
use crate::{match_page, Model, Msg};
#[inline(always)] #[inline(always)]
pub fn project_board_lists(model: &Model) -> Node<Msg> { pub fn project_board_lists(model: &Model) -> Node<Msg> {

View File

@ -1,7 +1,7 @@
use std::collections::HashMap; use std::collections::HashMap;
use chrono::Datelike;
use bitque_data::Issue; use bitque_data::Issue;
use chrono::Datelike;
use seed::prelude::*; use seed::prelude::*;
use seed::*; use seed::*;

View File

@ -1,11 +1,11 @@
use std::collections::HashMap; use std::collections::HashMap;
pub use init_load_sets::*;
use bitque_data::msg::{ use bitque_data::msg::{
WsError, WsMsgComment, WsMsgEpic, WsMsgIssue, WsMsgIssueStatus, WsMsgMessage, WsMsgProject, WsError, WsMsgComment, WsMsgEpic, WsMsgIssue, WsMsgIssueStatus, WsMsgMessage, WsMsgProject,
WsMsgSession, WsMsgUser, WsMsgSession, WsMsgUser,
}; };
use bitque_data::*; use bitque_data::*;
pub use init_load_sets::*;
use seed::prelude::*; use seed::prelude::*;
use crate::model::*; use crate::model::*;

View File

@ -14,11 +14,12 @@ path = "./src/lib.rs"
[dependencies] [dependencies]
actix = { version = "0.13.0" } actix = { version = "0.13.0" }
actix-web = { version = "4" }
actix-web-actors = { version = "4" }
async-trait = { version = "*" } async-trait = { version = "*" }
bincode = { version = "*" } bincode = { version = "*" }
bitque-config = { workspace = true, features = ["websocket"] } bitque-config = { workspace = true, features = ["websocket"] }
bitque-data = { workspace = true, features = ["backend"] } bitque-data = { workspace = true, features = ["backend"] }
common = { workspace = true }
comrak = { version = "*" } comrak = { version = "*" }
database-actor = { workspace = true } database-actor = { workspace = true }
flate2 = { version = "*" } flate2 = { version = "*" }
@ -31,4 +32,5 @@ openssl-sys = { version = "*", features = ["vendored"] }
serde = { version = "*" } serde = { version = "*" }
syntect = { version = "*" } syntect = { version = "*" }
toml = { version = "*" } toml = { version = "*" }
tracing = { version = "0.1.37" }
uuid = { version = "1.3.0", features = ["serde", "v4", "v5"] } uuid = { version = "1.3.0", features = ["serde", "v4", "v5"] }

View File

@ -1,10 +1,10 @@
use actix::AsyncContext; use actix::AsyncContext;
use bitque_data::msg::{WsError, WsMsgSession};
use bitque_data::{Token, WsMsg};
use database_actor::authorize_user::AuthorizeUser; use database_actor::authorize_user::AuthorizeUser;
use database_actor::tokens::{CreateBindToken, FindBindToken}; use database_actor::tokens::{CreateBindToken, FindBindToken};
use database_actor::users::LookupUser; use database_actor::users::LookupUser;
use futures::executor::block_on; use futures::executor::block_on;
use bitque_data::msg::{WsError, WsMsgSession};
use bitque_data::{Token, WsMsg};
use mail_actor::welcome::Welcome; use mail_actor::welcome::Welcome;
use crate::server::InnerMsg; use crate::server::InnerMsg;

View File

@ -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::msg::{WsMsgInvitation, WsMsgMessage};
use bitque_data::{ use bitque_data::{
EmailString, InvitationId, InvitationToken, MessageType, UserRole, UsernameString, WsMsg, 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::handlers::{LoadInvitedUsers, RemoveInvitedUser};
use crate::server::InnerMsg; use crate::server::InnerMsg;

View File

@ -1,6 +1,6 @@
use database_actor::issue_statuses;
use bitque_data::msg::WsMsgIssueStatus; use bitque_data::msg::WsMsgIssueStatus;
use bitque_data::{IssueStatusId, Position, TitleString, WsMsg}; use bitque_data::{IssueStatusId, Position, TitleString, WsMsg};
use database_actor::issue_statuses;
use crate::{db_or_debug_and_return, AsyncHandler, WebSocketActor, WsResult}; use crate::{db_or_debug_and_return, AsyncHandler, WebSocketActor, WsResult};

View File

@ -1,9 +1,11 @@
use std::collections::HashMap; 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::issue_assignees::LoadAssignees;
use database_actor::issues::{LoadProjectIssues, UpdateIssue}; 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}; use crate::{db_or_debug_and_return, AsyncHandler, WebSocketActor, WsResult};

View File

@ -1,6 +1,6 @@
use database_actor::messages;
use bitque_data::msg::WsMsgMessage; use bitque_data::msg::WsMsgMessage;
use bitque_data::MessageId; use bitque_data::MessageId;
use database_actor::messages;
use crate::{db_or_debug_and_return, AsyncHandler, WebSocketActor, WsResult}; use crate::{db_or_debug_and_return, AsyncHandler, WebSocketActor, WsResult};

View File

@ -1,6 +1,6 @@
use database_actor as db;
use bitque_data::msg::WsMsgProject; use bitque_data::msg::WsMsgProject;
use bitque_data::{UpdateProjectPayload, UserProject, WsMsg}; use bitque_data::{UpdateProjectPayload, UserProject, WsMsg};
use database_actor as db;
use crate::handlers::{LoadIssues, LoadProjectUsers}; use crate::handlers::{LoadIssues, LoadProjectUsers};
use crate::{db_or_debug_and_return, AsyncHandler, WebSocketActor, WsResult}; use crate::{db_or_debug_and_return, AsyncHandler, WebSocketActor, WsResult};

View File

@ -1,5 +1,5 @@
use database_actor as db;
use bitque_data::{UserProjectId, WsMsg}; use bitque_data::{UserProjectId, WsMsg};
use database_actor as db;
use crate::{db_or_debug_and_return, AsyncHandler, WebSocketActor, WsResult}; use crate::{db_or_debug_and_return, AsyncHandler, WebSocketActor, WsResult};

View File

@ -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::msg::{WsMsgInvitation, WsMsgProject, WsMsgSession, WsMsgUser};
use bitque_data::{UserId, UserProject, UserRole, WsMsg}; 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::auth::Authenticate;
use crate::handlers::user_settings; use crate::handlers::user_settings;

View File

@ -2,15 +2,14 @@ use actix::{Actor, ActorContext, Addr, AsyncContext, Handler, Recipient, StreamH
use actix_web::web::{self, Data}; use actix_web::web::{self, Data};
use actix_web::{get, Error, HttpRequest, HttpResponse}; use actix_web::{get, Error, HttpRequest, HttpResponse};
use actix_web_actors::ws; use actix_web_actors::ws;
use ::tracing::*; use bitque_data::msg::{WsMsgInvitation, WsMsgSession};
use common::{actix_web, actix_web_actors}; use bitque_data::{Project, User, UserProject, WsMsg};
use database_actor::projects::LoadCurrentProject; use database_actor::projects::LoadCurrentProject;
use database_actor::user_projects::CurrentUserProject; use database_actor::user_projects::CurrentUserProject;
use database_actor::DbExecutor; use database_actor::DbExecutor;
use futures::executor::block_on as wait; 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 mail_actor::MailExecutor;
use tracing::*;
use crate::handlers::*; use crate::handlers::*;
use crate::server::{InnerMsg, WsServer}; use crate::server::{InnerMsg, WsServer};

View File

@ -1,7 +1,7 @@
use std::collections::HashMap; use std::collections::HashMap;
use actix::{Actor, Context, Recipient};
use ::tracing::*; use ::tracing::*;
use actix::{Actor, Context, Recipient};
use bitque_data::{ProjectId, UserId, WsMsg}; use bitque_data::{ProjectId, UserId, WsMsg};
#[derive(Debug, actix::Message)] #[derive(Debug, actix::Message)]
@ -110,10 +110,7 @@ impl WsServer {
fn send_to_recipients(&self, recipients: &[Recipient<InnerMsg>], msg: &WsMsg) { fn send_to_recipients(&self, recipients: &[Recipient<InnerMsg>], msg: &WsMsg) {
for recipient in recipients.iter() { for recipient in recipients.iter() {
match recipient.do_send(InnerMsg::Transfer(msg.clone())) { recipient.do_send(InnerMsg::Transfer(msg.clone()));
Ok(_) => ::tracing::debug!("msg sent"),
Err(e) => ::tracing::error!("{}", e),
};
} }
} }
} }

View File

@ -1 +1 @@
DROP TYPE IF EXISTS "ProjectCategory" CASCADE; DROP TYPE IF EXISTS "ProjectCategoryMapping" CASCADE;

View File

@ -1,5 +1,5 @@
DROP TYPE IF EXISTS "ProjectCategory" CASCADE; DROP TYPE IF EXISTS "ProjectCategoryMapping" CASCADE;
CREATE TYPE "ProjectCategory" as ENUM ( CREATE TYPE "ProjectCategoryMapping" as ENUM (
'software', 'software',
'marketing', 'marketing',
'business' 'business'

View File

@ -1 +1 @@
DROP TYPE IF EXISTS "IssuePriority" CASCADE; DROP TYPE IF EXISTS "IssuePriorityMapping" CASCADE;

View File

@ -1,5 +1,5 @@
DROP TYPE IF EXISTS "IssuePriority" CASCADE; DROP TYPE IF EXISTS "IssuePriorityMapping" CASCADE;
CREATE TYPE "IssuePriority" as ENUM ( CREATE TYPE "IssuePriorityMapping" as ENUM (
'highest', 'highest',
'high', 'high',
'medium', 'medium',

View File

@ -1 +1 @@
DROP TYPE IF EXISTS "IssueType" CASCADE; DROP TYPE IF EXISTS "IssueTypeMapping" CASCADE;

View File

@ -1,5 +1,5 @@
DROP TYPE IF EXISTS "IssueType" CASCADE; DROP TYPE IF EXISTS "IssueTypeMapping" CASCADE;
CREATE TYPE "IssueType" AS ENUM ( CREATE TYPE "IssueTypeMapping" AS ENUM (
'task', 'task',
'bug', 'bug',
'story' 'story'

View File

@ -1 +1 @@
DROP TYPE IF EXISTS "IssueStatus" CASCADE; DROP TYPE IF EXISTS "IssueStatusMapping" CASCADE;

View File

@ -1,5 +1,5 @@
DROP TYPE IF EXISTS "IssueStatus" CASCADE; DROP TYPE IF EXISTS "IssueStatusMapping" CASCADE;
CREATE TYPE "IssueStatus" AS ENUM ( CREATE TYPE "IssueStatusMapping" AS ENUM (
'backlog', 'backlog',
'selected', 'selected',
'in_progress', 'in_progress',

View File

@ -1,9 +1,9 @@
CREATE TABLE issues ( CREATE TABLE issues (
id serial primary key not null, id serial primary key not null,
title text not null, title text not null,
issue_type "IssueType" NOT NULL DEFAULT 'task', issue_type "IssueTypeMapping" NOT NULL DEFAULT 'task',
status "IssueStatus" NOT NULL DEFAULT 'backlog', status "IssueStatusMapping" NOT NULL DEFAULT 'backlog',
priority "IssuePriority" NOT NULL DEFAULT 'low', priority "IssuePriorityMapping" NOT NULL DEFAULT 'low',
list_position double precision not null default 0, list_position double precision not null default 0,
description text, description text,
description_text text, description_text text,

View File

@ -4,8 +4,8 @@ DROP DEFAULT;
ALTER TABLE projects ALTER TABLE projects
ALTER COLUMN category ALTER COLUMN category
SET DATA TYPE "ProjectCategory" SET DATA TYPE "ProjectCategoryMapping"
USING category::text::"ProjectCategory"; USING category::text::"ProjectCategoryMapping";
ALTER TABLE projects ALTER TABLE projects
ALTER COLUMN category ALTER COLUMN category

View File

@ -1,2 +1,2 @@
ALTER TABLE IF EXISTS users DROP COLUMN role; ALTER TABLE IF EXISTS users DROP COLUMN role;
DROP TYPE IF EXISTS "UserRole"; DROP TYPE IF EXISTS "UserRoleMapping";

View File

@ -1,8 +1,8 @@
DROP TYPE IF EXISTS "UserRole" CASCADE; DROP TYPE IF EXISTS "UserRoleMapping" CASCADE;
CREATE TYPE "UserRole" AS ENUM ( CREATE TYPE "UserRoleMapping" AS ENUM (
'user', 'user',
'manager', 'manager',
'owner' 'owner'
); );
ALTER TABLE users ADD COLUMN role "UserRole" DEFAULT 'user' NOT NULL; ALTER TABLE users ADD COLUMN role "UserRoleMapping" DEFAULT 'user' NOT NULL;

View File

@ -1,2 +1,2 @@
drop TABLE IF EXISTS invitations CASCADE; drop TABLE IF EXISTS invitations CASCADE;
drop TYPE IF EXISTS "InvitationState" CASCADE; drop TYPE IF EXISTS "InvitationStateMapping" CASCADE;

View File

@ -1,4 +1,4 @@
create type "InvitationState" AS ENUM ( create type "InvitationStateMapping" AS ENUM (
'sent', 'sent',
'accepted', 'accepted',
'revoked' 'revoked'
@ -8,7 +8,7 @@ create table invitations (
id serial primary key not null, id serial primary key not null,
name text not null, name text not null,
email 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), project_id integer not null references projects (id),
invited_by_id integer not null references users (id), invited_by_id integer not null references users (id),
created_at timestamp not null default now(), created_at timestamp not null default now(),

View File

@ -1,3 +1,3 @@
alter TABLE projects drop COLUMN time_tracking; alter TABLE projects drop COLUMN time_tracking;
drop TYPE IF EXISTS "TimeTracking"; drop TYPE IF EXISTS "TimeTrackingMapping";

View File

@ -1,7 +1,7 @@
CREATE TYPE "TimeTracking" AS ENUM ( CREATE TYPE "TimeTrackingMapping" AS ENUM (
'untracked', 'untracked',
'fibonacci', 'fibonacci',
'hourly' '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';

View File

@ -1,13 +1,13 @@
DROP TYPE IF EXISTS "IssueStatus" CASCADE; DROP TYPE IF EXISTS "IssueStatusMapping" CASCADE;
CREATE TYPE "IssueStatus" AS ENUM ( CREATE TYPE "IssueStatusMapping" AS ENUM (
'backlog', 'backlog',
'selected', 'selected',
'in_progress', 'in_progress',
'done' 'done'
); );
ALTER TABLE issues ADD COLUMN status "IssueStatus"; ALTER TABLE issues ADD COLUMN status "IssueStatusMapping";
UPDATE issues UPDATE issues
SET status = issue_statuses.name :: "IssueStatus" SET status = issue_statuses.name :: "IssueStatusMapping"
FROM issue_statuses FROM issue_statuses
WHERE issue_statuses.id = issues.issue_status_id; WHERE issue_statuses.id = issues.issue_status_id;

View File

@ -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 DROP COLUMN status;
ALTER TABLE issues ALTER COLUMN issue_status_id SET NOT NULL; ALTER TABLE issues ALTER COLUMN issue_status_id SET NOT NULL;
DROP TYPE IF EXISTS "IssueStatus"; DROP TYPE IF EXISTS "IssueStatusMapping";

View File

@ -1,6 +1,6 @@
BEGIN; 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; ALTER TABLE users ADD COLUMN project_id int;
UPDATE users UPDATE users

View File

@ -7,7 +7,7 @@ CREATE TABLE user_projects (
project_id int not null references projects (id), project_id int not null references projects (id),
is_default bool not null default false, is_default bool not null default false,
is_current 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(), created_at timestamp not null default now(),
updated_at timestamp not null default now() updated_at timestamp not null default now()
); );

View File

@ -1 +1 @@
ALTER TABLE invitations ADD COLUMN role "UserRole" NOT NULL DEFAULT 'user'; ALTER TABLE invitations ADD COLUMN role "UserRoleMapping" NOT NULL DEFAULT 'user';

View File

@ -1,4 +1,4 @@
ALTER TABLE messages ALTER TABLE messages
ALTER COLUMN message_type ALTER COLUMN message_type
SET DATA TYPE text; SET DATA TYPE text;
DROP TYPE "MessageType"; DROP TYPE "MessageTypeMapping";

View File

@ -1,4 +1,4 @@
CREATE TYPE "MessageType" AS ENUM ( CREATE TYPE "MessageTypeMapping" AS ENUM (
'received_invitation', 'received_invitation',
'assigned_to_issue', 'assigned_to_issue',
'mention' 'mention'
@ -6,5 +6,5 @@ CREATE TYPE "MessageType" AS ENUM (
ALTER TABLE messages ALTER TABLE messages
ALTER COLUMN message_type ALTER COLUMN message_type
SET DATA TYPE "MessageType" SET DATA TYPE "MessageTypeMapping"
USING message_type::text::"MessageType"; USING message_type::text::"MessageTypeMapping";

View File

@ -7,8 +7,8 @@ UPDATE "issues"
SET "issue_type" = 'task' SET "issue_type" = 'task'
WHERE "issue_type" = 'epic'; WHERE "issue_type" = 'epic';
DROP TYPE IF EXISTS "IssueType" CASCADE; DROP TYPE IF EXISTS "IssueTypeMapping" CASCADE;
CREATE TYPE "IssueType" AS ENUM ( CREATE TYPE "IssueTypeMapping" AS ENUM (
'task', 'task',
'bug', 'bug',
'story' 'story'
@ -16,5 +16,5 @@ CREATE TYPE "IssueType" AS ENUM (
ALTER TABLE "issues" ALTER TABLE "issues"
ALTER COLUMN "issue_type" ALTER COLUMN "issue_type"
SET DATA TYPE "IssueType" SET DATA TYPE "IssueTypeMapping"
USING "issue_type"::"IssueType"; USING "issue_type"::"IssueTypeMapping";

View File

@ -3,8 +3,8 @@ ALTER TABLE "issues"
SET DATA TYPE TEXT SET DATA TYPE TEXT
USING "issue_type"::TEXT; USING "issue_type"::TEXT;
DROP TYPE IF EXISTS "IssueType" CASCADE; DROP TYPE IF EXISTS "IssueTypeMapping" CASCADE;
CREATE TYPE "IssueType" AS ENUM ( CREATE TYPE "IssueTypeMapping" AS ENUM (
'task', 'task',
'bug', 'bug',
'story', 'story',
@ -13,5 +13,5 @@ CREATE TYPE "IssueType" AS ENUM (
ALTER TABLE "issues" ALTER TABLE "issues"
ALTER COLUMN "issue_type" ALTER COLUMN "issue_type"
SET DATA TYPE "IssueType" SET DATA TYPE "IssueTypeMapping"
USING "issue_type"::"IssueType"; USING "issue_type"::"IssueTypeMapping";

Some files were not shown because too many files have changed in this diff Show More