feat: support upload files & adjust output
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,6 +1,9 @@
|
||||
# --> sqlite3
|
||||
*.db
|
||||
|
||||
# user files
|
||||
/user_files
|
||||
|
||||
# ---> Rust
|
||||
# Generated by Cargo
|
||||
# will have compiled files and executables
|
||||
|
||||
2
Rocket.toml
Normal file
2
Rocket.toml
Normal file
@@ -0,0 +1,2 @@
|
||||
[default]
|
||||
limits = { file = "200MB", files = "200MB" }
|
||||
@@ -5,7 +5,6 @@ use crate::models::*;
|
||||
use crate::rds_conn::RdsConn;
|
||||
use crate::rds_models::*;
|
||||
use crate::schema;
|
||||
use chrono::{offset::Utc, DateTime};
|
||||
use diesel::{ExpressionMethods, QueryDsl, RunQueryDsl};
|
||||
use rocket::form::Form;
|
||||
use rocket::futures::future;
|
||||
@@ -30,7 +29,7 @@ pub struct CommentOutput {
|
||||
can_del: bool,
|
||||
name_id: i32,
|
||||
is_tmp: bool,
|
||||
create_time: DateTime<Utc>,
|
||||
create_time: i64,
|
||||
is_blocked: bool,
|
||||
blocked_count: Option<i32>,
|
||||
// for old version frontend
|
||||
@@ -61,19 +60,16 @@ pub async fn c2output<'r>(
|
||||
BlockedUsers::check_blocked(rconn, user.id, &user.namehash, &c.author_hash)
|
||||
.await
|
||||
.unwrap_or_default();
|
||||
let can_view = !is_blocked && user.id.is_some() || user.namehash.eq(&c.author_hash);
|
||||
let can_view = user.is_admin
|
||||
|| (!is_blocked && user.id.is_some() || user.namehash.eq(&c.author_hash));
|
||||
Some(CommentOutput {
|
||||
cid: c.id,
|
||||
text: format!(
|
||||
"{}{}",
|
||||
if c.is_tmp { "[tmp]\n" } else { "" },
|
||||
if can_view { &c.content } else { "" }
|
||||
),
|
||||
text: (if can_view { &c.content } else { "" }).to_string(),
|
||||
author_title: c.author_title.to_string(),
|
||||
can_del: c.check_permission(user, "wd").is_ok(),
|
||||
name_id: name_id,
|
||||
is_tmp: c.is_tmp,
|
||||
create_time: c.create_time,
|
||||
create_time: c.create_time.timestamp(),
|
||||
is_blocked: is_blocked,
|
||||
blocked_count: if user.is_admin {
|
||||
BlockCounter::get_count(rconn, &c.author_hash).await.ok()
|
||||
|
||||
@@ -25,6 +25,13 @@ macro_rules! code0 {
|
||||
);
|
||||
}
|
||||
|
||||
macro_rules! e2s {
|
||||
($e:expr) => (json!({
|
||||
"code": -1,
|
||||
"msg": $e.to_string()
|
||||
}));
|
||||
}
|
||||
|
||||
#[catch(401)]
|
||||
pub fn catch_401_error() -> &'static str {
|
||||
"未登录或token过期"
|
||||
@@ -100,21 +107,15 @@ pub enum APIError {
|
||||
DbError(diesel::result::Error),
|
||||
RdsError(redis::RedisError),
|
||||
PcError(PolicyError),
|
||||
IoError(std::io::Error),
|
||||
}
|
||||
|
||||
impl<'r> Responder<'r, 'static> for APIError {
|
||||
fn respond_to(self, req: &'r Request<'_>) -> response::Result<'static> {
|
||||
match self {
|
||||
APIError::DbError(e) => json!({
|
||||
"code": -1,
|
||||
"msg": e.to_string()
|
||||
})
|
||||
.respond_to(req),
|
||||
APIError::RdsError(e) => json!({
|
||||
"code": -1,
|
||||
"msg": e.to_string()
|
||||
})
|
||||
.respond_to(req),
|
||||
APIError::DbError(e) => e2s!(e).respond_to(req),
|
||||
APIError::RdsError(e) => e2s!(e).respond_to(req),
|
||||
APIError::IoError(e) => e2s!(e).respond_to(req),
|
||||
APIError::PcError(e) => json!({
|
||||
"code": -1,
|
||||
"msg": match e {
|
||||
@@ -142,6 +143,12 @@ impl From<redis::RedisError> for APIError {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for APIError {
|
||||
fn from(err: std::io::Error) -> APIError {
|
||||
APIError::IoError(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PolicyError> for APIError {
|
||||
fn from(err: PolicyError) -> APIError {
|
||||
APIError::PcError(err)
|
||||
@@ -237,4 +244,5 @@ pub mod operation;
|
||||
pub mod post;
|
||||
pub mod search;
|
||||
pub mod systemlog;
|
||||
pub mod upload;
|
||||
pub mod vote;
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
use crate::api::comment::{c2output, CommentOutput};
|
||||
use crate::api::vote::get_poll_dict;
|
||||
use crate::api::{CurrentUser, JsonAPI, UGC, PolicyError::*};
|
||||
use crate::api::{CurrentUser, JsonAPI, PolicyError::*, UGC};
|
||||
use crate::db_conn::Db;
|
||||
use crate::libs::diesel_logger::LoggingConnection;
|
||||
use crate::models::*;
|
||||
use crate::rds_conn::RdsConn;
|
||||
use crate::rds_models::*;
|
||||
use crate::schema;
|
||||
use chrono::{offset::Utc, DateTime};
|
||||
use diesel::{ExpressionMethods, QueryDsl, RunQueryDsl};
|
||||
use rocket::form::Form;
|
||||
use rocket::futures::future;
|
||||
@@ -38,8 +37,8 @@ pub struct PostOutput {
|
||||
is_tmp: bool,
|
||||
n_attentions: i32,
|
||||
n_comments: i32,
|
||||
create_time: DateTime<Utc>,
|
||||
last_comment_time: DateTime<Utc>,
|
||||
create_time: i64,
|
||||
last_comment_time: i64,
|
||||
allow_search: bool,
|
||||
is_reported: Option<bool>,
|
||||
comments: Option<Vec<CommentOutput>>,
|
||||
@@ -67,19 +66,16 @@ async fn p2output(p: &Post, user: &CurrentUser, db: &Db, rconn: &RdsConn) -> Pos
|
||||
let is_blocked = BlockedUsers::check_blocked(rconn, user.id, &user.namehash, &p.author_hash)
|
||||
.await
|
||||
.unwrap_or_default();
|
||||
let can_view = !is_blocked && user.id.is_some() || user.namehash.eq(&p.author_hash);
|
||||
let can_view =
|
||||
user.is_admin || (!is_blocked && user.id.is_some() || user.namehash.eq(&p.author_hash));
|
||||
PostOutput {
|
||||
pid: p.id,
|
||||
text: format!(
|
||||
"{}{}",
|
||||
if p.is_tmp { "[tmp]\n" } else { "" },
|
||||
if can_view { &p.content } else { "" }
|
||||
),
|
||||
text: (if can_view { &p.content } else { "" }).to_string(),
|
||||
cw: (!p.cw.is_empty()).then(|| p.cw.to_string()),
|
||||
n_attentions: p.n_attentions,
|
||||
n_comments: p.n_comments,
|
||||
create_time: p.create_time,
|
||||
last_comment_time: p.last_comment_time,
|
||||
create_time: p.create_time.timestamp(),
|
||||
last_comment_time: p.last_comment_time.timestamp(),
|
||||
allow_search: p.allow_search,
|
||||
author_title: (!p.author_title.is_empty()).then(|| p.author_title.to_string()),
|
||||
is_tmp: p.is_tmp,
|
||||
|
||||
37
src/api/upload.rs
Normal file
37
src/api/upload.rs
Normal file
@@ -0,0 +1,37 @@
|
||||
use crate::api::{CurrentUser, JsonAPI};
|
||||
use rocket::form::Form;
|
||||
use rocket::fs::TempFile;
|
||||
use rocket::serde::json::json;
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
use std::process::Command;
|
||||
|
||||
#[derive(FromForm)]
|
||||
pub struct Upload<'f> {
|
||||
file: TempFile<'f>,
|
||||
}
|
||||
|
||||
#[post("/upload", data = "<form>")]
|
||||
pub async fn ipfs_upload(user: CurrentUser, mut form: Form<Upload<'_>>) -> JsonAPI {
|
||||
let file_dir = Path::new("user_files").join(user.namehash);
|
||||
fs::create_dir_all(&file_dir)?;
|
||||
let file = &mut form.file;
|
||||
// dbg!(&file);
|
||||
let filename = file.name().unwrap_or("file").to_string()
|
||||
+ "."
|
||||
+ &file.content_type().map_or("", |ct| ct.sub().as_str());
|
||||
file.persist_to(file_dir.with_file_name(&filename)).await?;
|
||||
let output = Command::new("ipfs")
|
||||
.args(["add", "-q", "-r", "-cid-version=1", "user_files"])
|
||||
.output()?;
|
||||
// dbg!(&output);
|
||||
let hash = std::str::from_utf8(&output.stdout)
|
||||
.unwrap()
|
||||
.split_terminator("\n")
|
||||
.last()
|
||||
.unwrap();
|
||||
code0!(json!({
|
||||
"hash": hash,
|
||||
"filename": filename,
|
||||
}))
|
||||
}
|
||||
@@ -71,6 +71,7 @@ async fn main() -> Result<(), rocket::Error> {
|
||||
api::operation::set_title,
|
||||
api::operation::block,
|
||||
api::vote::vote,
|
||||
api::upload::ipfs_upload,
|
||||
],
|
||||
)
|
||||
.mount(
|
||||
|
||||
Reference in New Issue
Block a user