clean up tables
This commit is contained in:
parent
4ea44b3639
commit
7462a36515
|
@ -1,3 +1,2 @@
|
||||||
pub mod tables;
|
pub mod tables;
|
||||||
|
|
||||||
pub mod routes;
|
pub mod routes;
|
||||||
|
|
|
@ -15,7 +15,7 @@ use rocket_db_pools::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use fossil::routes;
|
use fossil::routes;
|
||||||
use fossil::tables::{Db, Post};
|
use fossil::tables::{posts::Post, Db};
|
||||||
|
|
||||||
#[catch(default)]
|
#[catch(default)]
|
||||||
fn default_catcher(status: Status, _: &Request) -> RawHtml<String> {
|
fn default_catcher(status: Status, _: &Request) -> RawHtml<String> {
|
||||||
|
@ -158,6 +158,7 @@ async fn main() {
|
||||||
routes::images::upload,
|
routes::images::upload,
|
||||||
routes::images::delete_image,
|
routes::images::delete_image,
|
||||||
routes::images::get_images_by_username,
|
routes::images::get_images_by_username,
|
||||||
|
// posts stuff
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
.mount("/api", routes![routes::users::api_perms])
|
.mount("/api", routes![routes::users::api_perms])
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::tables::{Db, Image, LoginStatus, User};
|
use crate::tables::{images::Image, users::LoginStatus, users::User, Db};
|
||||||
use image::io::Reader;
|
use image::io::Reader;
|
||||||
use rocket::fs::NamedFile;
|
use rocket::fs::NamedFile;
|
||||||
use rocket::fs::TempFile;
|
use rocket::fs::TempFile;
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
pub mod images;
|
pub mod images;
|
||||||
pub mod users;
|
pub mod users;
|
||||||
pub mod web;
|
pub mod web;
|
||||||
|
pub mod posts;
|
||||||
|
|
|
@ -8,7 +8,7 @@ use std::fs;
|
||||||
use rocket::http::CookieJar;
|
use rocket::http::CookieJar;
|
||||||
use rocket::serde::{json::Json, Deserialize};
|
use rocket::serde::{json::Json, Deserialize};
|
||||||
|
|
||||||
use crate::tables::{Db, User};
|
use crate::tables::{users::User, Db};
|
||||||
use rocket::{get, post};
|
use rocket::{get, post};
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
|
@ -58,7 +58,7 @@ pub async fn createuser(
|
||||||
},
|
},
|
||||||
Err(why) => {
|
Err(why) => {
|
||||||
format!("Couldn't create user: {}", why);
|
format!("Couldn't create user: {}", why);
|
||||||
status::Custom(Status::InternalServerError, format!("{why}"))
|
status::Custom(Status::InternalServerError, why.to_string())
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
536
src/tables.rs
536
src/tables.rs
|
@ -1,536 +0,0 @@
|
||||||
use base64::{engine::general_purpose, Engine};
|
|
||||||
use rand::{RngCore, SeedableRng};
|
|
||||||
use regex::Regex;
|
|
||||||
use rocket::http::{Cookie, CookieJar};
|
|
||||||
use rocket_db_pools::sqlx::Executor;
|
|
||||||
use rocket_db_pools::Connection;
|
|
||||||
use rocket_db_pools::{
|
|
||||||
sqlx::{self, PgPool, Row},
|
|
||||||
Database,
|
|
||||||
};
|
|
||||||
use sqlx::FromRow;
|
|
||||||
|
|
||||||
#[derive(Database)]
|
|
||||||
#[database("fossil_postgres")]
|
|
||||||
pub struct Db(PgPool);
|
|
||||||
|
|
||||||
#[derive(FromRow)]
|
|
||||||
pub struct Post {
|
|
||||||
pub id: i32,
|
|
||||||
pub uuid: String,
|
|
||||||
pub text_id: String,
|
|
||||||
pub title: String,
|
|
||||||
pub body: String,
|
|
||||||
pub published: bool,
|
|
||||||
}
|
|
||||||
impl Post {
|
|
||||||
pub async fn create(
|
|
||||||
mut db: Connection<Db>,
|
|
||||||
title: String, /*ex: Why Trans People Deserve All Your Money*/
|
|
||||||
body: String, /*ex: # Because we're cooler than you */
|
|
||||||
published: bool,
|
|
||||||
uuid: String,
|
|
||||||
text_id: String, /*ex: why-trans-people-deserve-all-your-money */
|
|
||||||
) {
|
|
||||||
match db
|
|
||||||
.fetch_all(
|
|
||||||
sqlx::query(
|
|
||||||
r#"
|
|
||||||
INSERT INTO posts (title, body, published, uuid, text_id)
|
|
||||||
VALUES ($1, $2, $3, $4, $5);
|
|
||||||
"#,
|
|
||||||
)
|
|
||||||
.bind(title)
|
|
||||||
.bind(body)
|
|
||||||
.bind(published)
|
|
||||||
.bind(uuid)
|
|
||||||
.bind(text_id),
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(_) => (),
|
|
||||||
Err(why) => {
|
|
||||||
eprintln!("Couldn't create database entry: {why:?}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub async fn get(mut db: Connection<Db>, id: i32) -> Post {
|
|
||||||
let res = db
|
|
||||||
.fetch_one(sqlx::query("SELECT * FROM posts WHERE id = $1;").bind(id))
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
Post {
|
|
||||||
id: res.get::<i32, _>("id"),
|
|
||||||
uuid: res.get::<String, _>("uuid"),
|
|
||||||
text_id: res.get::<String, _>("text_id"),
|
|
||||||
title: res.get::<String, _>("title"),
|
|
||||||
body: res.get::<String, _>("body"),
|
|
||||||
published: res.get::<bool, _>("published"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub async fn get_by_uuid(mut db: Connection<Db>, uuid: String) -> Post {
|
|
||||||
let res = db
|
|
||||||
.fetch_one(sqlx::query("SELECT * FROM posts WHERE uuid = $1;").bind(uuid))
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
Post {
|
|
||||||
id: res.get::<i32, _>("id"),
|
|
||||||
uuid: res.get::<String, _>("uuid"),
|
|
||||||
text_id: res.get::<String, _>("text_id"),
|
|
||||||
title: res.get::<String, _>("title"),
|
|
||||||
body: res.get::<String, _>("body"),
|
|
||||||
published: res.get::<bool, _>("published"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub async fn get_by_text_id(mut db: Connection<Db>, text_id: String) -> Post {
|
|
||||||
let res = db
|
|
||||||
.fetch_one(sqlx::query("SELECT * FROM posts WHERE text_id = $1;").bind(text_id))
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
Post {
|
|
||||||
id: res.get::<i32, _>("id"),
|
|
||||||
uuid: res.get::<String, _>("uuid"),
|
|
||||||
text_id: res.get::<String, _>("text_id"),
|
|
||||||
title: res.get::<String, _>("title"),
|
|
||||||
body: res.get::<String, _>("body"),
|
|
||||||
published: res.get::<bool, _>("published"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn edit_body(
|
|
||||||
mut db: Connection<Db>,
|
|
||||||
id: i32,
|
|
||||||
new_body: String,
|
|
||||||
) -> Result<(), String> {
|
|
||||||
match db
|
|
||||||
.execute(
|
|
||||||
sqlx::query("UPDATE posts SET body = $1 WHERE id = $2;")
|
|
||||||
.bind(new_body)
|
|
||||||
.bind(id),
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(_) => Ok(()),
|
|
||||||
Err(why) => {
|
|
||||||
eprintln!("{why:?}");
|
|
||||||
Err("Couldn't update post".to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub async fn edit_body_by_uuid(
|
|
||||||
mut db: Connection<Db>,
|
|
||||||
uuid: String,
|
|
||||||
new_body: String,
|
|
||||||
) -> Result<(), String> {
|
|
||||||
match db
|
|
||||||
.execute(
|
|
||||||
sqlx::query("UPDATE posts SET body = $1 WHERE uuid = $2;")
|
|
||||||
.bind(new_body)
|
|
||||||
.bind(uuid),
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(_) => Ok(()),
|
|
||||||
Err(why) => {
|
|
||||||
eprintln!("{why:?}");
|
|
||||||
Err("Couldn't update post".to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub async fn edit_body_by_text_id(
|
|
||||||
mut db: Connection<Db>,
|
|
||||||
text_id: String,
|
|
||||||
new_body: String,
|
|
||||||
) -> Result<(), String> {
|
|
||||||
match db
|
|
||||||
.execute(
|
|
||||||
sqlx::query("UPDATE posts SET body = $1 WHERE text_id = $2;")
|
|
||||||
.bind(new_body)
|
|
||||||
.bind(text_id),
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(_) => Ok(()),
|
|
||||||
Err(why) => {
|
|
||||||
eprintln!("{why:?}");
|
|
||||||
Err("Couldn't update post".to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub async fn edit_title(
|
|
||||||
mut db: Connection<Db>,
|
|
||||||
id: i32,
|
|
||||||
new_title: String,
|
|
||||||
) -> Result<(), String> {
|
|
||||||
match db
|
|
||||||
.execute(
|
|
||||||
sqlx::query("UPDATE posts SET title = $1 WHERE id = $2;")
|
|
||||||
.bind(new_title)
|
|
||||||
.bind(id),
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(_) => Ok(()),
|
|
||||||
Err(why) => {
|
|
||||||
eprintln!("{why:?}");
|
|
||||||
Err("Couldn't update post".to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub async fn edit_title_by_uuid(
|
|
||||||
mut db: Connection<Db>,
|
|
||||||
uuid: String,
|
|
||||||
new_title: String,
|
|
||||||
) -> Result<(), String> {
|
|
||||||
match db
|
|
||||||
.execute(
|
|
||||||
sqlx::query("UPDATE posts SET title = $1 WHERE uuid = $2;")
|
|
||||||
.bind(new_title)
|
|
||||||
.bind(uuid),
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(_) => Ok(()),
|
|
||||||
Err(why) => {
|
|
||||||
eprintln!("{why:?}");
|
|
||||||
Err("Couldn't update post".to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub async fn edit_title_by_text_id(
|
|
||||||
mut db: Connection<Db>,
|
|
||||||
text_id: String,
|
|
||||||
new_title: String,
|
|
||||||
) -> Result<(), String> {
|
|
||||||
match db
|
|
||||||
.execute(
|
|
||||||
sqlx::query("UPDATE posts SET body = $1 WHERE text_id = $2;")
|
|
||||||
.bind(new_title)
|
|
||||||
.bind(text_id),
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(_) => Ok(()),
|
|
||||||
Err(why) => {
|
|
||||||
eprintln!("{why:?}");
|
|
||||||
Err("Couldn't update post".to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub async fn edit_text_id(
|
|
||||||
mut db: Connection<Db>,
|
|
||||||
id: i32,
|
|
||||||
new_text_id: String,
|
|
||||||
) -> Result<(), String> {
|
|
||||||
match db
|
|
||||||
.execute(
|
|
||||||
sqlx::query("UPDATE posts SET text_id = $1 WHERE id = $2;")
|
|
||||||
.bind(new_text_id)
|
|
||||||
.bind(id),
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(_) => Ok(()),
|
|
||||||
Err(why) => {
|
|
||||||
eprintln!("{why:?}");
|
|
||||||
Err("Couldn't update post".to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub async fn edit_text_id_by_uuid(
|
|
||||||
mut db: Connection<Db>,
|
|
||||||
uuid: String,
|
|
||||||
new_text_id: String,
|
|
||||||
) -> Result<(), String> {
|
|
||||||
match db
|
|
||||||
.execute(
|
|
||||||
sqlx::query("UPDATE posts SET text_id = $1 WHERE uuid = $2;")
|
|
||||||
.bind(new_text_id)
|
|
||||||
.bind(uuid),
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(_) => Ok(()),
|
|
||||||
Err(why) => {
|
|
||||||
eprintln!("{why:?}");
|
|
||||||
Err("Couldn't update post".to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(FromRow, Debug)]
|
|
||||||
pub struct User {
|
|
||||||
pub id: i32,
|
|
||||||
pub username: String,
|
|
||||||
pub password: String,
|
|
||||||
pub token: Option<String>,
|
|
||||||
pub admin: bool,
|
|
||||||
pub make_posts: bool,
|
|
||||||
pub comment: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum LoginStatus {
|
|
||||||
InvalidToken,
|
|
||||||
NotLoggedIn,
|
|
||||||
LoggedIn(User),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl User {
|
|
||||||
pub async fn create(
|
|
||||||
db: &mut Connection<Db>,
|
|
||||||
username: &String,
|
|
||||||
password: &String,
|
|
||||||
) -> Result<String, String> {
|
|
||||||
match Regex::new(r"[^A-Za-z0-9_]") {
|
|
||||||
Ok(r) => {
|
|
||||||
match r.captures(username) {
|
|
||||||
Some(_) =>
|
|
||||||
Err("The username contains invalid characters. Only letters, numbers, and underscores are allowed.".to_string())
|
|
||||||
,
|
|
||||||
None => {
|
|
||||||
if username.len().gt(&32) || username.len().lt(&3) { // i can Never
|
|
||||||
// remember which symbol is which. this works better for me.
|
|
||||||
Err("Please choose a username between 3 and 32 characters.".to_string())
|
|
||||||
} else {
|
|
||||||
match db
|
|
||||||
.execute(
|
|
||||||
sqlx::query(
|
|
||||||
r#"
|
|
||||||
INSERT INTO users (username, password)
|
|
||||||
VALUES ($1, $2);
|
|
||||||
"#,
|
|
||||||
)
|
|
||||||
.bind(username)
|
|
||||||
.bind(sha256::digest(password)),
|
|
||||||
).await
|
|
||||||
{
|
|
||||||
Ok(_) =>
|
|
||||||
Ok("Created user.".to_string())
|
|
||||||
,
|
|
||||||
Err(why) => {
|
|
||||||
eprintln!("Couldn't create database entry: {why:?}");
|
|
||||||
Err("Failed to create user.".to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(why) => {
|
|
||||||
eprintln!("Couldn't compile name regex: {why:?}");
|
|
||||||
Err("Couldn't compile name regex.".to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub async fn get_by_id(db: &mut Connection<Db>, id: i32) -> Option<User> {
|
|
||||||
match db
|
|
||||||
.fetch_one(sqlx::query("SELECT * FROM users WHERE id = $1;").bind(id))
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(user) => Some(User {
|
|
||||||
id: user.get::<i32, _>("id"),
|
|
||||||
username: user.get::<String, _>("username"),
|
|
||||||
password: user.get::<String, _>("password"),
|
|
||||||
token: user.get::<Option<String>, _>("token"),
|
|
||||||
admin: user.get::<bool, _>("admin"),
|
|
||||||
make_posts: user.get::<bool, _>("make_posts"),
|
|
||||||
comment: user.get::<bool, _>("comment"),
|
|
||||||
}),
|
|
||||||
Err(_) => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub async fn get_by_token(db: &mut Connection<Db>, token: Cookie<'static>) -> Option<User> {
|
|
||||||
let to = token.to_string();
|
|
||||||
let mut fixed_token = to.split('=').collect::<Vec<&str>>();
|
|
||||||
fixed_token.reverse();
|
|
||||||
fixed_token.pop();
|
|
||||||
fixed_token.reverse();
|
|
||||||
let token_string = fixed_token.join("=");
|
|
||||||
|
|
||||||
match db
|
|
||||||
.fetch_one(sqlx::query("SELECT * FROM users WHERE token = $1;").bind(token_string))
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(user) => Some(User {
|
|
||||||
id: user.get::<i32, _>("id"),
|
|
||||||
username: user.get::<String, _>("username"),
|
|
||||||
password: user.get::<String, _>("password"),
|
|
||||||
token: user.get::<Option<String>, _>("token"),
|
|
||||||
admin: user.get::<bool, _>("admin"),
|
|
||||||
make_posts: user.get::<bool, _>("make_posts"),
|
|
||||||
comment: user.get::<bool, _>("comment"),
|
|
||||||
}),
|
|
||||||
Err(_) => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub async fn get_by_username(db: &mut Connection<Db>, username: &String) -> Option<User> {
|
|
||||||
match db
|
|
||||||
.fetch_one(sqlx::query("SELECT * FROM users WHERE username = $1;").bind(username))
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(user) => Some(User {
|
|
||||||
id: user.get::<i32, _>("id"),
|
|
||||||
username: user.get::<String, _>("username"),
|
|
||||||
password: user.get::<String, _>("password"),
|
|
||||||
token: user.get::<Option<String>, _>("token"),
|
|
||||||
admin: user.get::<bool, _>("admin"),
|
|
||||||
make_posts: user.get::<bool, _>("make_posts"),
|
|
||||||
comment: user.get::<bool, _>("comment"),
|
|
||||||
}),
|
|
||||||
Err(_) => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub async fn set_new_token(&self, db: &mut Connection<Db>) -> Result<String, String> {
|
|
||||||
let token_end = format!("{}", rand_hc::Hc128Rng::from_entropy().next_u64());
|
|
||||||
let token_start = sha256::digest(&self.username);
|
|
||||||
|
|
||||||
let token = format!(
|
|
||||||
"{}-{}",
|
|
||||||
general_purpose::STANDARD.encode(token_start),
|
|
||||||
general_purpose::STANDARD.encode(token_end)
|
|
||||||
);
|
|
||||||
|
|
||||||
match db
|
|
||||||
.execute(
|
|
||||||
sqlx::query("UPDATE users SET token = $1 WHERE id = $2")
|
|
||||||
.bind(&token)
|
|
||||||
.bind(self.id),
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(_) => Ok(token),
|
|
||||||
Err(why) => Err(why.to_string()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn set_role(
|
|
||||||
&self,
|
|
||||||
db: &mut Connection<Db>,
|
|
||||||
role: &String,
|
|
||||||
value: &bool,
|
|
||||||
) -> Result<String, String> {
|
|
||||||
let mut sql = String::from("UPDATE users SET {{perm}} = $1 WHERE id = $2");
|
|
||||||
if role == "admin" {
|
|
||||||
sql = sql.replace("{{perm}}", "admin");
|
|
||||||
} else if role == "make_posts" {
|
|
||||||
sql = sql.replace("{{perm}}", "make_posts");
|
|
||||||
} else if role == &"comment".to_string() {
|
|
||||||
sql = sql.replace("{{perm}}", "comment");
|
|
||||||
}
|
|
||||||
if sql.contains("{{perm}}") {
|
|
||||||
Err("Invalid role.".to_string())
|
|
||||||
} else {
|
|
||||||
match db
|
|
||||||
.execute(sqlx::query(&sql[..]).bind(value).bind(self.id))
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(_) => Ok("Succesfully updated role.".to_string()),
|
|
||||||
Err(why) => Err(why.to_string()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn login_status(db: &mut Connection<Db>, cookies: &CookieJar<'_>) -> LoginStatus {
|
|
||||||
match cookies.get_private("token") {
|
|
||||||
Some(t) => match User::get_by_token(db, t).await {
|
|
||||||
Some(user) => LoginStatus::LoggedIn(user),
|
|
||||||
None => LoginStatus::InvalidToken,
|
|
||||||
},
|
|
||||||
None => LoginStatus::NotLoggedIn,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Image {
|
|
||||||
pub id: i32,
|
|
||||||
pub uuid: String,
|
|
||||||
pub owner_name: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Image {
|
|
||||||
pub async fn create(db: &mut Connection<Db>, uuid: &String, user: User) -> Result<(), String> {
|
|
||||||
match db
|
|
||||||
.execute(
|
|
||||||
sqlx::query(
|
|
||||||
r#"
|
|
||||||
INSERT INTO images (uuid, owner_name)
|
|
||||||
VALUES ($1, $2);
|
|
||||||
"#,
|
|
||||||
)
|
|
||||||
.bind(uuid)
|
|
||||||
.bind(user.username),
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(_) => Ok(()),
|
|
||||||
Err(why) => {
|
|
||||||
eprintln!("Couldn't create database entry: {why:?}");
|
|
||||||
Err("Couldn't create image.".to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub async fn get_by_uuid(db: &mut Connection<Db>, uuid: &String) -> Result<Image, String> {
|
|
||||||
match db
|
|
||||||
.fetch_one(sqlx::query("SELECT * FROM images WHERE uuid = $1;").bind(uuid))
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(img) => Ok(Image {
|
|
||||||
id: img.get::<i32, _>("id"),
|
|
||||||
uuid: img.get::<String, _>("uuid"),
|
|
||||||
owner_name: img.get::<String, _>("owner_name"),
|
|
||||||
}),
|
|
||||||
Err(_) => Err("Couldn't get image.".to_string()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub async fn is_owned_by(
|
|
||||||
db: &mut Connection<Db>,
|
|
||||||
uuid: &String,
|
|
||||||
username: &String,
|
|
||||||
) -> Result<bool, String> {
|
|
||||||
match Image::get_by_uuid(db, uuid).await {
|
|
||||||
Ok(img) => Ok(&img.owner_name == username),
|
|
||||||
Err(why) => {
|
|
||||||
eprintln!("{why:?}");
|
|
||||||
Err("couldn't get image".to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub async fn get_by_username(
|
|
||||||
db: &mut Connection<Db>,
|
|
||||||
owner_name: &String,
|
|
||||||
) -> Result<Vec<Image>, String> {
|
|
||||||
match db
|
|
||||||
.fetch_all(sqlx::query("SELECT * FROM images WHERE owner_name = $1;").bind(owner_name))
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(imgs) => {
|
|
||||||
let mut res = vec![];
|
|
||||||
for img in imgs {
|
|
||||||
res.push(Image {
|
|
||||||
id: img.get::<i32, _>("id"),
|
|
||||||
uuid: img.get::<String, _>("uuid"),
|
|
||||||
owner_name: img.get::<String, _>("owner_name"),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
Ok(res)
|
|
||||||
}
|
|
||||||
Err(_) => Err("Couldn't get image.".to_string()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub async fn delete(db: &mut Connection<Db>, uuid: &String) -> Result<(), ()> {
|
|
||||||
match db
|
|
||||||
.execute(sqlx::query("DELETE FROM images WHERE uuid = $1").bind(uuid))
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(rows_gone) => {
|
|
||||||
eprintln!("Deleted {rows_gone:?} rows.");
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
Err(why) => {
|
|
||||||
eprintln!("Couldn't remove database entry: {why:?}");
|
|
||||||
Err(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,97 @@
|
||||||
|
use crate::tables::{users::User, Db};
|
||||||
|
use rocket_db_pools::sqlx::Executor;
|
||||||
|
use rocket_db_pools::sqlx::{self, Row};
|
||||||
|
use rocket_db_pools::Connection;
|
||||||
|
|
||||||
|
pub struct Image {
|
||||||
|
pub id: i32,
|
||||||
|
pub uuid: String,
|
||||||
|
pub owner_name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Image {
|
||||||
|
pub async fn create(db: &mut Connection<Db>, uuid: &String, user: User) -> Result<(), String> {
|
||||||
|
match db
|
||||||
|
.execute(
|
||||||
|
sqlx::query(
|
||||||
|
r#"
|
||||||
|
INSERT INTO images (uuid, owner_name)
|
||||||
|
VALUES ($1, $2);
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.bind(uuid)
|
||||||
|
.bind(user.username),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
Err(why) => {
|
||||||
|
eprintln!("Couldn't create database entry: {why:?}");
|
||||||
|
Err("Couldn't create image.".to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub async fn get_by_uuid(db: &mut Connection<Db>, uuid: &String) -> Result<Image, String> {
|
||||||
|
match db
|
||||||
|
.fetch_one(sqlx::query("SELECT * FROM images WHERE uuid = $1;").bind(uuid))
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(img) => Ok(Image {
|
||||||
|
id: img.get::<i32, _>("id"),
|
||||||
|
uuid: img.get::<String, _>("uuid"),
|
||||||
|
owner_name: img.get::<String, _>("owner_name"),
|
||||||
|
}),
|
||||||
|
Err(_) => Err("Couldn't get image.".to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub async fn is_owned_by(
|
||||||
|
db: &mut Connection<Db>,
|
||||||
|
uuid: &String,
|
||||||
|
username: &String,
|
||||||
|
) -> Result<bool, String> {
|
||||||
|
match Image::get_by_uuid(db, uuid).await {
|
||||||
|
Ok(img) => Ok(&img.owner_name == username),
|
||||||
|
Err(why) => {
|
||||||
|
eprintln!("{why:?}");
|
||||||
|
Err("couldn't get image".to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub async fn get_by_username(
|
||||||
|
db: &mut Connection<Db>,
|
||||||
|
owner_name: &String,
|
||||||
|
) -> Result<Vec<Image>, String> {
|
||||||
|
match db
|
||||||
|
.fetch_all(sqlx::query("SELECT * FROM images WHERE owner_name = $1;").bind(owner_name))
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(imgs) => {
|
||||||
|
let mut res = vec![];
|
||||||
|
for img in imgs {
|
||||||
|
res.push(Image {
|
||||||
|
id: img.get::<i32, _>("id"),
|
||||||
|
uuid: img.get::<String, _>("uuid"),
|
||||||
|
owner_name: img.get::<String, _>("owner_name"),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
Err(_) => Err("Couldn't get image.".to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub async fn delete(db: &mut Connection<Db>, uuid: &String) -> Result<(), ()> {
|
||||||
|
match db
|
||||||
|
.execute(sqlx::query("DELETE FROM images WHERE uuid = $1").bind(uuid))
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(rows_gone) => {
|
||||||
|
eprintln!("Deleted {rows_gone:?} rows.");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Err(why) => {
|
||||||
|
eprintln!("Couldn't remove database entry: {why:?}");
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
pub mod images;
|
||||||
|
pub mod posts;
|
||||||
|
pub mod users;
|
||||||
|
|
||||||
|
use rocket_db_pools::{sqlx::PgPool, Database};
|
||||||
|
|
||||||
|
#[derive(Database)]
|
||||||
|
#[database("fossil_postgres")]
|
||||||
|
pub struct Db(PgPool);
|
|
@ -0,0 +1,251 @@
|
||||||
|
use rocket_db_pools::sqlx::Executor;
|
||||||
|
use rocket_db_pools::sqlx::{self, Row};
|
||||||
|
use rocket_db_pools::Connection;
|
||||||
|
|
||||||
|
use crate::tables::Db;
|
||||||
|
use sqlx::FromRow;
|
||||||
|
|
||||||
|
#[derive(FromRow)]
|
||||||
|
pub struct Post {
|
||||||
|
pub id: i32,
|
||||||
|
pub uuid: String,
|
||||||
|
pub text_id: String,
|
||||||
|
pub title: String,
|
||||||
|
pub body: String,
|
||||||
|
pub published: bool,
|
||||||
|
}
|
||||||
|
impl Post {
|
||||||
|
pub async fn create(
|
||||||
|
mut db: Connection<Db>,
|
||||||
|
title: String, /*ex: Why Trans People Deserve All Your Money*/
|
||||||
|
body: String, /*ex: # Because we're cooler than you */
|
||||||
|
published: bool,
|
||||||
|
uuid: String,
|
||||||
|
text_id: String, /*ex: why-trans-people-deserve-all-your-money */
|
||||||
|
) {
|
||||||
|
match db
|
||||||
|
.fetch_all(
|
||||||
|
sqlx::query(
|
||||||
|
r#"
|
||||||
|
INSERT INTO posts (title, body, published, uuid, text_id)
|
||||||
|
VALUES ($1, $2, $3, $4, $5);
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.bind(title)
|
||||||
|
.bind(body)
|
||||||
|
.bind(published)
|
||||||
|
.bind(uuid)
|
||||||
|
.bind(text_id),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(_) => (),
|
||||||
|
Err(why) => {
|
||||||
|
eprintln!("Couldn't create database entry: {why:?}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub async fn get(mut db: Connection<Db>, id: i32) -> Post {
|
||||||
|
let res = db
|
||||||
|
.fetch_one(sqlx::query("SELECT * FROM posts WHERE id = $1;").bind(id))
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
Post {
|
||||||
|
id: res.get::<i32, _>("id"),
|
||||||
|
uuid: res.get::<String, _>("uuid"),
|
||||||
|
text_id: res.get::<String, _>("text_id"),
|
||||||
|
title: res.get::<String, _>("title"),
|
||||||
|
body: res.get::<String, _>("body"),
|
||||||
|
published: res.get::<bool, _>("published"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub async fn get_by_uuid(mut db: Connection<Db>, uuid: String) -> Post {
|
||||||
|
let res = db
|
||||||
|
.fetch_one(sqlx::query("SELECT * FROM posts WHERE uuid = $1;").bind(uuid))
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
Post {
|
||||||
|
id: res.get::<i32, _>("id"),
|
||||||
|
uuid: res.get::<String, _>("uuid"),
|
||||||
|
text_id: res.get::<String, _>("text_id"),
|
||||||
|
title: res.get::<String, _>("title"),
|
||||||
|
body: res.get::<String, _>("body"),
|
||||||
|
published: res.get::<bool, _>("published"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub async fn get_by_text_id(mut db: Connection<Db>, text_id: String) -> Post {
|
||||||
|
let res = db
|
||||||
|
.fetch_one(sqlx::query("SELECT * FROM posts WHERE text_id = $1;").bind(text_id))
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
Post {
|
||||||
|
id: res.get::<i32, _>("id"),
|
||||||
|
uuid: res.get::<String, _>("uuid"),
|
||||||
|
text_id: res.get::<String, _>("text_id"),
|
||||||
|
title: res.get::<String, _>("title"),
|
||||||
|
body: res.get::<String, _>("body"),
|
||||||
|
published: res.get::<bool, _>("published"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn edit_body(
|
||||||
|
mut db: Connection<Db>,
|
||||||
|
id: i32,
|
||||||
|
new_body: String,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
match db
|
||||||
|
.execute(
|
||||||
|
sqlx::query("UPDATE posts SET body = $1 WHERE id = $2;")
|
||||||
|
.bind(new_body)
|
||||||
|
.bind(id),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
Err(why) => {
|
||||||
|
eprintln!("{why:?}");
|
||||||
|
Err("Couldn't update post".to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub async fn edit_body_by_uuid(
|
||||||
|
mut db: Connection<Db>,
|
||||||
|
uuid: String,
|
||||||
|
new_body: String,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
match db
|
||||||
|
.execute(
|
||||||
|
sqlx::query("UPDATE posts SET body = $1 WHERE uuid = $2;")
|
||||||
|
.bind(new_body)
|
||||||
|
.bind(uuid),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
Err(why) => {
|
||||||
|
eprintln!("{why:?}");
|
||||||
|
Err("Couldn't update post".to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub async fn edit_body_by_text_id(
|
||||||
|
mut db: Connection<Db>,
|
||||||
|
text_id: String,
|
||||||
|
new_body: String,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
match db
|
||||||
|
.execute(
|
||||||
|
sqlx::query("UPDATE posts SET body = $1 WHERE text_id = $2;")
|
||||||
|
.bind(new_body)
|
||||||
|
.bind(text_id),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
Err(why) => {
|
||||||
|
eprintln!("{why:?}");
|
||||||
|
Err("Couldn't update post".to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub async fn edit_title(
|
||||||
|
mut db: Connection<Db>,
|
||||||
|
id: i32,
|
||||||
|
new_title: String,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
match db
|
||||||
|
.execute(
|
||||||
|
sqlx::query("UPDATE posts SET title = $1 WHERE id = $2;")
|
||||||
|
.bind(new_title)
|
||||||
|
.bind(id),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
Err(why) => {
|
||||||
|
eprintln!("{why:?}");
|
||||||
|
Err("Couldn't update post".to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub async fn edit_title_by_uuid(
|
||||||
|
mut db: Connection<Db>,
|
||||||
|
uuid: String,
|
||||||
|
new_title: String,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
match db
|
||||||
|
.execute(
|
||||||
|
sqlx::query("UPDATE posts SET title = $1 WHERE uuid = $2;")
|
||||||
|
.bind(new_title)
|
||||||
|
.bind(uuid),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
Err(why) => {
|
||||||
|
eprintln!("{why:?}");
|
||||||
|
Err("Couldn't update post".to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub async fn edit_title_by_text_id(
|
||||||
|
mut db: Connection<Db>,
|
||||||
|
text_id: String,
|
||||||
|
new_title: String,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
match db
|
||||||
|
.execute(
|
||||||
|
sqlx::query("UPDATE posts SET body = $1 WHERE text_id = $2;")
|
||||||
|
.bind(new_title)
|
||||||
|
.bind(text_id),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
Err(why) => {
|
||||||
|
eprintln!("{why:?}");
|
||||||
|
Err("Couldn't update post".to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub async fn edit_text_id(
|
||||||
|
mut db: Connection<Db>,
|
||||||
|
id: i32,
|
||||||
|
new_text_id: String,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
match db
|
||||||
|
.execute(
|
||||||
|
sqlx::query("UPDATE posts SET text_id = $1 WHERE id = $2;")
|
||||||
|
.bind(new_text_id)
|
||||||
|
.bind(id),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
Err(why) => {
|
||||||
|
eprintln!("{why:?}");
|
||||||
|
Err("Couldn't update post".to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub async fn edit_text_id_by_uuid(
|
||||||
|
mut db: Connection<Db>,
|
||||||
|
uuid: String,
|
||||||
|
new_text_id: String,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
match db
|
||||||
|
.execute(
|
||||||
|
sqlx::query("UPDATE posts SET text_id = $1 WHERE uuid = $2;")
|
||||||
|
.bind(new_text_id)
|
||||||
|
.bind(uuid),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
Err(why) => {
|
||||||
|
eprintln!("{why:?}");
|
||||||
|
Err("Couldn't update post".to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,193 @@
|
||||||
|
use crate::tables::Db;
|
||||||
|
use base64::engine::general_purpose;
|
||||||
|
use base64::Engine;
|
||||||
|
use rand::{RngCore, SeedableRng};
|
||||||
|
use regex::Regex;
|
||||||
|
use rocket::http::{Cookie, CookieJar};
|
||||||
|
use rocket_db_pools::sqlx::Executor;
|
||||||
|
use rocket_db_pools::sqlx::{self, Row};
|
||||||
|
use rocket_db_pools::Connection;
|
||||||
|
use sqlx::FromRow;
|
||||||
|
|
||||||
|
#[derive(FromRow, Debug)]
|
||||||
|
pub struct User {
|
||||||
|
pub id: i32,
|
||||||
|
pub username: String,
|
||||||
|
pub password: String,
|
||||||
|
pub token: Option<String>,
|
||||||
|
pub admin: bool,
|
||||||
|
pub make_posts: bool,
|
||||||
|
pub comment: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum LoginStatus {
|
||||||
|
InvalidToken,
|
||||||
|
NotLoggedIn,
|
||||||
|
LoggedIn(User),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl User {
|
||||||
|
pub async fn create(
|
||||||
|
db: &mut Connection<Db>,
|
||||||
|
username: &String,
|
||||||
|
password: &String,
|
||||||
|
) -> Result<String, String> {
|
||||||
|
match Regex::new(r"[^A-Za-z0-9_]") {
|
||||||
|
Ok(r) => {
|
||||||
|
match r.captures(username) {
|
||||||
|
Some(_) =>
|
||||||
|
Err("The username contains invalid characters. Only letters, numbers, and underscores are allowed.".to_string())
|
||||||
|
,
|
||||||
|
None => {
|
||||||
|
if username.len().gt(&32) || username.len().lt(&3) { // i can Never
|
||||||
|
// remember which symbol is which. this works better for me.
|
||||||
|
Err("Please choose a username between 3 and 32 characters.".to_string())
|
||||||
|
} else {
|
||||||
|
match db
|
||||||
|
.execute(
|
||||||
|
sqlx::query(
|
||||||
|
r#"
|
||||||
|
INSERT INTO users (username, password)
|
||||||
|
VALUES ($1, $2);
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.bind(username)
|
||||||
|
.bind(sha256::digest(password)),
|
||||||
|
).await
|
||||||
|
{
|
||||||
|
Ok(_) =>
|
||||||
|
Ok("Created user.".to_string())
|
||||||
|
,
|
||||||
|
Err(why) => {
|
||||||
|
eprintln!("Couldn't create database entry: {why:?}");
|
||||||
|
Err("Failed to create user.".to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(why) => {
|
||||||
|
eprintln!("Couldn't compile name regex: {why:?}");
|
||||||
|
Err("Couldn't compile name regex.".to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub async fn get_by_id(db: &mut Connection<Db>, id: i32) -> Option<User> {
|
||||||
|
match db
|
||||||
|
.fetch_one(sqlx::query("SELECT * FROM users WHERE id = $1;").bind(id))
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(user) => Some(User {
|
||||||
|
id: user.get::<i32, _>("id"),
|
||||||
|
username: user.get::<String, _>("username"),
|
||||||
|
password: user.get::<String, _>("password"),
|
||||||
|
token: user.get::<Option<String>, _>("token"),
|
||||||
|
admin: user.get::<bool, _>("admin"),
|
||||||
|
make_posts: user.get::<bool, _>("make_posts"),
|
||||||
|
comment: user.get::<bool, _>("comment"),
|
||||||
|
}),
|
||||||
|
Err(_) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub async fn get_by_token(db: &mut Connection<Db>, token: Cookie<'static>) -> Option<User> {
|
||||||
|
let to = token.to_string();
|
||||||
|
let mut fixed_token = to.split('=').collect::<Vec<&str>>();
|
||||||
|
fixed_token.reverse();
|
||||||
|
fixed_token.pop();
|
||||||
|
fixed_token.reverse();
|
||||||
|
let token_string = fixed_token.join("=");
|
||||||
|
|
||||||
|
match db
|
||||||
|
.fetch_one(sqlx::query("SELECT * FROM users WHERE token = $1;").bind(token_string))
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(user) => Some(User {
|
||||||
|
id: user.get::<i32, _>("id"),
|
||||||
|
username: user.get::<String, _>("username"),
|
||||||
|
password: user.get::<String, _>("password"),
|
||||||
|
token: user.get::<Option<String>, _>("token"),
|
||||||
|
admin: user.get::<bool, _>("admin"),
|
||||||
|
make_posts: user.get::<bool, _>("make_posts"),
|
||||||
|
comment: user.get::<bool, _>("comment"),
|
||||||
|
}),
|
||||||
|
Err(_) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub async fn get_by_username(db: &mut Connection<Db>, username: &String) -> Option<User> {
|
||||||
|
match db
|
||||||
|
.fetch_one(sqlx::query("SELECT * FROM users WHERE username = $1;").bind(username))
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(user) => Some(User {
|
||||||
|
id: user.get::<i32, _>("id"),
|
||||||
|
username: user.get::<String, _>("username"),
|
||||||
|
password: user.get::<String, _>("password"),
|
||||||
|
token: user.get::<Option<String>, _>("token"),
|
||||||
|
admin: user.get::<bool, _>("admin"),
|
||||||
|
make_posts: user.get::<bool, _>("make_posts"),
|
||||||
|
comment: user.get::<bool, _>("comment"),
|
||||||
|
}),
|
||||||
|
Err(_) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub async fn set_new_token(&self, db: &mut Connection<Db>) -> Result<String, String> {
|
||||||
|
let token_end = format!("{}", rand_hc::Hc128Rng::from_entropy().next_u64());
|
||||||
|
let token_start = sha256::digest(&self.username);
|
||||||
|
|
||||||
|
let token = format!(
|
||||||
|
"{}-{}",
|
||||||
|
general_purpose::STANDARD.encode(token_start),
|
||||||
|
general_purpose::STANDARD.encode(token_end)
|
||||||
|
);
|
||||||
|
|
||||||
|
match db
|
||||||
|
.execute(
|
||||||
|
sqlx::query("UPDATE users SET token = $1 WHERE id = $2")
|
||||||
|
.bind(&token)
|
||||||
|
.bind(self.id),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(_) => Ok(token),
|
||||||
|
Err(why) => Err(why.to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn set_role(
|
||||||
|
&self,
|
||||||
|
db: &mut Connection<Db>,
|
||||||
|
role: &String,
|
||||||
|
value: &bool,
|
||||||
|
) -> Result<String, String> {
|
||||||
|
let mut sql = String::from("UPDATE users SET {{perm}} = $1 WHERE id = $2");
|
||||||
|
if role == "admin" {
|
||||||
|
sql = sql.replace("{{perm}}", "admin");
|
||||||
|
} else if role == "make_posts" {
|
||||||
|
sql = sql.replace("{{perm}}", "make_posts");
|
||||||
|
} else if role == &"comment".to_string() {
|
||||||
|
sql = sql.replace("{{perm}}", "comment");
|
||||||
|
}
|
||||||
|
if sql.contains("{{perm}}") {
|
||||||
|
Err("Invalid role.".to_string())
|
||||||
|
} else {
|
||||||
|
match db
|
||||||
|
.execute(sqlx::query(&sql[..]).bind(value).bind(self.id))
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(_) => Ok("Succesfully updated role.".to_string()),
|
||||||
|
Err(why) => Err(why.to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn login_status(db: &mut Connection<Db>, cookies: &CookieJar<'_>) -> LoginStatus {
|
||||||
|
match cookies.get_private("token") {
|
||||||
|
Some(t) => match User::get_by_token(db, t).await {
|
||||||
|
Some(user) => LoginStatus::LoggedIn(user),
|
||||||
|
None => LoginStatus::InvalidToken,
|
||||||
|
},
|
||||||
|
None => LoginStatus::NotLoggedIn,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue