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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -21,6 +21,7 @@ actix = { version = "0.13.0", optional = true }
chrono = { version = "*", features = ["serde"] }
diesel = { version = "2.0.3", features = ["postgres", "numeric", "uuid", "r2d2"], optional = true }
diesel-derive-enum = { version = "2.0.1", features = ["postgres"] }
#diesel-derive-enum = { path = "../derive_enum_sql", features = ["postgres"] }
diesel-derive-more = { version = "1.1.3" }
diesel-derive-newtype = { version = "2.0.0-rc.0", optional = true }
serde = { version = "*" }

View File

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

View File

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

View File

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

View File

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

View File

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

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"] }
byteorder = { version = "1.0" }
chrono = { version = "0.4", features = ["serde"] }
common = { workspace = true }
derive_db_execute = { workspace = true }
diesel = { version = "2.0.3", features = ["postgres", "numeric", "uuid", "r2d2", "chrono"] }
dotenv = { version = "*" }

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 diesel::prelude::*;
use crate::db_find;
use crate::tokens::FindAccessToken;

View File

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

View File

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

View File

@ -1,15 +1,15 @@
use actix::{Handler, Message};
use diesel::prelude::*;
use bitque_data::{
EmailString, Invitation, InvitationId, InvitationState, InvitationToken, ProjectId, Token,
User, UserId, UserRole, UsernameString,
};
use diesel::prelude::*;
use crate::tokens::CreateBindToken;
use crate::users::{LookupUser, Register};
use crate::{
db_create, db_delete, db_find, db_load, db_pool, db_update, DbExecutor, DbPooledConn,
InvitationError,
db_create, db_delete, db_find, db_load, db_pool, db_update, DatabaseError, DbExecutor,
DbPooledConn, InvitationError,
};
db_find! {
@ -80,12 +80,12 @@ impl Handler<RevokeInvitation> for DbExecutor {
type Result = Result<(), crate::DatabaseError>;
fn handle(&mut self, msg: RevokeInvitation, _ctx: &mut Self::Context) -> Self::Result {
let conn = db_pool!(self);
let mut conn = db_pool!(self);
UpdateInvitationState {
id: msg.id,
state: InvitationState::Revoked,
}
.execute(conn)?;
.execute(&mut conn)?;
Ok(())
}
}
@ -95,9 +95,22 @@ pub struct AcceptInvitation {
}
impl AcceptInvitation {
pub fn execute(self, conn: &DbPooledConn) -> Result<Token, crate::DatabaseError> {
crate::Guard::new(conn)?.run::<Token, _>(|_guard| {
let invitation = crate::invitations::FindByBindToken {
pub fn execute(self, conn: &mut DbPooledConn) -> Result<Token, crate::DatabaseError> {
let mut res = Err(DatabaseError::DatabaseConnectionLost);
conn.transaction(|conn| {
res = self.exec_in_transaction(conn);
if res.is_err() {
Err(diesel::NotFound)
} else {
Ok(())
}
})
.ok();
res
}
fn exec_in_transaction(self, conn: &mut DbPooledConn) -> Result<Token, crate::DatabaseError> {
let invitation = FindByBindToken {
token: self.invitation_token,
}
.execute(conn)?;
@ -108,7 +121,7 @@ impl AcceptInvitation {
));
}
crate::invitations::UpdateInvitationState {
UpdateInvitationState {
id: invitation.id,
state: InvitationState::Accepted,
}
@ -151,7 +164,6 @@ impl AcceptInvitation {
.execute(conn)?;
crate::tokens::FindUserId { user_id: user.id }.execute(conn)
})
}
}
@ -163,8 +175,8 @@ impl Handler<AcceptInvitation> for DbExecutor {
type Result = Result<Token, crate::DatabaseError>;
fn handle(&mut self, msg: AcceptInvitation, _ctx: &mut Self::Context) -> Self::Result {
let conn = db_pool!(self);
let mut conn = db_pool!(self);
msg.execute(conn)
msg.execute(&mut conn)
}
}

View File

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

View File

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

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

View File

@ -63,47 +63,3 @@ pub trait SyncQuery {
fn handle(&self, pool: &DbPool) -> Self::Result;
}
pub struct Guard<'l> {
conn: &'l crate::DbPooledConn,
tm: &'l diesel::connection::AnsiTransactionManager,
}
impl<'l> Guard<'l> {
pub fn new(conn: &'l DbPooledConn) -> Result<Self, crate::DatabaseError> {
use diesel::connection::TransactionManager;
use diesel::prelude::*;
let tm = conn.transaction_manager();
tm.begin_transaction(conn).map_err(|e| {
::tracing::error!("{:?}", e);
crate::DatabaseError::DatabaseConnectionLost
})?;
Ok(Self { conn, tm })
}
pub fn run<R, F: FnOnce(&Guard) -> Result<R, crate::DatabaseError>>(
&self,
f: F,
) -> Result<R, crate::DatabaseError> {
use diesel::connection::TransactionManager;
let r = f(self);
match r {
Ok(r) => {
self.tm.commit_transaction(self.conn).map_err(|e| {
::tracing::error!("{:?}", e);
crate::DatabaseError::DatabaseConnectionLost
})?;
Ok(r)
}
Err(e) => {
::tracing::error!("{:?}", e);
self.tm.rollback_transaction(self.conn).map_err(|e| {
::tracing::error!("{:?}", e);
crate::DatabaseError::DatabaseConnectionLost
})?;
Err(e)
}
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,5 @@
use diesel::prelude::*;
use bitque_data::{Token, UserId};
use diesel::prelude::*;
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 diesel::prelude::*;
use crate::{db_create, db_delete, db_find, db_load, db_update};
@ -26,8 +26,8 @@ db_load! {
}
mod inner {
use diesel::prelude::*;
use bitque_data::{UserId, UserProject, UserProjectId};
use diesel::prelude::*;
use crate::db_update;

View File

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

View File

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

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

View File

@ -27,7 +27,7 @@ fn consume_ident(mut it: Peekable<IntoIter>, name: &str) -> Peekable<IntoIter> {
it
}
pub(in crate) fn codegen(mut it: Peekable<IntoIter>) -> Result<String, String> {
pub(crate) fn codegen(mut it: Peekable<IntoIter>) -> Result<String, String> {
let name = it
.next()
.expect("Expect to struct name but nothing was found");

View File

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

View File

@ -1,155 +1,500 @@
#![recursion_limit = "1024"]
extern crate proc_macro;
use proc_macro::{TokenStream, TokenTree};
use heck::{ToKebabCase, ToLowerCamelCase, ToShoutySnakeCase, ToSnakeCase, ToUpperCamelCase};
use proc_macro::TokenStream;
use proc_macro2::{Ident, Span};
use quote::quote;
use syn::*;
fn to_lower_case(s: &str) -> String {
let mut lower = String::new();
for (idx, c) in s.chars().enumerate() {
if idx > 0 && c.is_uppercase() {
lower.push('_');
}
lower.push_str(c.to_lowercase().to_string().as_str());
}
lower
/// Implement the traits necessary for inserting the enum directly into a
/// database
///
/// # Attributes
///
/// ## Type attributes
///
/// * `#[ExistingTypePath = "crate::schema::sql_types::NewEnum"]` specifies the
/// path to a corresponding diesel type that was already created by the diesel
/// CLI. If omitted, the type will be generated by this macro. *Note*: Only
/// applies to `postgres`, will error if specified for other databases
/// * `#[DieselType = "NewEnumMapping"]` specifies the name for the diesel type
/// to create. If omitted, uses `<enum name>Mapping`. *Note*: Cannot be
/// specified alongside `ExistingTypePath`
/// * `#[DbValueStyle = "snake_case"]` specifies a renaming style from each of
/// the rust enum variants to each of the database variants. Either
/// `camelCase`, `kebab-case`, `PascalCase`, `SCREAMING_SNAKE_CASE`,
/// `snake_case`, `verbatim`. If omitted, uses `snake_case`.
///
/// ## Variant attributes
///
/// * `#[db_rename = "variant"]` specifies the db name for a specific variant.
#[proc_macro_derive(
DbEnum,
attributes(PgType, DieselType, ExistingTypePath, DbValueStyle, db_rename)
)]
pub fn derive(input: TokenStream) -> TokenStream {
let input: DeriveInput = parse_macro_input!(input as DeriveInput);
let existing_mapping_path = val_from_attrs(&input.attrs, "ExistingTypePath");
if !cfg!(feature = "postgres") && existing_mapping_path.is_some() {
panic!("ExistingTypePath attribute only applies when the 'postgres' feature is enabled");
}
fn into_str(name: &str, variants: &[String]) -> String {
let mut code = format!(
r#"
#[cfg(feature = "backend")]
impl diesel::serialize::ToSql<{name}Type, diesel::pg::Pg> for {name} {{
fn to_sql<W: std::io::Write>(&self, out: &mut diesel::serialize::Output<W, diesel::pg::Pg>) -> diesel::serialize::Result {{
match *self {{
"#,
name = name,
);
// we could allow a default value here but... I'm not very keen
// let existing_mapping_path = existing_mapping_path
// .unwrap_or_else(|| format!("crate::schema::sql_types::{}", input.ident));
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
let pg_internal_type = val_from_attrs(&input.attrs, "PgType");
if existing_mapping_path.is_some() && pg_internal_type.is_some() {
panic!("Cannot specify both `ExistingTypePath` and `PgType` attributes");
}
let pg_internal_type = pg_internal_type.unwrap_or(input.ident.to_string().to_snake_case());
let new_diesel_mapping = val_from_attrs(&input.attrs, "DieselType");
if existing_mapping_path.is_some() && new_diesel_mapping.is_some() {
panic!("Cannot specify both `ExistingTypePath` and `DieselType` attributes");
}
let new_diesel_mapping = new_diesel_mapping.unwrap_or_else(|| format!("{}Type", input.ident));
// Maintain backwards compatibility by defaulting to snake case.
let case_style =
val_from_attrs(&input.attrs, "DbValueStyle").unwrap_or_else(|| "snake_case".to_string());
let case_style = CaseStyle::from_string(&case_style);
let existing_mapping_path = existing_mapping_path.map(|v| {
v.parse::<proc_macro2::TokenStream>()
.expect("ExistingTypePath is not a valid token")
});
let new_diesel_mapping = Ident::new(new_diesel_mapping.as_ref(), Span::call_site());
if let Data::Enum(syn::DataEnum {
variants: data_variants,
..
}) = input.data
{
generate_derive_enum_impls(
&existing_mapping_path,
&new_diesel_mapping,
&pg_internal_type,
case_style,
&input.ident,
&data_variants,
)
.as_str(),
);
}
code.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
} else {
syn::Error::new(
Span::call_site(),
"derive(DbEnum) can only be applied to enums",
)
.as_str(),
);
.to_compile_error()
.into()
}
}
code.push_str(format!(" _ => Ok({name}::default()),", name = name).as_str());
code.push_str(" }\n }\n}");
code.push_str(
format!(
r#"
#[cfg(feature = "backend")]
impl diesel::deserialize::FromSql<{name}Type, diesel::pg::Pg> for {name} {{
fn from_sql(bytes: Option<&[u8]>) -> deserialize::Result<Self> {{
{name}::from_diesel_bytes(bytes)
}}
}}
fn val_from_attrs(attrs: &[Attribute], attr_name: &str) -> Option<String> {
for attr in attrs {
if attr.path.is_ident(attr_name) {
match attr.parse_meta().ok()? {
Meta::NameValue(MetaNameValue {
lit: Lit::Str(lit_str),
..
}) => return Some(lit_str.value()),
_ => panic!(
"Attribute '{}' must have form: {} = \"value\"",
attr_name, attr_name
),
}
}
}
None
}
#[cfg(feature = "backend")]
impl diesel::deserialize::FromSql<diesel::sql_types::Text, diesel::pg::Pg> for {name} {{
fn from_sql(bytes: Option<&[u8]>) -> deserialize::Result<Self> {{
{name}::from_diesel_bytes(bytes)
}}
}}
"#,
name = name
/// Defines the casing for the database representation. Follows serde naming
/// convention.
#[derive(Copy, Clone, Debug, PartialEq)]
enum CaseStyle {
Camel,
Kebab,
Pascal,
Upper,
ScreamingSnake,
Snake,
Verbatim,
}
impl CaseStyle {
fn from_string(name: &str) -> Self {
match name {
"camelCase" => CaseStyle::Camel,
"kebab-case" => CaseStyle::Kebab,
"PascalCase" => CaseStyle::Pascal,
"SCREAMING_SNAKE_CASE" => CaseStyle::ScreamingSnake,
"UPPERCASE" => CaseStyle::Upper,
"snake_case" => CaseStyle::Snake,
"verbatim" | "verbatimcase" => CaseStyle::Verbatim,
s => panic!("unsupported casing: `{}`", s),
}
}
}
fn generate_derive_enum_impls(
existing_mapping_path: &Option<proc_macro2::TokenStream>,
new_diesel_mapping: &Ident,
pg_internal_type: &str,
case_style: CaseStyle,
enum_ty: &Ident,
variants: &syn::punctuated::Punctuated<Variant, syn::token::Comma>,
) -> TokenStream {
let modname = Ident::new(&format!("db_enum_impl_{}", enum_ty), Span::call_site());
let variant_ids: Vec<proc_macro2::TokenStream> = variants
.iter()
.map(|variant| {
if let Fields::Unit = variant.fields {
let id = &variant.ident;
quote! {
#enum_ty::#id
}
} else {
panic!("Variants must be fieldless")
}
})
.collect();
let variants_db: Vec<String> = variants
.iter()
.map(|variant| {
val_from_attrs(&variant.attrs, "db_rename")
.unwrap_or_else(|| stylize_value(&variant.ident.to_string(), case_style))
})
.collect();
let variants_db_bytes: Vec<LitByteStr> = variants_db
.iter()
.map(|variant_str| LitByteStr::new(variant_str.as_bytes(), Span::call_site()))
.collect();
let common = generate_common(enum_ty, &variant_ids, &variants_db, &variants_db_bytes);
let (diesel_mapping_def, diesel_mapping_use) =
// Skip this part if we already have an existing mapping
if existing_mapping_path.is_some() {
(None, None)
} else {
let new_diesel_mapping_def = generate_new_diesel_mapping(new_diesel_mapping, pg_internal_type);
let common_impls_on_new_diesel_mapping =
generate_common_impls(&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;
}),
)
.as_str(),
);
code
}
};
#[proc_macro_derive(EnumSql)]
pub fn derive_enum_sql(item: TokenStream) -> TokenStream {
let mut it = item.into_iter().peekable();
while let Some(token) = it.peek() {
if let TokenTree::Ident(_) = token {
break;
} else {
it.next();
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
})
}
}
if let Some(TokenTree::Ident(ident)) = it.next() {
if ident.to_string().as_str() != "pub" {
panic!("Expect to find keyword pub but was found {:?}", ident)
None => Some(generate_postgres_impl(
&quote! { #new_diesel_mapping },
enum_ty,
false,
)),
}
} else {
panic!("Expect to find keyword pub but nothing was found")
}
if let Some(TokenTree::Ident(ident)) = it.next() {
if ident.to_string().as_str() != "enum" {
panic!("Expect to find keyword struct but was found {:?}", ident)
}
None
};
let mysql_impl = if cfg!(feature = "mysql") {
Some(generate_mysql_impl(new_diesel_mapping, enum_ty))
} else {
panic!("Expect to find keyword struct but nothing was found")
}
let name = it
.next()
.expect("Expect to struct name but nothing was found")
.to_string();
None
};
let mut variants = vec![];
if let Some(TokenTree::Group(group)) = it.next() {
for token in group.stream() {
if let TokenTree::Ident(ident) = token {
variants.push(ident.to_string())
}
}
let sqlite_impl = if cfg!(feature = "sqlite") {
Some(generate_sqlite_impl(new_diesel_mapping, enum_ty))
} else {
panic!("Enum variants group expected");
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
}
if variants.is_empty() {
panic!("Enum cannot be empty")
};
quoted.into()
}
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()
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)
}
}
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,19 +1,21 @@
use actix_web::HttpResponse;
use common::*;
use std::fmt::{Display, Formatter};
use actix_web::body::BoxBody;
use actix_web::{HttpResponse, ResponseError};
use bitque_data::msg::WsError;
use bitque_data::ErrorResponse;
const TOKEN_NOT_FOUND: &str = "Token not found";
const DATABASE_CONNECTION_FAILED: &str = "Database connection failed";
#[derive(Debug)]
#[derive(Debug, Copy, Clone)]
pub enum HighlightError {
UnknownLanguage,
UnknownTheme,
ResultUnserializable,
}
#[derive(Debug)]
#[derive(Debug, Clone)]
pub enum ServiceError {
Unauthorized,
DatabaseConnectionLost,
@ -30,6 +32,18 @@ impl ServiceError {
}
}
impl Display for ServiceError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str("")
}
}
impl ResponseError for ServiceError {
fn error_response(&self) -> HttpResponse<BoxBody> {
self.clone().into()
}
}
impl Into<HttpResponse> for ServiceError {
fn into(self) -> HttpResponse {
match self {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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::{
EmailString, InvitationId, InvitationToken, MessageType, UserRole, UsernameString, WsMsg,
};
use database_actor::invitations;
use database_actor::messages::CreateMessageReceiver;
use futures::executor::block_on;
use crate::handlers::{LoadInvitedUsers, RemoveInvitedUser};
use crate::server::InnerMsg;

View File

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

View File

@ -1,9 +1,11 @@
use std::collections::HashMap;
use bitque_data::msg::{IssueSync, WsMsgIssue, WsMsgProject};
use bitque_data::{
CreateIssuePayload, IssueAssignee, IssueFieldId, IssueId, PayloadVariant, WsMsg,
};
use database_actor::issue_assignees::LoadAssignees;
use database_actor::issues::{LoadProjectIssues, UpdateIssue};
use bitque_data::msg::{IssueSync, WsMsgIssue, WsMsgProject};
use bitque_data::{CreateIssuePayload, IssueAssignee, IssueFieldId, IssueId, PayloadVariant, WsMsg};
use crate::{db_or_debug_and_return, AsyncHandler, WebSocketActor, WsResult};

View File

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

View File

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

View File

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

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::{UserId, UserProject, UserRole, WsMsg};
use database_actor::users::Register as DbRegister;
use database_actor::{self};
use crate::handlers::auth::Authenticate;
use crate::handlers::user_settings;

View File

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

View File

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

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;
CREATE TYPE "ProjectCategory" as ENUM (
DROP TYPE IF EXISTS "ProjectCategoryMapping" CASCADE;
CREATE TYPE "ProjectCategoryMapping" as ENUM (
'software',
'marketing',
'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;
CREATE TYPE "IssuePriority" as ENUM (
DROP TYPE IF EXISTS "IssuePriorityMapping" CASCADE;
CREATE TYPE "IssuePriorityMapping" as ENUM (
'highest',
'high',
'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;
CREATE TYPE "IssueType" AS ENUM (
DROP TYPE IF EXISTS "IssueTypeMapping" CASCADE;
CREATE TYPE "IssueTypeMapping" AS ENUM (
'task',
'bug',
'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;
CREATE TYPE "IssueStatus" AS ENUM (
DROP TYPE IF EXISTS "IssueStatusMapping" CASCADE;
CREATE TYPE "IssueStatusMapping" AS ENUM (
'backlog',
'selected',
'in_progress',

View File

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

View File

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

View File

@ -1,2 +1,2 @@
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;
CREATE TYPE "UserRole" AS ENUM (
DROP TYPE IF EXISTS "UserRoleMapping" CASCADE;
CREATE TYPE "UserRoleMapping" AS ENUM (
'user',
'manager',
'owner'
);
ALTER TABLE users ADD COLUMN role "UserRole" DEFAULT 'user' NOT NULL;
ALTER TABLE users ADD COLUMN role "UserRoleMapping" DEFAULT 'user' NOT NULL;

View File

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

View File

@ -1,3 +1,3 @@
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',
'fibonacci',
'hourly'
);
ALTER TABLE projects ADD COLUMN time_tracking "TimeTracking" NOT NULL DEFAULT 'untracked';
ALTER TABLE projects ADD COLUMN time_tracking "TimeTrackingMapping" NOT NULL DEFAULT 'untracked';

View File

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

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 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;
ALTER TABLE users ADD COLUMN role "UserRole" DEFAULT 'user' NOT NULL;
ALTER TABLE users ADD COLUMN role "UserRoleMapping" DEFAULT 'user' NOT NULL;
ALTER TABLE users ADD COLUMN project_id int;
UPDATE users

View File

@ -7,7 +7,7 @@ CREATE TABLE user_projects (
project_id int not null references projects (id),
is_default bool not null default false,
is_current bool not null default false,
role "UserRole" not null default 'user',
role "UserRoleMapping" not null default 'user',
created_at timestamp not null default now(),
updated_at timestamp not null default now()
);

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 COLUMN message_type
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',
'assigned_to_issue',
'mention'
@ -6,5 +6,5 @@ CREATE TYPE "MessageType" AS ENUM (
ALTER TABLE messages
ALTER COLUMN message_type
SET DATA TYPE "MessageType"
USING message_type::text::"MessageType";
SET DATA TYPE "MessageTypeMapping"
USING message_type::text::"MessageTypeMapping";

View File

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

View File

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

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