Start basics
This commit is contained in:
parent
34a928e98c
commit
759c12ee9a
241
Cargo.lock
generated
241
Cargo.lock
generated
@ -382,6 +382,12 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anymap2"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d301b3b94cb4b2f23d7917810addbbaff90738e0ca2be692bd027e70d7e0330c"
|
||||
|
||||
[[package]]
|
||||
name = "argon2"
|
||||
version = "0.4.1"
|
||||
@ -495,6 +501,15 @@ version = "1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3bdca834647821e0b13d9539a8634eb62d3501b6b6c2cec1722786ee6671b851"
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "1.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
@ -615,6 +630,17 @@ dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "contract"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"byteorder",
|
||||
"chrono",
|
||||
"serde",
|
||||
"sqlx",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "convert_case"
|
||||
version = "0.4.0"
|
||||
@ -989,6 +1015,171 @@ version = "0.27.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4"
|
||||
|
||||
[[package]]
|
||||
name = "gloo"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a4bef6b277b3ab073253d4bca60761240cf8d6998f4bd142211957b69a61b20"
|
||||
dependencies = [
|
||||
"gloo-console",
|
||||
"gloo-dialogs",
|
||||
"gloo-events",
|
||||
"gloo-file",
|
||||
"gloo-history",
|
||||
"gloo-net",
|
||||
"gloo-render",
|
||||
"gloo-storage",
|
||||
"gloo-timers",
|
||||
"gloo-utils",
|
||||
"gloo-worker",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gloo-console"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "82b7ce3c05debe147233596904981848862b068862e9ec3e34be446077190d3f"
|
||||
dependencies = [
|
||||
"gloo-utils",
|
||||
"js-sys",
|
||||
"serde",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gloo-dialogs"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67062364ac72d27f08445a46cab428188e2e224ec9e37efdba48ae8c289002e6"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[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 = [
|
||||
"gloo-events",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gloo-history"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd451019e0b7a2b8a7a7b23e74916601abf1135c54664e57ff71dcc26dfcdeb7"
|
||||
dependencies = [
|
||||
"gloo-events",
|
||||
"gloo-utils",
|
||||
"serde",
|
||||
"serde-wasm-bindgen",
|
||||
"serde_urlencoded",
|
||||
"thiserror",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gloo-net"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9902a044653b26b99f7e3693a42f171312d9be8b26b5697bd1e43ad1f8a35e10"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"gloo-utils",
|
||||
"js-sys",
|
||||
"pin-project",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gloo-render"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2fd9306aef67cfd4449823aadcd14e3958e0800aa2183955a309112a84ec7764"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gloo-storage"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d6ab60bf5dbfd6f0ed1f7843da31b41010515c745735c970e821945ca91e480"
|
||||
dependencies = [
|
||||
"gloo-utils",
|
||||
"js-sys",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"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 = [
|
||||
"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]]
|
||||
name = "gloo-worker"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13471584da78061a28306d1359dd0178d8d6fc1c7c80e5e35d27260346e0516a"
|
||||
dependencies = [
|
||||
"anymap2",
|
||||
"bincode",
|
||||
"gloo-console",
|
||||
"gloo-utils",
|
||||
"js-sys",
|
||||
"serde",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gumdrop"
|
||||
version = "0.8.1"
|
||||
@ -1416,6 +1607,7 @@ dependencies = [
|
||||
"base64",
|
||||
"byteorder",
|
||||
"chrono",
|
||||
"contract",
|
||||
"dotenv",
|
||||
"futures",
|
||||
"futures-util",
|
||||
@ -1819,6 +2011,17 @@ dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde-wasm-bindgen"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3b4c031cd0d9014307d82b8abf653c0290fbdaeb4c02d00c63cf52f728628bf"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"serde",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.140"
|
||||
@ -2419,6 +2622,17 @@ dependencies = [
|
||||
"tracing-log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-subscriber-wasm"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "79804e80980173c6c8e53d98508eb24a2dbc4ee17a3e8d2ca8e5bad6bf13a898"
|
||||
dependencies = [
|
||||
"gloo",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "twoway"
|
||||
version = "0.2.2"
|
||||
@ -2602,9 +2816,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.81"
|
||||
version = "0.2.84"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7c53b543413a17a202f4be280a7e5c62a1c69345f5de525ee64f8cfdbc954994"
|
||||
checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"serde",
|
||||
@ -2614,13 +2828,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.81"
|
||||
version = "0.2.84"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5491a68ab4500fa6b4d726bd67408630c3dbe9c4fe7bda16d5c82a1fd8c7340a"
|
||||
checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
@ -2641,9 +2855,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.81"
|
||||
version = "0.2.84"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c441e177922bc58f1e12c022624b6216378e5febc2f0533e41ba443d505b80aa"
|
||||
checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
@ -2651,9 +2865,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.81"
|
||||
version = "0.2.84"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d94ac45fcf608c1f45ef53e748d35660f168490c10b23704c7779ab8f5c3048"
|
||||
checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -2664,9 +2878,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.81"
|
||||
version = "0.2.84"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a89911bd99e5f3659ec4acf9c4d93b0a90fe4a2a11f15328472058edc5261be"
|
||||
checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-test"
|
||||
@ -2713,9 +2927,14 @@ dependencies = [
|
||||
name = "web"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"console_error_panic_hook",
|
||||
"contract",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sycamore",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
"tracing-subscriber-wasm",
|
||||
"wasm_request",
|
||||
]
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
[workspace]
|
||||
members = [
|
||||
'server',
|
||||
'web',
|
||||
'crates/server',
|
||||
'crates/web',
|
||||
'crates/contract',
|
||||
]
|
||||
|
@ -5,7 +5,9 @@
|
||||
https://github.com/dominem/postgresql_fts_polish_dict
|
||||
|
||||
```
|
||||
|
||||
cp db/dictionary/polish.dict /usr/share/postgresql/tsearch_data/polish.dict
|
||||
cp db/dictionary/polish.affix /usr/share/postgresql/tsearch_data/polish.affix
|
||||
cp db/dictionary/polish.stop /usr/share/postgresql/tsearch_data/polish.stop
|
||||
```
|
||||
|
||||
```sql
|
||||
|
14
crates/contract/Cargo.toml
Normal file
14
crates/contract/Cargo.toml
Normal file
@ -0,0 +1,14 @@
|
||||
[package]
|
||||
name = "contract"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[features]
|
||||
db = ['sqlx', 'byteorder']
|
||||
|
||||
[dependencies]
|
||||
serde = { version = "*", features = ['derive'] }
|
||||
chrono = { version = "*", features = ['serde'] }
|
||||
sqlx = { version = "*", optional = true }
|
||||
byteorder = { version = "1.4.3", optional = true }
|
||||
base64 = { version = "*" }
|
78
crates/contract/src/db.rs
Normal file
78
crates/contract/src/db.rs
Normal file
@ -0,0 +1,78 @@
|
||||
use byteorder::ByteOrder;
|
||||
use sqlx::database::{HasArguments, HasValueRef};
|
||||
use sqlx::encode::IsNull;
|
||||
use sqlx::error::BoxDynError;
|
||||
use sqlx::postgres::PgValueFormat;
|
||||
use sqlx::Postgres;
|
||||
|
||||
use crate::PriceRange;
|
||||
|
||||
fn take_i32(bytes: &mut &[u8]) -> i32 {
|
||||
let value = byteorder::BigEndian::read_i32(&bytes[0..4]);
|
||||
*bytes = &bytes[4..];
|
||||
value
|
||||
}
|
||||
|
||||
impl<'l> sqlx::Decode<'l, Postgres> for PriceRange {
|
||||
fn decode(value: <Postgres as HasValueRef<'l>>::ValueRef) -> Result<Self, BoxDynError> {
|
||||
match value.format() {
|
||||
PgValueFormat::Text => {
|
||||
let s = value.as_str()?;
|
||||
eprintln!("{s:?}");
|
||||
Ok(Self::Free)
|
||||
}
|
||||
PgValueFormat::Binary => {
|
||||
let mut bytes = value.as_bytes()?;
|
||||
// println!("{bytes:?}");
|
||||
|
||||
let _len = take_i32(&mut bytes);
|
||||
|
||||
let _ty = take_i32(&mut bytes);
|
||||
let _min_len = take_i32(&mut bytes);
|
||||
let min = take_i32(&mut bytes);
|
||||
|
||||
let _ty = take_i32(&mut bytes);
|
||||
let _max_len = take_i32(&mut bytes);
|
||||
let max = take_i32(&mut bytes);
|
||||
|
||||
Ok((min, max).into())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn encode(n: i32, buf: &mut <Postgres as HasArguments<'_>>::ArgumentBuffer) {
|
||||
let _ = <i32 as sqlx::Encode<'_, Postgres>>::encode(n, buf);
|
||||
}
|
||||
|
||||
impl<'l> sqlx::Encode<'l, Postgres> for PriceRange {
|
||||
fn encode_by_ref(&self, buf: &mut <Postgres as HasArguments<'l>>::ArgumentBuffer) -> IsNull {
|
||||
encode(2i32, buf);
|
||||
fn write_value(n: &i32, buf: &mut <Postgres as HasArguments<'_>>::ArgumentBuffer) {
|
||||
encode(23i32, buf);
|
||||
encode(4i32, buf);
|
||||
encode(*n, buf);
|
||||
}
|
||||
match self {
|
||||
PriceRange::Free => {
|
||||
write_value(&0, buf);
|
||||
write_value(&0, buf);
|
||||
}
|
||||
PriceRange::Fixed { value } => {
|
||||
write_value(value, buf);
|
||||
write_value(&0, buf);
|
||||
}
|
||||
PriceRange::Range { min, max } => {
|
||||
write_value(min, buf);
|
||||
write_value(max, buf);
|
||||
}
|
||||
}
|
||||
IsNull::No
|
||||
}
|
||||
}
|
||||
|
||||
impl sqlx::Type<Postgres> for PriceRange {
|
||||
fn type_info() -> sqlx::postgres::PgTypeInfo {
|
||||
sqlx::postgres::PgTypeInfo::with_name("PriceRange")
|
||||
}
|
||||
}
|
454
crates/contract/src/lib.rs
Normal file
454
crates/contract/src/lib.rs
Normal file
@ -0,0 +1,454 @@
|
||||
use std::fmt::{Display, Formatter};
|
||||
|
||||
use chrono::{NaiveDateTime, Utc};
|
||||
#[cfg(feature = "db")]
|
||||
pub use db::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[cfg(feature = "db")]
|
||||
mod db;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Account {
|
||||
pub id: i32,
|
||||
pub login: String,
|
||||
pub email: String,
|
||||
pub pass: String,
|
||||
pub facebook_id: Option<String>,
|
||||
pub account_type: AccountType,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct NewsArticle {
|
||||
pub id: i32,
|
||||
pub title: String,
|
||||
pub body: String,
|
||||
pub status: NewsStatus,
|
||||
pub published_at: Option<NaiveDateTime>,
|
||||
pub created_at: NaiveDateTime,
|
||||
}
|
||||
|
||||
impl Default for NewsArticle {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
id: 0,
|
||||
title: "".to_string(),
|
||||
body: "".to_string(),
|
||||
status: NewsStatus::Pending,
|
||||
published_at: None,
|
||||
created_at: Utc::now().naive_utc(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum NewsStatus {
|
||||
Pending,
|
||||
Published,
|
||||
Hidden,
|
||||
}
|
||||
|
||||
impl NewsStatus {
|
||||
pub fn as_str(&self) -> &str {
|
||||
match self {
|
||||
Self::Pending => "Pending",
|
||||
Self::Published => "Published",
|
||||
Self::Hidden => "Hidden",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Copy, Clone, Serialize, Deserialize)]
|
||||
pub enum PriceRange {
|
||||
#[default]
|
||||
Free,
|
||||
Fixed {
|
||||
value: i32,
|
||||
},
|
||||
Range {
|
||||
min: i32,
|
||||
max: i32,
|
||||
},
|
||||
}
|
||||
|
||||
impl From<(i32, i32)> for PriceRange {
|
||||
fn from((min, max): (i32, i32)) -> Self {
|
||||
match (min, max) {
|
||||
(0, 0) => Self::Free,
|
||||
(_, 0) => Self::Fixed { value: min },
|
||||
_ => Self::Range { min, max },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||
#[derive(Debug, Default, PartialOrd, PartialEq, Eq, Copy, Clone, Serialize, Deserialize)]
|
||||
pub enum AccountType {
|
||||
#[default]
|
||||
User = 1,
|
||||
Business = 10,
|
||||
Admin = 100,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||
#[derive(Debug, Default, Copy, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum LocalBusinessState {
|
||||
#[default]
|
||||
Pending = 1,
|
||||
Approved = 2,
|
||||
Banned = 3,
|
||||
Pinned = 4,
|
||||
Internal = 5,
|
||||
}
|
||||
|
||||
impl Display for LocalBusinessState {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(self.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl LocalBusinessState {
|
||||
pub fn as_str(&self) -> &str {
|
||||
match self {
|
||||
Self::Pending => "Pending",
|
||||
Self::Approved => "Approved",
|
||||
Self::Banned => "Banned",
|
||||
Self::Pinned => "Pinned",
|
||||
Self::Internal => "Internal",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||
#[derive(Debug, Default, Copy, Clone, PartialEq, PartialOrd, Serialize, Deserialize)]
|
||||
pub enum OfferState {
|
||||
#[default]
|
||||
Pending = 0,
|
||||
Approved = 1,
|
||||
Banned = 2,
|
||||
Finished = 3,
|
||||
}
|
||||
|
||||
impl OfferState {
|
||||
pub fn as_str(&self) -> &str {
|
||||
match self {
|
||||
OfferState::Pending => "Pending",
|
||||
OfferState::Approved => "Approved",
|
||||
OfferState::Banned => "Banned",
|
||||
OfferState::Finished => "Finished",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||
pub enum Page {
|
||||
#[default]
|
||||
LocalBusinesses,
|
||||
News,
|
||||
Account,
|
||||
Register,
|
||||
Login,
|
||||
AccountBusinessItems,
|
||||
Marketplace,
|
||||
AccountOffers,
|
||||
AdminNews,
|
||||
AdminCreateNews,
|
||||
AdminBusinesses,
|
||||
AdminOffers,
|
||||
Terms,
|
||||
Privacy,
|
||||
Business,
|
||||
}
|
||||
|
||||
impl Page {
|
||||
pub fn is_public(&self) -> bool {
|
||||
!self.is_admin()
|
||||
}
|
||||
|
||||
pub fn is_admin(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
Page::AdminNews | Page::AdminCreateNews | Page::AdminBusinesses | Page::AdminOffers
|
||||
)
|
||||
}
|
||||
|
||||
pub fn select_index(&self) -> &str {
|
||||
if matches!(self, Page::LocalBusinesses) {
|
||||
"selected"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
}
|
||||
|
||||
pub fn select_news(&self) -> &str {
|
||||
if matches!(self, Page::News) {
|
||||
"selected"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
}
|
||||
|
||||
pub fn select_account(&self) -> &str {
|
||||
if matches!(self, Page::Account) {
|
||||
"selected"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
}
|
||||
|
||||
pub fn select_marketplace(&self) -> &str {
|
||||
if matches!(self, Page::Marketplace | Page::AccountOffers) {
|
||||
"selected"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
}
|
||||
|
||||
pub fn select_admin_news(&self) -> &str {
|
||||
if matches!(self, Page::AdminNews) {
|
||||
"selected"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
}
|
||||
|
||||
pub fn select_admin_businesses(&self) -> &str {
|
||||
if matches!(self, Page::AdminBusinesses) {
|
||||
"selected"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
}
|
||||
|
||||
pub fn select_admin_offers(&self) -> &str {
|
||||
if matches!(self, Page::AdminOffers) {
|
||||
"selected"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct BusinessItemInput {
|
||||
pub name: String,
|
||||
pub price: u32,
|
||||
pub picture_url: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct SetStateBusinessInput {
|
||||
pub id: i32,
|
||||
pub state: LocalBusinessState,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct LocalBusiness {
|
||||
pub id: i32,
|
||||
pub owner_id: i32,
|
||||
pub name: String,
|
||||
pub description: String,
|
||||
pub state: LocalBusinessState,
|
||||
pub items: Vec<LocalBusinessItem>,
|
||||
pub contacts: Vec<ContactInfo>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct ContactInfo {
|
||||
pub id: i32,
|
||||
pub owner_id: i32,
|
||||
pub contact_type: String,
|
||||
pub content: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct LocalBusinessItem {
|
||||
pub id: i32,
|
||||
pub local_business_id: i32,
|
||||
pub name: String,
|
||||
pub price: i64,
|
||||
pub item_order: i32,
|
||||
pub picture_url: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct CreateBusinessItemInput {
|
||||
pub name: String,
|
||||
pub price: i64,
|
||||
pub picture_url: String,
|
||||
pub item_order: i32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct AtomicUpdateBusinessItemInput {
|
||||
pub id: i32,
|
||||
pub name: String,
|
||||
pub description: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct UpdateBusinessItemInput {
|
||||
pub id: i32,
|
||||
pub name: String,
|
||||
pub price: i64,
|
||||
pub picture_url: String,
|
||||
pub item_order: i32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct ModifyBusinessItemInput {
|
||||
pub id: i32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct MoveBusinessItemInput {
|
||||
pub id: i32,
|
||||
pub item_order: i32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct UpdateNewsArticleInput {
|
||||
pub id: i32,
|
||||
pub title: String,
|
||||
pub body: String,
|
||||
pub status: NewsStatus,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct CreateNewsArticleInput {
|
||||
pub title: String,
|
||||
pub body: String,
|
||||
pub status: NewsStatus,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct DeleteNewsArticleInput {
|
||||
pub id: i32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct CreateContactInfoInput {
|
||||
#[serde(rename = "type")]
|
||||
pub contact_type: String,
|
||||
pub content: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct UpdateContactInfoInput {
|
||||
pub id: i32,
|
||||
#[serde(rename = "type")]
|
||||
pub contact_type: String,
|
||||
pub content: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct DeleteContactInfoInput {
|
||||
pub id: i32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct CreateOfferInput {
|
||||
pub description: String,
|
||||
pub picture_url: String,
|
||||
pub price_min: i32,
|
||||
pub price_max: i32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct UpdateOfferInput {
|
||||
pub id: i32,
|
||||
pub description: String,
|
||||
pub picture_url: String,
|
||||
pub price_min: i32,
|
||||
pub price_max: i32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Offer {
|
||||
pub id: i32,
|
||||
pub owner_id: i32,
|
||||
pub price_range: PriceRange,
|
||||
pub description: String,
|
||||
pub picture_url: String,
|
||||
pub state: OfferState,
|
||||
pub created_at: NaiveDateTime,
|
||||
pub contacts: Vec<ContactInfo>,
|
||||
}
|
||||
|
||||
impl Default for Offer {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
id: 0,
|
||||
owner_id: 0,
|
||||
price_range: Default::default(),
|
||||
description: "".to_string(),
|
||||
picture_url: "".to_string(),
|
||||
state: Default::default(),
|
||||
created_at: chrono::Utc::now().naive_utc(),
|
||||
contacts: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod businesses {
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, Default, Serialize, Deserialize)]
|
||||
pub struct BusinessList {
|
||||
pub businesses: Vec<LocalBusiness>,
|
||||
pub account: Option<Account>,
|
||||
pub error: Option<String>,
|
||||
pub page: Page,
|
||||
#[serde(skip)]
|
||||
pub h: Helper,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Serialize, Deserialize)]
|
||||
pub struct Helper;
|
||||
|
||||
impl Helper {
|
||||
pub fn is_admin(&self, account: &Option<Account>) -> bool {
|
||||
account
|
||||
.as_ref()
|
||||
.map(|a| a.account_type == AccountType::Admin)
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn is_above_user(&self, account: &Option<Account>) -> bool {
|
||||
account
|
||||
.as_ref()
|
||||
.map(|a| a.account_type > AccountType::User)
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn account_id_tag(&self, account: &Option<Account>) -> String {
|
||||
account
|
||||
.as_ref()
|
||||
.map(|a| format!("account-id={}", a.id))
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn email<'a>(&self, account: &'a Option<Account>) -> &'a str {
|
||||
account
|
||||
.as_ref()
|
||||
.map(|a| a.email.as_str())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn render_contact(&self, ty: &str, val: &str) -> String {
|
||||
if ty == "mobile" {
|
||||
self.mobile(val)
|
||||
} else {
|
||||
val.into()
|
||||
}
|
||||
}
|
||||
|
||||
fn mobile(&self, phone: &str) -> String {
|
||||
base64::encode(phone)
|
||||
}
|
||||
}
|
@ -26,7 +26,7 @@ postgres = { version = "0.19.3" }
|
||||
rand = { version = "0.8.5", features = [] }
|
||||
serde = { version = "*", features = ["derive"] }
|
||||
serde_json = { version = "*" }
|
||||
sqlx = { version = "*", features = ["runtime-actix-rustls", "postgres", "uuid", "chrono"] }
|
||||
sqlx = { version = "*", features = ["runtime-actix-rustls", "postgres", "uuid", "chrono", "migrate"] }
|
||||
sqlx-core = { version = "0.6.0" }
|
||||
tracing = { version = "*" }
|
||||
tracing-actix-web = { version = "*" }
|
||||
@ -34,3 +34,4 @@ tracing-subscriber = { version = "*" }
|
||||
uuid = { version = "*", features = ["serde"] }
|
||||
validator = { version = "0.14", features = ["derive"] }
|
||||
base64 = { version = "0.13.0" }
|
||||
contract = { path = "../contract", features = ['db'] }
|
182
crates/server/src/model/db.rs
Normal file
182
crates/server/src/model/db.rs
Normal file
@ -0,0 +1,182 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use chrono::{NaiveDateTime, Utc};
|
||||
use contract::{AccountType, LocalBusinessState, NewsStatus, OfferState, PriceRange};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::FromRow;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, FromRow)]
|
||||
pub struct Account {
|
||||
pub id: i32,
|
||||
pub login: String,
|
||||
pub email: String,
|
||||
pub pass: String,
|
||||
pub facebook_id: Option<String>,
|
||||
pub account_type: AccountType,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, FromRow)]
|
||||
pub struct Token {
|
||||
pub id: i32,
|
||||
pub claims: HashMap<String, String>,
|
||||
pub iss: String, /* issuer */
|
||||
pub sub: i32, /* subject */
|
||||
pub aud: String, /* audience */
|
||||
pub exp: NaiveDateTime, /* expiration time */
|
||||
pub nbt: NaiveDateTime, /* not before time */
|
||||
pub iat: NaiveDateTime, /* issued at time */
|
||||
pub jti: Uuid, /* JWT ID - unique */
|
||||
pub role: AccountType,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Serialize, Deserialize, FromRow)]
|
||||
pub struct LocalBusiness {
|
||||
pub id: i32,
|
||||
pub owner_id: i32,
|
||||
pub name: String,
|
||||
pub description: String,
|
||||
pub state: LocalBusinessState,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, FromRow)]
|
||||
pub struct LocalBusinessItem {
|
||||
pub id: i32,
|
||||
pub local_business_id: i32,
|
||||
pub name: String,
|
||||
pub price: i64,
|
||||
pub item_order: i32,
|
||||
pub picture_url: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, FromRow)]
|
||||
pub struct ContactInfo {
|
||||
pub id: i32,
|
||||
pub owner_id: i32,
|
||||
pub contact_type: String,
|
||||
pub content: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, FromRow)]
|
||||
pub struct NewsArticle {
|
||||
pub id: i32,
|
||||
pub title: String,
|
||||
pub body: String,
|
||||
pub status: NewsStatus,
|
||||
pub published_at: Option<NaiveDateTime>,
|
||||
pub created_at: NaiveDateTime,
|
||||
}
|
||||
|
||||
impl Default for NewsArticle {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
id: 0,
|
||||
title: "".to_string(),
|
||||
body: "".to_string(),
|
||||
status: NewsStatus::Pending,
|
||||
published_at: None,
|
||||
created_at: Utc::now().naive_utc(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, FromRow)]
|
||||
pub struct CreateNewsArticleInput {
|
||||
pub title: String,
|
||||
pub body: String,
|
||||
pub status: NewsStatus,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, FromRow)]
|
||||
pub struct UpdateNewsArticleInput {
|
||||
pub id: i32,
|
||||
pub title: String,
|
||||
pub body: String,
|
||||
pub status: NewsStatus,
|
||||
pub published_at: Option<NaiveDateTime>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, FromRow)]
|
||||
pub struct UpdateLocalBusinessInput {
|
||||
pub id: i32,
|
||||
pub name: String,
|
||||
pub description: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, FromRow)]
|
||||
pub struct Offer {
|
||||
pub id: i32,
|
||||
pub owner_id: i32,
|
||||
pub price_range: PriceRange,
|
||||
pub description: String,
|
||||
pub picture_url: String,
|
||||
pub state: OfferState,
|
||||
pub created_at: NaiveDateTime,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CreateLocalBusinessItemInput {
|
||||
pub account_id: i32,
|
||||
pub local_business_id: i32,
|
||||
pub name: String,
|
||||
pub price: i64,
|
||||
pub item_order: i32,
|
||||
pub picture_url: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct UpdateLocalBusinessItemInput {
|
||||
pub id: i32,
|
||||
pub local_business_id: i32,
|
||||
pub name: String,
|
||||
pub price: i64,
|
||||
pub item_order: i32,
|
||||
pub picture_url: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct DeleteNewsArticleInput {
|
||||
pub id: i32,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CreateContactInput {
|
||||
pub owner_id: i32,
|
||||
pub contact_type: String,
|
||||
pub content: String,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct UpdateContactInput {
|
||||
pub id: i32,
|
||||
pub owner_id: i32,
|
||||
pub contact_type: String,
|
||||
pub content: String,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CreateAccountInput {
|
||||
pub login: String,
|
||||
pub email: String,
|
||||
pub pass: String,
|
||||
pub facebook_id: Option<String>,
|
||||
pub account_type: AccountType,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CreateOfferInput {
|
||||
pub description: String,
|
||||
pub picture_url: String,
|
||||
pub state: OfferState,
|
||||
pub owner_id: i32,
|
||||
pub price_range: PriceRange,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct UpdateOfferInput {
|
||||
pub id: i32,
|
||||
pub description: String,
|
||||
pub picture_url: String,
|
||||
pub state: OfferState,
|
||||
pub price_range: PriceRange,
|
||||
}
|
145
crates/server/src/model/view.rs
Normal file
145
crates/server/src/model/view.rs
Normal file
@ -0,0 +1,145 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
pub use contract::*;
|
||||
|
||||
use crate::model::db;
|
||||
|
||||
pub fn business_item_to_view(item: &db::LocalBusinessItem) -> LocalBusinessItem {
|
||||
let db::LocalBusinessItem {
|
||||
id,
|
||||
local_business_id,
|
||||
name,
|
||||
price,
|
||||
item_order,
|
||||
picture_url,
|
||||
} = item;
|
||||
LocalBusinessItem {
|
||||
id: *id,
|
||||
local_business_id: *local_business_id,
|
||||
name: name.clone(),
|
||||
price: *price,
|
||||
item_order: *item_order,
|
||||
picture_url: picture_url.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn business_to_view<'items, 'contacts>(
|
||||
service: db::LocalBusiness,
|
||||
items: &'items mut Vec<db::LocalBusinessItem>,
|
||||
contacts: &'contacts mut Vec<db::ContactInfo>,
|
||||
) -> LocalBusiness {
|
||||
LocalBusiness {
|
||||
id: service.id,
|
||||
owner_id: service.owner_id,
|
||||
name: service.name,
|
||||
description: service.description,
|
||||
state: service.state,
|
||||
items: items
|
||||
.drain_filter(|i| i.local_business_id == service.id)
|
||||
.map(|i| business_item_to_view(&i))
|
||||
.collect(),
|
||||
contacts: contacts
|
||||
.drain_filter(|c| c.owner_id == service.owner_id)
|
||||
.map(|c| contact_to_view(&c))
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn _info_to_view(offer: db::Offer, contacts: &Vec<Arc<db::ContactInfo>>) -> Offer {
|
||||
let db::Offer {
|
||||
id,
|
||||
owner_id,
|
||||
price_range,
|
||||
description,
|
||||
picture_url,
|
||||
state,
|
||||
created_at,
|
||||
} = offer;
|
||||
Offer {
|
||||
id,
|
||||
owner_id,
|
||||
price_range,
|
||||
description,
|
||||
picture_url,
|
||||
state,
|
||||
created_at,
|
||||
contacts: contacts
|
||||
.iter()
|
||||
.filter(|contact| contact.owner_id == owner_id)
|
||||
.map(|info| contact_to_view(info))
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn contact_to_view(info: &db::ContactInfo) -> ContactInfo {
|
||||
ContactInfo {
|
||||
id: info.id,
|
||||
owner_id: info.owner_id,
|
||||
contact_type: info.contact_type.clone(),
|
||||
content: info.content.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn account_to_view(account: db::Account) -> Account {
|
||||
let db::Account {
|
||||
id,
|
||||
login,
|
||||
email,
|
||||
pass,
|
||||
facebook_id,
|
||||
account_type,
|
||||
} = account;
|
||||
Account {
|
||||
id,
|
||||
login,
|
||||
email,
|
||||
pass,
|
||||
facebook_id,
|
||||
account_type,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn offer_to_view<'l, I>(offer: db::Offer, contacts: I) -> Offer
|
||||
where
|
||||
I: Iterator<Item = &'l db::ContactInfo>,
|
||||
{
|
||||
let db::Offer {
|
||||
id,
|
||||
owner_id,
|
||||
price_range,
|
||||
description,
|
||||
picture_url,
|
||||
state,
|
||||
created_at,
|
||||
} = offer;
|
||||
|
||||
Offer {
|
||||
id,
|
||||
owner_id,
|
||||
price_range,
|
||||
description,
|
||||
picture_url,
|
||||
state,
|
||||
created_at,
|
||||
contacts: contacts.map(|c| contact_to_view(c)).collect(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn news_to_view(news: &db::NewsArticle) -> NewsArticle {
|
||||
let db::NewsArticle {
|
||||
id,
|
||||
title,
|
||||
body,
|
||||
status,
|
||||
published_at,
|
||||
created_at,
|
||||
} = news;
|
||||
NewsArticle {
|
||||
id: *id,
|
||||
title: title.to_string(),
|
||||
body: body.to_string(),
|
||||
status: *status,
|
||||
published_at: published_at.clone(),
|
||||
created_at: *created_at,
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user