Start basics

This commit is contained in:
Adrian Woźniak 2023-04-24 16:11:49 +02:00
parent 34a928e98c
commit 759c12ee9a
146 changed files with 1990 additions and 942 deletions

241
Cargo.lock generated
View File

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

View File

@ -1,5 +1,6 @@
[workspace]
members = [
'server',
'web',
'crates/server',
'crates/web',
'crates/contract',
]

View File

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

View 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
View 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
View 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)
}
}

View File

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

View 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,
}

View 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