started work on db
This commit is contained in:
parent
8593af2441
commit
ab616cb181
File diff suppressed because it is too large
Load Diff
17
Cargo.toml
17
Cargo.toml
|
@ -20,16 +20,27 @@ clap = { version = "4.3.24", features = ["derive"] }
|
|||
stv-rs = "0.3.0"
|
||||
|
||||
|
||||
serde = "1.0"
|
||||
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_derive = "1.0"
|
||||
serde_yaml = "0.9.34"
|
||||
serde_yaml = "0.9.28"
|
||||
serde_json = "1.0"
|
||||
base64 = "~0.22.1"
|
||||
futures = "0.3.30"
|
||||
hyper = "1.3.1"
|
||||
url = "2.5.0"
|
||||
|
||||
sqlx = "0.7.4"
|
||||
oauth2 = "4.4.2"
|
||||
reqwest = { version = "0.12", features = ["blocking", "json"] }
|
||||
jsonwebtoken = "9.3.0"
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
sqlx = { version = "0.7", features = ["sqlite", "runtime-tokio-native-tls"] }
|
||||
anyhow = "1.0"
|
||||
bcrypt = "0.15.1"
|
||||
|
||||
itertools = "0.13"
|
||||
indoc = "1.0.3"
|
||||
|
||||
|
||||
[dev-dependencies]
|
||||
tokio-core = "*"
|
||||
|
|
|
@ -18,5 +18,5 @@ the aim of this is rather to create the webui for participants to submit their v
|
|||
## Building
|
||||
|
||||
```bash
|
||||
cargo +nightly -Z unstable-options build --out-dir ./build
|
||||
cargo -Z unstable-options build --out-dir ./build
|
||||
```
|
||||
|
|
416
flake.lock
416
flake.lock
|
@ -1,88 +1,5 @@
|
|||
{
|
||||
"nodes": {
|
||||
"cachix": {
|
||||
"inputs": {
|
||||
"devenv": "devenv_2",
|
||||
"flake-compat": [
|
||||
"devenv",
|
||||
"flake-compat"
|
||||
],
|
||||
"nixpkgs": [
|
||||
"devenv",
|
||||
"nixpkgs"
|
||||
],
|
||||
"pre-commit-hooks": [
|
||||
"devenv",
|
||||
"pre-commit-hooks"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1712055811,
|
||||
"narHash": "sha256-7FcfMm5A/f02yyzuavJe06zLa9hcMHsagE28ADcmQvk=",
|
||||
"owner": "cachix",
|
||||
"repo": "cachix",
|
||||
"rev": "02e38da89851ec7fec3356a5c04bc8349cae0e30",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"repo": "cachix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"devenv": {
|
||||
"inputs": {
|
||||
"cachix": "cachix",
|
||||
"flake-compat": "flake-compat_2",
|
||||
"nix": "nix_2",
|
||||
"nixpkgs": "nixpkgs_2",
|
||||
"pre-commit-hooks": "pre-commit-hooks"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1716484006,
|
||||
"narHash": "sha256-2gtN5jf21HS9TAZXhf9G+OSUY1TQ/95n6clcuFjYQ58=",
|
||||
"owner": "cachix",
|
||||
"repo": "devenv",
|
||||
"rev": "800f19d1b999f89464fd8e0226abf4b3b444b0fa",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"repo": "devenv",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"devenv_2": {
|
||||
"inputs": {
|
||||
"flake-compat": [
|
||||
"devenv",
|
||||
"cachix",
|
||||
"flake-compat"
|
||||
],
|
||||
"nix": "nix",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"poetry2nix": "poetry2nix",
|
||||
"pre-commit-hooks": [
|
||||
"devenv",
|
||||
"cachix",
|
||||
"pre-commit-hooks"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1708704632,
|
||||
"narHash": "sha256-w+dOIW60FKMaHI1q5714CSibk99JfYxm0CzTinYWr+Q=",
|
||||
"owner": "cachix",
|
||||
"repo": "devenv",
|
||||
"rev": "2ee4450b0f4b95a1b90f2eb5ffea98b90e48c196",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"ref": "python-rewrite",
|
||||
"repo": "devenv",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"fenix": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
|
@ -104,254 +21,7 @@
|
|||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-compat": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1673956053,
|
||||
"narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=",
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-compat_2": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1696426674,
|
||||
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1689068808,
|
||||
"narHash": "sha256-6ixXo3wt24N/melDWjq70UuHQLxGV8jZvooRanIHXw0=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "919d646de7be200f3bf08cb76ae1f09402b6f9b4",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils_2": {
|
||||
"inputs": {
|
||||
"systems": "systems_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1710146030,
|
||||
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"gitignore": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"devenv",
|
||||
"pre-commit-hooks",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1709087332,
|
||||
"narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nix": {
|
||||
"inputs": {
|
||||
"flake-compat": "flake-compat",
|
||||
"nixpkgs": [
|
||||
"devenv",
|
||||
"cachix",
|
||||
"devenv",
|
||||
"nixpkgs"
|
||||
],
|
||||
"nixpkgs-regression": "nixpkgs-regression"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1712911606,
|
||||
"narHash": "sha256-BGvBhepCufsjcUkXnEEXhEVjwdJAwPglCC2+bInc794=",
|
||||
"owner": "domenkozar",
|
||||
"repo": "nix",
|
||||
"rev": "b24a9318ea3f3600c1e24b4a00691ee912d4de12",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "domenkozar",
|
||||
"ref": "devenv-2.21",
|
||||
"repo": "nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nix-github-actions": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"devenv",
|
||||
"cachix",
|
||||
"devenv",
|
||||
"poetry2nix",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1688870561,
|
||||
"narHash": "sha256-4UYkifnPEw1nAzqqPOTL2MvWtm3sNGw1UTYTalkTcGY=",
|
||||
"owner": "nix-community",
|
||||
"repo": "nix-github-actions",
|
||||
"rev": "165b1650b753316aa7f1787f3005a8d2da0f5301",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "nix-github-actions",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nix_2": {
|
||||
"inputs": {
|
||||
"flake-compat": [
|
||||
"devenv",
|
||||
"flake-compat"
|
||||
],
|
||||
"nixpkgs": [
|
||||
"devenv",
|
||||
"nixpkgs"
|
||||
],
|
||||
"nixpkgs-regression": "nixpkgs-regression_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1712911606,
|
||||
"narHash": "sha256-BGvBhepCufsjcUkXnEEXhEVjwdJAwPglCC2+bInc794=",
|
||||
"owner": "domenkozar",
|
||||
"repo": "nix",
|
||||
"rev": "b24a9318ea3f3600c1e24b4a00691ee912d4de12",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "domenkozar",
|
||||
"ref": "devenv-2.21",
|
||||
"repo": "nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1692808169,
|
||||
"narHash": "sha256-x9Opq06rIiwdwGeK2Ykj69dNc2IvUH1fY55Wm7atwrE=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "9201b5ff357e781bf014d0330d18555695df7ba8",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-regression": {
|
||||
"locked": {
|
||||
"lastModified": 1643052045,
|
||||
"narHash": "sha256-uGJ0VXIhWKGXxkeNnq4TvV3CIOkUJ3PAoLZ3HMzNVMw=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-regression_2": {
|
||||
"locked": {
|
||||
"lastModified": 1643052045,
|
||||
"narHash": "sha256-uGJ0VXIhWKGXxkeNnq4TvV3CIOkUJ3PAoLZ3HMzNVMw=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-stable": {
|
||||
"locked": {
|
||||
"lastModified": 1710695816,
|
||||
"narHash": "sha256-3Eh7fhEID17pv9ZxrPwCLfqXnYP006RKzSs0JptsN84=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "614b4613980a522ba49f0d194531beddbb7220d3",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-23.11",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1713361204,
|
||||
"narHash": "sha256-TA6EDunWTkc5FvDCqU3W2T3SFn0gRZqh6D/hJnM02MM=",
|
||||
"owner": "cachix",
|
||||
"repo": "devenv-nixpkgs",
|
||||
"rev": "285676e87ad9f0ca23d8714a6ab61e7e027020c6",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"ref": "rolling",
|
||||
"repo": "devenv-nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_3": {
|
||||
"locked": {
|
||||
"lastModified": 1716509168,
|
||||
"narHash": "sha256-4zSIhSRRIoEBwjbPm3YiGtbd8HDWzFxJjw5DYSDy1n8=",
|
||||
|
@ -367,64 +37,10 @@
|
|||
"type": "github"
|
||||
}
|
||||
},
|
||||
"poetry2nix": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nix-github-actions": "nix-github-actions",
|
||||
"nixpkgs": [
|
||||
"devenv",
|
||||
"cachix",
|
||||
"devenv",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1692876271,
|
||||
"narHash": "sha256-IXfZEkI0Mal5y1jr6IRWMqK8GW2/f28xJenZIPQqkY0=",
|
||||
"owner": "nix-community",
|
||||
"repo": "poetry2nix",
|
||||
"rev": "d5006be9c2c2417dafb2e2e5034d83fabd207ee3",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "poetry2nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"pre-commit-hooks": {
|
||||
"inputs": {
|
||||
"flake-compat": [
|
||||
"devenv",
|
||||
"flake-compat"
|
||||
],
|
||||
"flake-utils": "flake-utils_2",
|
||||
"gitignore": "gitignore",
|
||||
"nixpkgs": [
|
||||
"devenv",
|
||||
"nixpkgs"
|
||||
],
|
||||
"nixpkgs-stable": "nixpkgs-stable"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1713775815,
|
||||
"narHash": "sha256-Wu9cdYTnGQQwtT20QQMg7jzkANKQjwBD9iccfGKkfls=",
|
||||
"owner": "cachix",
|
||||
"repo": "pre-commit-hooks.nix",
|
||||
"rev": "2ac4dcbf55ed43f3be0bae15e181f08a57af24a4",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"repo": "pre-commit-hooks.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"devenv": "devenv",
|
||||
"fenix": "fenix",
|
||||
"nixpkgs": "nixpkgs_3"
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
},
|
||||
"rust-analyzer-src": {
|
||||
|
@ -443,36 +59,6 @@
|
|||
"repo": "rust-analyzer",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems_2": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
|
|
39
flake.nix
39
flake.nix
|
@ -1,28 +1,37 @@
|
|||
{
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
devenv.url = "github:cachix/devenv";
|
||||
|
||||
fenix.url = "github:nix-community/fenix";
|
||||
fenix.inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, devenv, ... }@inputs:
|
||||
|
||||
outputs = { self, nixpkgs, fenix }@inputs:
|
||||
let
|
||||
systems = [
|
||||
"x86_64-linux"
|
||||
"aarch64-linux"
|
||||
"aarch64-darwin"
|
||||
];
|
||||
forAllSystems = f: nixpkgs.lib.genAttrs systems (system: let
|
||||
toolchain = fenix.packages.${system}.complete;
|
||||
pkgs = import nixpkgs {
|
||||
system = "x86_64-linux";
|
||||
};
|
||||
in {
|
||||
devShell.x86_64-linux = devenv.lib.mkShell {
|
||||
inherit inputs pkgs;
|
||||
modules = [
|
||||
{
|
||||
languages.rust = {
|
||||
enable = true;
|
||||
channel = "stable";
|
||||
};
|
||||
}
|
||||
inherit system;
|
||||
overlays = [
|
||||
(_: super: let pkgs = fenix.inputs.nixpkgs.legacyPackages.${system}; in fenix.overlays.default pkgs pkgs)
|
||||
];
|
||||
};
|
||||
in f system pkgs toolchain);
|
||||
in {
|
||||
devShell = forAllSystems (system: pkgs: toolchain: pkgs.mkShell {
|
||||
packages = [
|
||||
(toolchain.withComponents [
|
||||
"cargo" "rustc" "rustfmt" "clippy"
|
||||
])
|
||||
pkgs.openssl
|
||||
pkgs.pkg-config
|
||||
];
|
||||
RUST_SRC_PATH = "${toolchain.rust-src}/lib/rustlib/src/rust/library";
|
||||
});
|
||||
};
|
||||
}
|
||||
|
|
19
src/api.rs
19
src/api.rs
|
@ -7,6 +7,9 @@
|
|||
use rocket::http::Status;
|
||||
use rocket_contrib::json::{Json, JsonValue};
|
||||
|
||||
use crate::auth::login;
|
||||
|
||||
|
||||
// Define data models
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct User {
|
||||
|
@ -49,15 +52,19 @@ struct Vote {
|
|||
data: Vec<VoteItem>,
|
||||
}
|
||||
|
||||
// Routes
|
||||
#[post("/auth/login", format = "application/json", data = "<credentials>")]
|
||||
fn login(credentials: Json<User>) -> JsonValue {
|
||||
// Authentication logic here
|
||||
json!({
|
||||
"token": "your_generated_token"
|
||||
})
|
||||
async fn handle_login(credentials: Json<User>, db: Db) -> JsonValue {
|
||||
match login(credentials.email, credentials.password, db).await {
|
||||
Ok(token) => json!({
|
||||
"token": token
|
||||
}),
|
||||
Err(error) => json!({
|
||||
"error": error
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[post("/auth/token", format = "application/json", data = "<token>")]
|
||||
fn generate_token(token: Json<Authorization>) -> JsonValue {
|
||||
// Token generation logic here
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
use jsonwebtoken::{encode, Header, EncodingKey};
|
||||
use serde::{Serialize, Deserialize};
|
||||
use chrono::{Utc, Duration};
|
||||
use std::error::Error;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
struct Claims {
|
||||
sub: String,
|
||||
exp: usize,
|
||||
}
|
||||
|
||||
pub async fn login(username: &str, _password: &str, _db: &sqlx::SqlitePool) -> Result<String, Box<dyn Error>> {
|
||||
// Normally, you would validate the username and password against the database here.
|
||||
// For the mock, we just generate a token for any username.
|
||||
|
||||
let expiration = Utc::now()
|
||||
.checked_add_signed(Duration::minutes(60))
|
||||
.expect("valid timestamp")
|
||||
.timestamp() as usize;
|
||||
|
||||
let claims = Claims {
|
||||
sub: username.to_owned(),
|
||||
exp: expiration,
|
||||
};
|
||||
|
||||
let token = encode(
|
||||
&Header::default(),
|
||||
&claims,
|
||||
&EncodingKey::from_secret("secret".as_ref()),
|
||||
)?;
|
||||
|
||||
Ok(token)
|
||||
}
|
|
@ -0,0 +1,239 @@
|
|||
use sqlx::{sqlite::SqlitePool, Pool, Row};
|
||||
use std::error::Error;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use indoc::indoc;
|
||||
|
||||
pub struct Connection {
|
||||
pool: Pool<sqlx::Sqlite>,
|
||||
}
|
||||
|
||||
pub async fn connect() -> Result<Connection, Box<dyn Error>> {
|
||||
let database_url = "sqlite::memory:"; // Use an in-memory SQLite database for testing
|
||||
let pool = SqlitePool::connect(database_url).await?;
|
||||
Ok(Connection { pool })
|
||||
}
|
||||
|
||||
pub async fn init_db(conn: &Connection) -> Result<(), Box<dyn Error>> {
|
||||
sqlx::query(indoc! {"
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
username TEXT NOT NULL UNIQUE,
|
||||
jwt_token TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS elections (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
username TEXT NOT NULL,
|
||||
namespace TEXT NOT NULL,
|
||||
description TEXT,
|
||||
start_date TEXT NOT NULL,
|
||||
end_date TEXT NOT NULL,
|
||||
FOREIGN KEY (username) REFERENCES users(username)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS authorizations (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
from_date TEXT NOT NULL,
|
||||
to_date TEXT NOT NULL,
|
||||
from_user TEXT NOT NULL,
|
||||
to_user TEXT NOT NULL,
|
||||
namespace TEXT NOT NULL,
|
||||
FOREIGN KEY (from_user) REFERENCES users(username),
|
||||
FOREIGN KEY (to_user) REFERENCES users(username)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS votes (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
value INTEGER NOT NULL,
|
||||
option_id INTEGER NOT NULL,
|
||||
election_id INTEGER NOT NULL,
|
||||
option_name TEXT NOT NULL,
|
||||
user TEXT NOT NULL,
|
||||
namespace TEXT NOT NULL,
|
||||
date TEXT NOT NULL,
|
||||
FOREIGN KEY (election_id) REFERENCES elections(id),
|
||||
FOREIGN KEY (user) REFERENCES users(username)
|
||||
);
|
||||
"})
|
||||
.execute(&conn.pool)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Users
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct User {
|
||||
pub id: i64,
|
||||
pub username: String,
|
||||
pub jwt_token: String,
|
||||
}
|
||||
|
||||
pub async fn insert_user(conn: &Connection, username: &str, jwt_token: &str) -> Result<(), Box<dyn Error>> {
|
||||
sqlx::query("INSERT INTO users (username, jwt_token) VALUES (?, ?)")
|
||||
.bind(username)
|
||||
.bind(jwt_token)
|
||||
.execute(&conn.pool)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get_user(conn: &Connection, username: &str) -> Result<Option<User>, Box<dyn Error>> {
|
||||
let row = sqlx::query("SELECT id, username, jwt_token FROM users WHERE username = ?")
|
||||
.bind(username)
|
||||
.fetch_optional(&conn.pool)
|
||||
.await?;
|
||||
if let Some(row) = row {
|
||||
Ok(Some(User {
|
||||
id: row.get("id"),
|
||||
username: row.get("username"),
|
||||
jwt_token: row.get("jwt_token"),
|
||||
}))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
// Elections
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct Election {
|
||||
pub id: i64,
|
||||
pub name: String,
|
||||
pub username: String,
|
||||
pub namespace: String,
|
||||
pub description: String,
|
||||
pub start_date: String,
|
||||
pub end_date: String,
|
||||
}
|
||||
|
||||
pub async fn insert_election(conn: &Connection, election: &Election) -> Result<(), Box<dyn Error>> {
|
||||
sqlx::query(indoc! {"
|
||||
INSERT INTO elections (name, username, namespace, description, start_date, end_date)
|
||||
VALUES (?, ?, ?, ?, ?, ?)
|
||||
"})
|
||||
.bind(&election.name)
|
||||
.bind(&election.username)
|
||||
.bind(&election.namespace)
|
||||
.bind(&election.description)
|
||||
.bind(&election.start_date)
|
||||
.bind(&election.end_date)
|
||||
.execute(&conn.pool)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get_election(conn: &Connection, id: i64) -> Result<Option<Election>, Box<dyn Error>> {
|
||||
let row = sqlx::query("SELECT id, name, username, namespace, description, start_date, end_date FROM elections WHERE id = ?")
|
||||
.bind(id)
|
||||
.fetch_optional(&conn.pool)
|
||||
.await?;
|
||||
if let Some(row) = row {
|
||||
Ok(Some(Election {
|
||||
id: row.get("id"),
|
||||
name: row.get("name"),
|
||||
username: row.get("username"),
|
||||
namespace: row.get("namespace"),
|
||||
description: row.get("description"),
|
||||
start_date: row.get("start_date"),
|
||||
end_date: row.get("end_date"),
|
||||
}))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
// Authorizations
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct Authorization {
|
||||
pub id: i64,
|
||||
pub from_date: String,
|
||||
pub to_date: String,
|
||||
pub from_user: String,
|
||||
pub to_user: String,
|
||||
pub namespace: String,
|
||||
}
|
||||
|
||||
pub async fn insert_authorization(conn: &Connection, authorization: &Authorization) -> Result<(), Box<dyn Error>> {
|
||||
sqlx::query(indoc! {"
|
||||
INSERT INTO authorizations (from_date, to_date, from_user, to_user, namespace)
|
||||
VALUES (?, ?, ?, ?, ?)
|
||||
"})
|
||||
.bind(&authorization.from_date)
|
||||
.bind(&authorization.to_date)
|
||||
.bind(&authorization.from_user)
|
||||
.bind(&authorization.to_user)
|
||||
.bind(&authorization.namespace)
|
||||
.execute(&conn.pool)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get_authorization(conn: &Connection, id: i64) -> Result<Option<Authorization>, Box<dyn Error>> {
|
||||
let row = sqlx::query("SELECT id, from_date, to_date, from_user, to_user, namespace FROM authorizations WHERE id = ?")
|
||||
.bind(id)
|
||||
.fetch_optional(&conn.pool)
|
||||
.await?;
|
||||
if let Some(row) = row {
|
||||
Ok(Some(Authorization {
|
||||
id: row.get("id"),
|
||||
from_date: row.get("from_date"),
|
||||
to_date: row.get("to_date"),
|
||||
from_user: row.get("from_user"),
|
||||
to_user: row.get("to_user"),
|
||||
namespace: row.get("namespace"),
|
||||
}))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
// Votes
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct Vote {
|
||||
pub id: i64,
|
||||
pub value: i32,
|
||||
pub option_id: i64,
|
||||
pub election_id: i64,
|
||||
pub option_name: String,
|
||||
pub user: String,
|
||||
pub namespace: String,
|
||||
pub date: String,
|
||||
}
|
||||
|
||||
pub async fn insert_vote(conn: &Connection, vote: &Vote) -> Result<(), Box<dyn Error>> {
|
||||
sqlx::query(indoc! {"
|
||||
INSERT INTO votes (value, option_id, election_id, option_name, user, namespace, date)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||
"})
|
||||
.bind(vote.value)
|
||||
.bind(vote.option_id)
|
||||
.bind(vote.election_id)
|
||||
.bind(&vote.option_name)
|
||||
.bind(&vote.user)
|
||||
.bind(&vote.namespace)
|
||||
.bind(&vote.date)
|
||||
.execute(&conn.pool)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get_vote(conn: &Connection, id: i64) -> Result<Option<Vote>, Box<dyn Error>> {
|
||||
let row = sqlx::query("SELECT id, value, option_id, election_id, option_name, user, namespace, date FROM votes WHERE id = ?")
|
||||
.bind(id)
|
||||
.fetch_optional(&conn.pool)
|
||||
.await?;
|
||||
if let Some(row) = row {
|
||||
Ok(Some(Vote {
|
||||
id: row.get("id"),
|
||||
value: row.get("value"),
|
||||
option_id: row.get("option_id"),
|
||||
election_id: row.get("election_id"),
|
||||
option_name: row.get("option_name"),
|
||||
user: row.get("user"),
|
||||
namespace: row.get("namespace"),
|
||||
date: row.get("date"),
|
||||
}))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
11
src/lib.rs
11
src/lib.rs
|
@ -1,11 +0,0 @@
|
|||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
extern crate hyper;
|
||||
extern crate serde;
|
||||
extern crate serde_json;
|
||||
extern crate futures;
|
||||
extern crate url;
|
||||
|
||||
pub mod apis;
|
||||
pub mod models;
|
|
@ -0,0 +1,186 @@
|
|||
// main.rs
|
||||
|
||||
mod db;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::db;
|
||||
use tokio;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_connection() {
|
||||
let result = db::connect().await;
|
||||
assert!(result.is_ok(), "Database connection failed");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_insert_user() {
|
||||
let conn = db::connect().await.unwrap();
|
||||
db::init_db(&conn).await.unwrap();
|
||||
let result = db::insert_user(&conn, "test_user", "test_jwt").await;
|
||||
assert!(result.is_ok(), "Insert user operation failed");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_get_user() {
|
||||
let conn = db::connect().await.unwrap();
|
||||
db::init_db(&conn).await.unwrap();
|
||||
db::insert_user(&conn, "test_user", "test_jwt").await.unwrap();
|
||||
let result = db::get_user(&conn, "test_user").await;
|
||||
assert!(result.is_ok(), "Get user operation failed");
|
||||
let user = result.unwrap();
|
||||
assert!(user.is_some(), "User not found");
|
||||
let user = user.unwrap();
|
||||
assert_eq!(user.username, "test_user", "Username does not match");
|
||||
assert_eq!(user.jwt_token, "test_jwt", "JWT token does not match");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_insert_election() {
|
||||
let conn = db::connect().await.unwrap();
|
||||
db::init_db(&conn).await.unwrap();
|
||||
db::insert_user(&conn, "test_user", "test_jwt").await.unwrap();
|
||||
let election = db::Election {
|
||||
id: 0,
|
||||
name: "Election 1".to_string(),
|
||||
username: "test_user".to_string(),
|
||||
namespace: "namespace2".to_string(),
|
||||
description: "Description 1".to_string(),
|
||||
start_date: "2024-05-01T08:00".to_string(),
|
||||
end_date: "2024-05-10T20:00".to_string(),
|
||||
};
|
||||
let result = db::insert_election(&conn, &election).await;
|
||||
assert!(result.is_ok(), "Insert election operation failed");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_get_election() {
|
||||
let conn = db::connect().await.unwrap();
|
||||
db::init_db(&conn).await.unwrap();
|
||||
db::insert_user(&conn, "test_user", "test_jwt").await.unwrap();
|
||||
let election = db::Election {
|
||||
id: 0,
|
||||
name: "Election 1".to_string(),
|
||||
username: "test_user".to_string(),
|
||||
namespace: "namespace2".to_string(),
|
||||
description: "Description 1".to_string(),
|
||||
start_date: "2024-05-01T08:00".to_string(),
|
||||
end_date: "2024-05-10T20:00".to_string(),
|
||||
};
|
||||
db::insert_election(&conn, &election).await.unwrap();
|
||||
let result = db::get_election(&conn, 1).await;
|
||||
assert!(result.is_ok(), "Get election operation failed");
|
||||
let election = result.unwrap();
|
||||
assert!(election.is_some(), "Election not found");
|
||||
let election = election.unwrap();
|
||||
assert_eq!(election.name, "Election 1", "Election name does not match");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_insert_authorization() {
|
||||
let conn = db::connect().await.unwrap();
|
||||
db::init_db(&conn).await.unwrap();
|
||||
db::insert_user(&conn, "user1", "jwt1").await.unwrap();
|
||||
db::insert_user(&conn, "user2", "jwt2").await.unwrap();
|
||||
let authorization = db::Authorization {
|
||||
id: 0,
|
||||
from_date: "2024-05-01T00:00".to_string(),
|
||||
to_date: "2024-05-10T23:59".to_string(),
|
||||
from_user: "user1".to_string(),
|
||||
to_user: "user2".to_string(),
|
||||
namespace: "namespace".to_string(),
|
||||
};
|
||||
let result = db::insert_authorization(&conn, &authorization).await;
|
||||
assert!(result.is_ok(), "Insert authorization operation failed");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_get_authorization() {
|
||||
let conn = db::connect().await.unwrap();
|
||||
db::init_db(&conn).await.unwrap();
|
||||
db::insert_user(&conn, "user1", "jwt1").await.unwrap();
|
||||
db::insert_user(&conn, "user2", "jwt2").await.unwrap();
|
||||
let authorization = db::Authorization {
|
||||
id: 0,
|
||||
from_date: "2024-05-01T00:00".to_string(),
|
||||
to_date: "2024-05-10T23:59".to_string(),
|
||||
from_user: "user1".to_string(),
|
||||
to_user: "user2".to_string(),
|
||||
namespace: "namespace".to_string(),
|
||||
};
|
||||
db::insert_authorization(&conn, &authorization).await.unwrap();
|
||||
let result = db::get_authorization(&conn, 1).await;
|
||||
assert!(result.is_ok(), "Get authorization operation failed");
|
||||
let authorization = result.unwrap();
|
||||
assert!(authorization.is_some(), "Authorization not found");
|
||||
let authorization = authorization.unwrap();
|
||||
assert_eq!(authorization.from_user, "user1", "From user does not match");
|
||||
assert_eq!(authorization.to_user, "user2", "To user does not match");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_insert_vote() {
|
||||
let conn = db::connect().await.unwrap();
|
||||
db::init_db(&conn).await.unwrap();
|
||||
db::insert_user(&conn, "user1", "jwt1").await.unwrap();
|
||||
db::insert_election(&conn, &db::Election {
|
||||
id: 0,
|
||||
name: "Election 1".to_string(),
|
||||
username: "user1".to_string(),
|
||||
namespace: "namespace".to_string(),
|
||||
description: "Description 1".to_string(),
|
||||
start_date: "2024-05-01T08:00".to_string(),
|
||||
end_date: "2024-05-10T20:00".to_string(),
|
||||
}).await.unwrap();
|
||||
let vote = db::Vote {
|
||||
id: 0,
|
||||
value: 1,
|
||||
option_id: 1,
|
||||
election_id: 1,
|
||||
option_name: "Option 1".to_string(),
|
||||
user: "user1".to_string(),
|
||||
namespace: "namespace".to_string(),
|
||||
date: "2024-05-01T12:00".to_string(),
|
||||
};
|
||||
let result = db::insert_vote(&conn, &vote).await;
|
||||
assert!(result.is_ok(), "Insert vote operation failed");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_get_vote() {
|
||||
let conn = db::connect().await.unwrap();
|
||||
db::init_db(&conn).await.unwrap();
|
||||
db::insert_user(&conn, "user1", "jwt1").await.unwrap();
|
||||
db::insert_election(&conn, &db::Election {
|
||||
id: 0,
|
||||
name: "Election 1".to_string(),
|
||||
username: "user1".to_string(),
|
||||
namespace: "namespace".to_string(),
|
||||
description: "Description 1".to_string(),
|
||||
start_date: "2024-05-01T08:00".to_string(),
|
||||
end_date: "2024-05-10T20:00".to_string(),
|
||||
}).await.unwrap();
|
||||
let vote = db::Vote {
|
||||
id: 0,
|
||||
value: 1,
|
||||
option_id: 1,
|
||||
election_id: 1,
|
||||
option_name: "Option 1".to_string(),
|
||||
user: "user1".to_string(),
|
||||
namespace: "namespace".to_string(),
|
||||
date: "2024-05-01T12:00".to_string(),
|
||||
};
|
||||
db::insert_vote(&conn, &vote).await.unwrap();
|
||||
let result = db::get_vote(&conn, 1).await;
|
||||
assert!(result.is_ok(), "Get vote operation failed");
|
||||
let vote = result.unwrap();
|
||||
assert!(vote.is_some(), "Vote not found");
|
||||
let vote = vote.unwrap();
|
||||
assert_eq!(vote.option_name, "Option 1", "Option name does not match");
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
println!("This is the main function. Run `cargo test` to execute tests.");
|
||||
}
|
|
@ -59,6 +59,7 @@
|
|||
<label for="namespace">Namespace:</label>
|
||||
<input type="text" id="namespace" name="namespace" placeholder="Enter namespace" required>
|
||||
<input type="submit" value="Give Acces">
|
||||
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
|
@ -76,6 +76,8 @@
|
|||
// Add more users as needed
|
||||
];
|
||||
|
||||
|
||||
|
||||
const usersContainer = document.getElementById("usersContainer");
|
||||
|
||||
users.forEach(user => {
|
Loading…
Reference in New Issue