SQL improvements
This commit is contained in:
parent
467c00410c
commit
9133d1ea9e
|
@ -15,6 +15,8 @@ mod config;
|
|||
mod error;
|
||||
mod ipfs;
|
||||
mod lib;
|
||||
mod models;
|
||||
mod sql;
|
||||
mod v1;
|
||||
|
||||
#[derive(StructOpt)]
|
||||
|
|
41
src/models.rs
Normal file
41
src/models.rs
Normal file
|
@ -0,0 +1,41 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct Meme {
|
||||
pub id: i32,
|
||||
pub filename: String,
|
||||
pub userid: String,
|
||||
pub username: String,
|
||||
pub category: String,
|
||||
pub timestamp: i64,
|
||||
pub ipfs: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct Category {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct User {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
pub userdir: String,
|
||||
pub tokenhash: String,
|
||||
pub dayuploads: i32,
|
||||
}
|
||||
|
||||
pub enum UserIdentifier {
|
||||
Id(String),
|
||||
Token(String),
|
||||
Username(String),
|
||||
Null,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct MemeFilter {
|
||||
pub category: Option<String>,
|
||||
pub user: Option<String>,
|
||||
pub search: Option<String>,
|
||||
}
|
145
src/sql.rs
Normal file
145
src/sql.rs
Normal file
|
@ -0,0 +1,145 @@
|
|||
use crate::ipfs::IPFSFile;
|
||||
use crate::models::{Category, Meme, MemeFilter, User, UserIdentifier};
|
||||
use sqlx::mysql::MySqlRow;
|
||||
use sqlx::{MySqlPool, Result, Row};
|
||||
|
||||
impl Meme {
|
||||
pub async fn get(id: i32, pool: &MySqlPool) -> Result<Option<Self>> {
|
||||
let q: Option<Self> = sqlx::query("SELECT memes.id, user, filename, category, name, UNIX_TIMESTAMP(timestamp) AS ts, cid FROM memes, users WHERE memes.user = users.id AND memes.id=?").bind(id)
|
||||
.map(|row: MySqlRow| Self {
|
||||
id: row.get("id"),
|
||||
filename: row.get("filename"),
|
||||
username: row.get("name"),
|
||||
userid: row.get("user"),
|
||||
category: row.get("category"),
|
||||
timestamp: row.get("ts"),
|
||||
ipfs: row.get("cid"),
|
||||
})
|
||||
.fetch_optional(pool).await?;
|
||||
Ok(q)
|
||||
}
|
||||
|
||||
pub async fn get_all(filter: MemeFilter, pool: &MySqlPool) -> Result<Vec<Self>> {
|
||||
let q: Vec<Self> = sqlx::query("SELECT memes.id, user, filename, category, name, UNIX_TIMESTAMP(timestamp) AS ts, cid FROM memes, users WHERE memes.user = users.id AND (category LIKE ? AND name LIKE ? AND filename LIKE ?) ORDER BY memes.id")
|
||||
.bind(filter.category.unwrap_or_else(|| String::from("%")))
|
||||
.bind(format!("%{}%", filter.user.unwrap_or_else(String::new)))
|
||||
.bind(format!("%{}%", filter.search.unwrap_or_else(String::new)))
|
||||
.map(|row: MySqlRow| Self {
|
||||
id: row.get("id"),
|
||||
filename: row.get("filename"),
|
||||
username: row.get("name"),
|
||||
userid: row.get("user"),
|
||||
category: row.get("category"),
|
||||
timestamp: row.get("ts"),
|
||||
ipfs: row.get("cid"),
|
||||
})
|
||||
.fetch_all(pool).await?;
|
||||
Ok(q)
|
||||
}
|
||||
|
||||
pub async fn get_random(filter: MemeFilter, pool: &MySqlPool) -> Result<Self> {
|
||||
let q: Self = sqlx::query("SELECT memes.id, user, filename, category, name, UNIX_TIMESTAMP(timestamp) AS ts, cid FROM memes, users WHERE memes.user = users.id AND (category LIKE ? AND name LIKE ? AND filename LIKE ?) ORDER BY RAND() LIMIT 1")
|
||||
.bind(filter.category.unwrap_or_else(|| String::from("%")))
|
||||
.bind(format!("%{}%", filter.user.unwrap_or_else(String::new)))
|
||||
.bind(format!("%{}%", filter.search.unwrap_or_else(String::new)))
|
||||
.map(|row: MySqlRow| Self {
|
||||
id: row.get("id"),
|
||||
filename: row.get("filename"),
|
||||
username: row.get("name"),
|
||||
userid: row.get("user"),
|
||||
category: row.get("category"),
|
||||
timestamp: row.get("ts"),
|
||||
ipfs: row.get("cid"),
|
||||
})
|
||||
.fetch_one(pool).await?;
|
||||
Ok(q)
|
||||
}
|
||||
}
|
||||
|
||||
impl Category {
|
||||
pub async fn get(id: &String, pool: &MySqlPool) -> Result<Option<Self>> {
|
||||
let q: Option<Self> = sqlx::query("SELECT * FROM categories WHERE id=?")
|
||||
.bind(id)
|
||||
.map(|row: MySqlRow| Self {
|
||||
id: row.get("id"),
|
||||
name: row.get("name"),
|
||||
})
|
||||
.fetch_optional(pool)
|
||||
.await?;
|
||||
Ok(q)
|
||||
}
|
||||
|
||||
pub async fn get_all(pool: &MySqlPool) -> Result<Vec<Self>> {
|
||||
let q: Vec<Self> = sqlx::query("SELECT * FROM categories ORDER BY num")
|
||||
.map(|row: MySqlRow| Self {
|
||||
id: row.get("id"),
|
||||
name: row.get("name"),
|
||||
})
|
||||
.fetch_all(pool)
|
||||
.await?;
|
||||
Ok(q)
|
||||
}
|
||||
|
||||
pub async fn add_meme(
|
||||
&self,
|
||||
user: &User,
|
||||
file: &IPFSFile,
|
||||
ip: &String,
|
||||
pool: &MySqlPool,
|
||||
) -> Result<u64> {
|
||||
let mut tx = pool.begin().await?;
|
||||
sqlx::query("INSERT INTO memes (filename, user, category, timestamp, ip, cid) VALUES (?, ?, ?, NOW(), ?, ?)")
|
||||
.bind(&file.name)
|
||||
.bind(&user.id)
|
||||
.bind(&self.id)
|
||||
.bind(ip)
|
||||
.bind(&file.hash)
|
||||
.execute(&mut tx).await?;
|
||||
let id: u64 = sqlx::query("SELECT LAST_INSERT_ID() as id")
|
||||
.map(|row: MySqlRow| row.get("id"))
|
||||
.fetch_one(&mut tx)
|
||||
.await?;
|
||||
tx.commit().await?;
|
||||
Ok(id)
|
||||
}
|
||||
}
|
||||
|
||||
impl User {
|
||||
pub async fn get(identifier: UserIdentifier, pool: &MySqlPool) -> Result<Option<Self>> {
|
||||
let query = match identifier {
|
||||
UserIdentifier::Id(id) => sqlx::query("SELECT id, name, IFNULL(MD5(token), '0') AS hash, uploads FROM (SELECT id, name, IFNULL(count.uploads, 0) AS uploads FROM users LEFT JOIN (SELECT user, COUNT(*) AS uploads FROM memes WHERE DATE(timestamp) = CURDATE() GROUP BY (user)) AS count ON users.id = count.user) AS users LEFT JOIN token ON users.id = token.uid WHERE users.id = ?").bind(id),
|
||||
UserIdentifier::Token(token) => sqlx::query("SELECT id, name, IFNULL(MD5(token), '0') AS hash, uploads FROM (SELECT id, name, IFNULL(count.uploads, 0) AS uploads FROM users LEFT JOIN (SELECT user, COUNT(*) AS uploads FROM memes WHERE DATE(timestamp) = CURDATE() GROUP BY (user)) AS count ON users.id = count.user) AS users LEFT JOIN token ON users.id = token.uid WHERE token = ?").bind(token),
|
||||
UserIdentifier::Username(name) => sqlx::query("SELECT id, name, IFNULL(MD5(token), '0') AS hash, uploads FROM (SELECT id, name, IFNULL(count.uploads, 0) AS uploads FROM users LEFT JOIN (SELECT user, COUNT(*) AS uploads FROM memes WHERE DATE(timestamp) = CURDATE() GROUP BY (user)) AS count ON users.id = count.user) AS users LEFT JOIN token ON users.id = token.uid WHERE name = ?").bind(name),
|
||||
UserIdentifier::Null => sqlx::query("SELECT id, name, '0' AS hash, 0 AS uploads FROM users WHERE id = '000'"),
|
||||
};
|
||||
let q: Option<Self> = query
|
||||
.map(|row: MySqlRow| Self {
|
||||
id: row.get("id"),
|
||||
name: row.get("name"),
|
||||
userdir: row.get("id"),
|
||||
tokenhash: row.get("hash"),
|
||||
dayuploads: row.get("uploads"),
|
||||
})
|
||||
.fetch_optional(pool)
|
||||
.await?;
|
||||
Ok(q)
|
||||
}
|
||||
|
||||
pub async fn get_all(pool: &MySqlPool) -> Result<Vec<Self>> {
|
||||
let q: Vec<Self> = sqlx::query("SELECT id, name, IFNULL(MD5(token), '0') AS hash, uploads FROM (SELECT id, name, IFNULL(count.uploads, 0) AS uploads FROM users LEFT JOIN (SELECT user, COUNT(*) AS uploads FROM memes WHERE DATE(timestamp) = CURDATE() GROUP BY (user)) AS count ON users.id = count.user) AS users LEFT JOIN token ON users.id = token.uid")
|
||||
.map(|row: MySqlRow| Self {
|
||||
id: row.get("id"),
|
||||
name: row.get("name"),
|
||||
userdir: row.get("id"),
|
||||
tokenhash: row.get("hash"),
|
||||
dayuploads: row.get("uploads"),
|
||||
})
|
||||
.fetch_all(pool).await?;
|
||||
Ok(q)
|
||||
}
|
||||
|
||||
pub async fn check_token(token: &String, pool: &MySqlPool) -> Result<Option<Self>> {
|
||||
let user = Self::get(UserIdentifier::Token(token.clone()), pool).await?;
|
||||
Ok(user)
|
||||
}
|
||||
}
|
|
@ -25,6 +25,8 @@ pub enum APIError {
|
|||
#[error("{0}")]
|
||||
Forbidden(String),
|
||||
#[error("{0}")]
|
||||
NotFound(String),
|
||||
#[error("{0}")]
|
||||
Internal(String),
|
||||
#[error("IPFS error: {0}")]
|
||||
Ipfs(#[from] IPFSError),
|
||||
|
@ -57,6 +59,7 @@ impl IntoResponse for APIError {
|
|||
APIError::BadRequest(err) => ErrorResponse::new(StatusCode::BAD_REQUEST, Some(err)),
|
||||
APIError::Unauthorized(err) => ErrorResponse::new(StatusCode::UNAUTHORIZED, Some(err)),
|
||||
APIError::Forbidden(err) => ErrorResponse::new(StatusCode::FORBIDDEN, Some(err)),
|
||||
APIError::NotFound(err) => ErrorResponse::new(StatusCode::NOT_FOUND, Some(err)),
|
||||
APIError::Internal(err) => {
|
||||
ErrorResponse::new(StatusCode::INTERNAL_SERVER_ERROR, Some(err))
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
mod error;
|
||||
pub mod models;
|
||||
mod routes;
|
||||
mod sql;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use axum::extract::{FromRequest, RequestParts};
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use reqwest::StatusCode;
|
||||
use serde::{Deserialize, Serialize, Serializer};
|
||||
|
||||
use crate::models::{Category, Meme, User, UserIdentifier};
|
||||
|
||||
fn serialize_status<S>(x: &StatusCode, s: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
|
@ -9,7 +11,7 @@ where
|
|||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct Meme {
|
||||
pub struct V1Meme {
|
||||
pub id: String,
|
||||
pub link: String,
|
||||
pub category: String,
|
||||
|
@ -18,35 +20,20 @@ pub struct Meme {
|
|||
pub ipfs: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct Category {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct User {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
pub userdir: String,
|
||||
pub tokenhash: String,
|
||||
pub dayuploads: i32,
|
||||
}
|
||||
|
||||
//Responses
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct MemesResponse {
|
||||
pub status: i32,
|
||||
pub error: Option<String>,
|
||||
pub memes: Option<Vec<Meme>>,
|
||||
pub memes: Option<Vec<V1Meme>>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct MemeResponse {
|
||||
pub status: i32,
|
||||
pub error: Option<String>,
|
||||
pub meme: Option<Meme>,
|
||||
pub meme: Option<V1Meme>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
|
@ -111,9 +98,29 @@ pub struct UserIDQuery {
|
|||
pub name: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct MemeFilterQuery {
|
||||
pub category: Option<String>,
|
||||
pub user: Option<String>,
|
||||
pub search: Option<String>,
|
||||
impl V1Meme {
|
||||
pub fn new(meme: Meme, cdn: String) -> Self {
|
||||
Self {
|
||||
id: meme.id.to_string(),
|
||||
link: format!("{}/{}/{}", cdn, meme.userid, meme.filename),
|
||||
category: meme.category,
|
||||
user: meme.username,
|
||||
timestamp: meme.timestamp.to_string(),
|
||||
ipfs: meme.ipfs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<UserIDQuery> for UserIdentifier {
|
||||
fn from(query: UserIDQuery) -> Self {
|
||||
if let Some(id) = query.id {
|
||||
Self::Id(id)
|
||||
} else if let Some(token) = query.token {
|
||||
Self::Token(token)
|
||||
} else if let Some(name) = query.name {
|
||||
Self::Username(name)
|
||||
} else {
|
||||
Self::Null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use crate::config::ConfVars;
|
||||
use crate::ipfs::IPFSFile;
|
||||
use crate::lib::ExtractIP;
|
||||
use crate::models::{Category, Meme, MemeFilter, User};
|
||||
use crate::v1::models::*;
|
||||
|
||||
use axum::extract::{ContentLengthLimit, Extension, Multipart};
|
||||
|
@ -19,7 +20,12 @@ async fn meme(
|
|||
Extension(db_pool): Extension<MySqlPool>,
|
||||
Extension(vars): Extension<ConfVars>,
|
||||
) -> Result<impl IntoResponse, APIError> {
|
||||
let meme = Meme::get(params.id, &db_pool, vars.cdn).await?;
|
||||
let meme = V1Meme::new(
|
||||
Meme::get(params.id, &db_pool)
|
||||
.await?
|
||||
.ok_or_else(|| APIError::NotFound("Meme not found".to_string()))?,
|
||||
vars.cdn,
|
||||
);
|
||||
Ok(Json(MemeResponse {
|
||||
status: 200,
|
||||
error: None,
|
||||
|
@ -28,11 +34,15 @@ async fn meme(
|
|||
}
|
||||
|
||||
async fn memes(
|
||||
Query(params): Query<MemeFilterQuery>,
|
||||
Query(params): Query<MemeFilter>,
|
||||
Extension(db_pool): Extension<MySqlPool>,
|
||||
Extension(vars): Extension<ConfVars>,
|
||||
) -> Result<impl IntoResponse, APIError> {
|
||||
let memes = Meme::get_all(params, &db_pool, vars.cdn).await?;
|
||||
let memes = Meme::get_all(params, &db_pool)
|
||||
.await?
|
||||
.into_iter()
|
||||
.map(|meme| V1Meme::new(meme, vars.cdn.clone()))
|
||||
.collect();
|
||||
Ok(Json(MemesResponse {
|
||||
status: 200,
|
||||
error: None,
|
||||
|
@ -44,7 +54,9 @@ async fn category(
|
|||
Query(params): Query<IDQuery>,
|
||||
Extension(db_pool): Extension<MySqlPool>,
|
||||
) -> Result<impl IntoResponse, APIError> {
|
||||
let category = Category::get(¶ms.id, &db_pool).await?;
|
||||
let category = Category::get(¶ms.id, &db_pool)
|
||||
.await?
|
||||
.ok_or_else(|| APIError::NotFound("Category not found".to_string()))?;
|
||||
Ok(Json(CategoryResponse {
|
||||
status: 200,
|
||||
error: None,
|
||||
|
@ -67,7 +79,9 @@ async fn user(
|
|||
Query(params): Query<UserIDQuery>,
|
||||
Extension(db_pool): Extension<MySqlPool>,
|
||||
) -> Result<impl IntoResponse, APIError> {
|
||||
let user = User::get(params, &db_pool).await?;
|
||||
let user = User::get(params.into(), &db_pool)
|
||||
.await?
|
||||
.ok_or_else(|| APIError::NotFound("User not found".to_string()))?;
|
||||
Ok(Json(UserResponse {
|
||||
status: 200,
|
||||
error: None,
|
||||
|
@ -85,11 +99,11 @@ async fn users(Extension(db_pool): Extension<MySqlPool>) -> Result<impl IntoResp
|
|||
}
|
||||
|
||||
async fn random(
|
||||
Query(params): Query<MemeFilterQuery>,
|
||||
Query(params): Query<MemeFilter>,
|
||||
Extension(db_pool): Extension<MySqlPool>,
|
||||
Extension(vars): Extension<ConfVars>,
|
||||
) -> Result<impl IntoResponse, APIError> {
|
||||
let random = Meme::get_random(params, &db_pool, vars.cdn).await?;
|
||||
let random = V1Meme::new(Meme::get_random(params, &db_pool).await?, vars.cdn);
|
||||
Ok(Json(MemeResponse {
|
||||
status: 200,
|
||||
error: None,
|
||||
|
@ -140,7 +154,9 @@ async fn upload(
|
|||
return Err(APIError::Forbidden("Upload limit reached".to_string()));
|
||||
}
|
||||
|
||||
let cat = Category::get(&category, &db_pool).await?;
|
||||
let cat = Category::get(&category, &db_pool)
|
||||
.await?
|
||||
.ok_or_else(|| APIError::BadRequest("Category not existing".to_string()))?;
|
||||
|
||||
let ip = ip.to_string();
|
||||
|
||||
|
|
179
src/v1/sql.rs
179
src/v1/sql.rs
|
@ -1,179 +0,0 @@
|
|||
use crate::ipfs::IPFSFile;
|
||||
use crate::v1::models::{Category, Meme, MemeFilterQuery, User, UserIDQuery};
|
||||
use sqlx::mysql::MySqlRow;
|
||||
use sqlx::{MySqlPool, Result, Row};
|
||||
|
||||
pub struct DBMeme {
|
||||
pub id: i32,
|
||||
pub filename: String,
|
||||
pub user: String,
|
||||
pub userdir: String,
|
||||
pub category: String,
|
||||
pub timestamp: i64,
|
||||
pub ipfs: String,
|
||||
}
|
||||
|
||||
impl Meme {
|
||||
pub fn new(meme: DBMeme, cdn: String) -> Self {
|
||||
Self {
|
||||
id: meme.id.to_string(),
|
||||
link: format!("{}/{}/{}", cdn, meme.userdir, meme.filename),
|
||||
category: meme.category,
|
||||
user: meme.user,
|
||||
timestamp: meme.timestamp.to_string(),
|
||||
ipfs: meme.ipfs,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get(id: i32, pool: &MySqlPool, cdn: String) -> Result<Meme> {
|
||||
let q: Self = sqlx::query("SELECT memes.id, user, filename, category, name, UNIX_TIMESTAMP(timestamp) AS ts, cid FROM memes, users WHERE memes.user = users.id AND memes.id=?").bind(id)
|
||||
.map(|row: MySqlRow| Self::new(DBMeme {
|
||||
id: row.get("id"),
|
||||
filename: row.get("filename"),
|
||||
user: row.get("name"),
|
||||
userdir: row.get("user"),
|
||||
category: row.get("category"),
|
||||
timestamp: row.get("ts"),
|
||||
ipfs: row.get("cid"),
|
||||
}, cdn.clone()))
|
||||
.fetch_one(pool).await?;
|
||||
Ok(q)
|
||||
}
|
||||
|
||||
pub async fn get_all(
|
||||
params: MemeFilterQuery,
|
||||
pool: &MySqlPool,
|
||||
cdn: String,
|
||||
) -> Result<Vec<Self>> {
|
||||
let q: Vec<Meme> = sqlx::query("SELECT memes.id, user, filename, category, name, UNIX_TIMESTAMP(timestamp) AS ts, cid FROM memes, users WHERE memes.user = users.id AND (category LIKE ? AND name LIKE ? AND filename LIKE ?) ORDER BY memes.id")
|
||||
.bind(params.category.unwrap_or_else(|| String::from("%")))
|
||||
.bind(format!("%{}%", params.user.unwrap_or_else(String::new)))
|
||||
.bind(format!("%{}%", params.search.unwrap_or_else(String::new)))
|
||||
.map(|row: MySqlRow| Self::new(DBMeme {
|
||||
id: row.get("id"),
|
||||
filename: row.get("filename"),
|
||||
user: row.get("name"),
|
||||
userdir: row.get("user"),
|
||||
category: row.get("category"),
|
||||
timestamp: row.get("ts"),
|
||||
ipfs: row.get("cid"),
|
||||
}, cdn.clone()))
|
||||
.fetch_all(pool).await?;
|
||||
Ok(q)
|
||||
}
|
||||
|
||||
pub async fn get_random(
|
||||
params: MemeFilterQuery,
|
||||
pool: &MySqlPool,
|
||||
cdn: String,
|
||||
) -> Result<Self> {
|
||||
let q: Meme = sqlx::query("SELECT memes.id, user, filename, category, name, UNIX_TIMESTAMP(timestamp) AS ts, cid FROM memes, users WHERE memes.user = users.id AND (category LIKE ? AND name LIKE ? AND filename LIKE ?) ORDER BY RAND() LIMIT 1")
|
||||
.bind(params.category.unwrap_or_else(|| String::from("%")))
|
||||
.bind(format!("%{}%", params.user.unwrap_or_else(String::new)))
|
||||
.bind(format!("%{}%", params.search.unwrap_or_else(String::new)))
|
||||
.map(|row: MySqlRow| Self::new(DBMeme {
|
||||
id: row.get("id"),
|
||||
filename: row.get("filename"),
|
||||
user: row.get("name"),
|
||||
userdir: row.get("user"),
|
||||
category: row.get("category"),
|
||||
timestamp: row.get("ts"),
|
||||
ipfs: row.get("cid"),
|
||||
}, cdn.clone()))
|
||||
.fetch_one(pool).await?;
|
||||
Ok(q)
|
||||
}
|
||||
}
|
||||
|
||||
impl Category {
|
||||
pub async fn get(id: &String, pool: &MySqlPool) -> Result<Self> {
|
||||
let q: Category = sqlx::query("SELECT * FROM categories WHERE id=?")
|
||||
.bind(id)
|
||||
.map(|row: MySqlRow| Self {
|
||||
id: row.get("id"),
|
||||
name: row.get("name"),
|
||||
})
|
||||
.fetch_one(pool)
|
||||
.await?;
|
||||
Ok(q)
|
||||
}
|
||||
|
||||
pub async fn get_all(pool: &MySqlPool) -> Result<Vec<Self>> {
|
||||
let q: Vec<Category> = sqlx::query("SELECT * FROM categories ORDER BY num")
|
||||
.map(|row: MySqlRow| Self {
|
||||
id: row.get("id"),
|
||||
name: row.get("name"),
|
||||
})
|
||||
.fetch_all(pool)
|
||||
.await?;
|
||||
Ok(q)
|
||||
}
|
||||
|
||||
pub async fn add_meme(
|
||||
&self,
|
||||
user: &User,
|
||||
file: &IPFSFile,
|
||||
ip: &String,
|
||||
pool: &MySqlPool,
|
||||
) -> Result<u64> {
|
||||
let mut tx = pool.begin().await?;
|
||||
sqlx::query("INSERT INTO memes (filename, user, category, timestamp, ip, cid) VALUES (?, ?, ?, NOW(), ?, ?)")
|
||||
.bind(&file.name)
|
||||
.bind(&user.id)
|
||||
.bind(&self.id)
|
||||
.bind(ip)
|
||||
.bind(&file.hash)
|
||||
.execute(&mut tx).await?;
|
||||
let id: u64 = sqlx::query("SELECT LAST_INSERT_ID() as id")
|
||||
.map(|row: MySqlRow| row.get("id"))
|
||||
.fetch_one(&mut tx)
|
||||
.await?;
|
||||
tx.commit().await?;
|
||||
Ok(id)
|
||||
}
|
||||
}
|
||||
|
||||
impl User {
|
||||
pub async fn get(params: UserIDQuery, pool: &MySqlPool) -> Result<Self> {
|
||||
let q: User = sqlx::query("SELECT id, name, MD5(token) AS hash, uploads FROM (SELECT id, name, IFNULL(count.uploads, 0) AS uploads FROM users LEFT JOIN (SELECT user, COUNT(*) AS uploads FROM memes WHERE DATE(timestamp) = CURDATE() GROUP BY (user)) AS count ON users.id = count.user) AS users, token WHERE users.id = token.uid AND (users.id LIKE ? OR token LIKE ? OR name LIKE ?) UNION SELECT id, name, 0 AS hash, 0 AS uploads FROM users WHERE id = '000'")
|
||||
.bind(params.id.unwrap_or_else(String::new))
|
||||
.bind(params.token.unwrap_or_else(String::new))
|
||||
.bind(params.name.unwrap_or_else(String::new))
|
||||
.map(|row: MySqlRow| Self {
|
||||
id: row.get("id"),
|
||||
name: row.get("name"),
|
||||
userdir: row.get("id"),
|
||||
tokenhash: row.get("hash"),
|
||||
dayuploads: row.get("uploads"),
|
||||
})
|
||||
.fetch_one(pool).await?;
|
||||
Ok(q)
|
||||
}
|
||||
|
||||
pub async fn get_all(pool: &MySqlPool) -> Result<Vec<Self>> {
|
||||
let q: Vec<User> = sqlx::query("SELECT id, name, MD5(token) AS hash, uploads FROM (SELECT id, name, IFNULL(count.uploads, 0) AS uploads FROM users LEFT JOIN (SELECT user, COUNT(*) AS uploads FROM memes WHERE DATE(timestamp) = CURDATE() GROUP BY (user)) AS count ON users.id = count.user) AS users, token WHERE users.id = token.uid UNION SELECT id, name, 0 AS hash, 0 AS uploads FROM users WHERE id = '000'")
|
||||
.map(|row: MySqlRow| Self {
|
||||
id: row.get("id"),
|
||||
name: row.get("name"),
|
||||
userdir: row.get("id"),
|
||||
tokenhash: row.get("hash"),
|
||||
dayuploads: row.get("uploads"),
|
||||
})
|
||||
.fetch_all(pool).await?;
|
||||
Ok(q)
|
||||
}
|
||||
|
||||
pub async fn check_token(token: &String, pool: &MySqlPool) -> Result<Option<Self>> {
|
||||
let q: Option<User> = sqlx::query("SELECT id, name, MD5(token) AS hash, uploads FROM (SELECT id, name, IFNULL(count.uploads, 0) AS uploads FROM users LEFT JOIN (SELECT user, COUNT(*) AS uploads FROM memes WHERE DATE(timestamp) = CURDATE() GROUP BY (user)) AS count ON users.id = count.user) AS users, token WHERE users.id = token.uid AND token = ?")
|
||||
.bind(token)
|
||||
.map(|row: MySqlRow| Self {
|
||||
id: row.get("id"),
|
||||
name: row.get("name"),
|
||||
userdir: row.get("id"),
|
||||
tokenhash: row.get("hash"),
|
||||
dayuploads: row.get("uploads"),
|
||||
})
|
||||
.fetch_optional(pool).await?;
|
||||
Ok(q)
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue