开始编写后端管理页面

This commit is contained in:
Songday 2021-03-15 16:28:36 +08:00
parent bacad0cd1c
commit 04475489ff
44 changed files with 1088 additions and 268 deletions

View File

@ -1,5 +1,5 @@
max_width = 120
fn_single_line = true
merge_imports = true
imports_granularity = "Crate"
match_block_trailing_comma = true
newline_style = "Native"

View File

@ -25,13 +25,13 @@ hyper = "0.14"
image = { version = "0.23", features = ["jpeg", "png", "gif"] }
lazy_static = "1.4"
lazy-static-include = "3"
once_cell = "1.7"
parking_lot = "0.11"
password-hash = { version = "0.1", features = ["rand_core"] }
# percent-encoding = "2.1"
# pulldown-cmark = "0.8"
once_cell = "1.7"
rand = "0.8"
v_htmlescape = "0.13"
regex = "1.4"
# subtle = "2"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
@ -41,6 +41,7 @@ scrypt = { version = "0.6" }
tokio = { version = "1", features = ["fs", "io-util", "macros", "rt", "rt-multi-thread", "signal", "time"] }
uuid = { version = "0.8", features = ["v5"] }
urlencoding = "1.1"
v_htmlescape = "0.13"
warp = "0.3"
# https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#platform-specific-dependencies

View File

@ -1,10 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>About</title>
</head>
<body>
</body>
</html>

View File

@ -0,0 +1,32 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>配置</title>
</head>
<body>
<h1>
博客基本信息配置
</h1>
<form class="pure-form pure-form-aligned">
<fieldset>
<div class="pure-control-group">
<label for="aligned-name">博客名称</label>
<input type="text" id="aligned-name" placeholder="博客名称" />
<span class="pure-form-message-inline">This is a required field.</span>
</div>
<div class="pure-control-group">
<label for="aligned-password">版权信息</label>
<input type="password" id="aligned-password" placeholder="Password" />
</div>
<div class="pure-control-group">
<label for="aligned-email">备案信息</label>
<input type="email" id="aligned-email" placeholder="Email Address" />
</div>
<div class="pure-controls">
<button type="submit" class="pure-button pure-button-primary">Submit</button>
</div>
</fieldset>
</form>
</body>
</html>

View File

@ -1,12 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Index</title>
</head>
<body>
<h1>
Welcome to Songday
</h1>
</body>
</html>

View File

@ -0,0 +1,29 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>配置管理用户</title>
</head>
<body>
<form class="pure-form pure-form-aligned" action="/user/login">
<fieldset>
<div class="pure-control-group">
<label for="aligned-email">邮箱地址</label>
<input type="email" id="aligned-email" placeholder="邮箱地址" />
<span class="pure-form-message-inline">用于管理博客或忘记密码之用.</span>
</div>
<div class="pure-control-group">
<label for="aligned-password1">登录密码</label>
<input type="password" id="aligned-password1" placeholder="密码" />
</div>
<div class="pure-control-group">
<label for="aligned-password2">确认密码</label>
<input type="password" id="aligned-password2" placeholder="密码" />
</div>
<div class="pure-controls">
<button type="submit" class="pure-button pure-button-primary">提交</button>
</div>
</fieldset>
</form>
</body>
</html>

View File

@ -0,0 +1,29 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>配置管理用户</title>
</head>
<body>
<form class="pure-form pure-form-aligned" action="/user/reg">
<fieldset>
<div class="pure-control-group">
<label for="aligned-email">邮箱地址</label>
<input type="email" id="aligned-email" placeholder="邮箱地址" />
<span class="pure-form-message-inline">用于管理博客或忘记密码之用.</span>
</div>
<div class="pure-control-group">
<label for="aligned-password1">登录密码</label>
<input type="password" id="aligned-password1" placeholder="密码" />
</div>
<div class="pure-control-group">
<label for="aligned-password2">确认密码</label>
<input type="password" id="aligned-password2" placeholder="密码" />
</div>
<div class="pure-controls">
<button type="submit" class="pure-button pure-button-primary">提交</button>
</div>
</fieldset>
</form>
</body>
</html>

View File

@ -14,11 +14,11 @@ use model::Tag;
use crate::util::result::Result;
pub mod model;
pub(crate) mod post;
mod setting;
pub(crate) mod tag;
pub(crate) mod user;
mod setting;
pub mod model;
type SqliteConnPool = sqlx::Pool<Sqlite>;

View File

@ -1,24 +1,27 @@
use core::time::Duration;
use std::time::SystemTime;
use comrak::{ComrakOptions, markdown_to_html};
use sqlx::{Sqlite, Row};
use comrak::{markdown_to_html, ComrakOptions};
use sqlx::{Row, Sqlite};
use blog_common::{
dto::{
post::{PostDetail, NewPost},
post::{NewPost, PostDetail},
PaginationData,
},
result::Error,
};
use crate::{
db::{self, DATA_SOURCE, SqlParam, tag},
util::snowflake,
db::{
self,
model::{Post, Tag, TagUsage},
tag,
tag::get_names,
SqlParam, DATA_SOURCE,
},
util::{result::Result, snowflake},
};
use crate::db::model::{Post, Tag, TagUsage};
use crate::util::result::Result;
use crate::db::tag::get_names;
pub async fn list(page_num: u8, page_size: u8) -> Result<PaginationData<Vec<PostDetail>>> {
let offset: i32 = ((page_num - 1) * page_size) as i32;
@ -62,24 +65,20 @@ pub async fn list_by_tag(tag_name: String, page_num: u8, page_size: u8) -> Resul
.await?;
let r = r.try_get::<i64, usize>(1);
if let Err(e) = r {
return Err(Error::SqliteDbError.into())
return Err(Error::SqliteDbError.into());
}
let total = r.unwrap() as u64;
if total < 1 {
return Ok(PaginationData {
total,
data: vec![],
});
return Ok(PaginationData { total, data: vec![] });
}
let d = sqlx::query_as::<Sqlite, Post>("SELECT p.* FROM post WHERE id IN (SELECT post_id FROM tag_usage WHERE tag_id = ? LIMIT ?, ?)")
.bind(tag.id)
.fetch_all(&DATA_SOURCE.get().unwrap().sqlite)
.await?;
let d = sqlx::query_as::<Sqlite, Post>(
"SELECT p.* FROM post WHERE id IN (SELECT post_id FROM tag_usage WHERE tag_id = ? LIMIT ?, ?)",
)
.bind(tag.id)
.fetch_all(&DATA_SOURCE.get().unwrap().sqlite)
.await?;
let d = d.iter().map(|i| i.into()).collect::<Vec<_>>();
Ok(PaginationData {
total,
data: d,
})
Ok(PaginationData { total, data: d })
}
pub async fn save(new_post: NewPost) -> Result<PostDetail> {
@ -106,17 +105,16 @@ pub async fn save(new_post: NewPost) -> Result<PostDetail> {
};
// save to sqlite
let last_insert_rowid = sqlx::query(
"INSERT INTO post(id, title, markdown_content, rendered_content, created_at)VALUES(?,?,?,?,?,?)",
)
.bind(&post_detail.id)
.bind(&post_detail.title)
.bind(&new_post.content)
.bind(&post_detail.content)
.bind(&post_detail.created_at.timestamp_millis())
.execute(&DATA_SOURCE.get().unwrap().sqlite)
.await?
.last_insert_rowid();
let last_insert_rowid =
sqlx::query("INSERT INTO post(id, title, markdown_content, rendered_content, created_at)VALUES(?,?,?,?,?,?)")
.bind(&post_detail.id)
.bind(&post_detail.title)
.bind(&new_post.content)
.bind(&post_detail.content)
.bind(&post_detail.created_at.timestamp_millis())
.execute(&DATA_SOURCE.get().unwrap().sqlite)
.await?
.last_insert_rowid();
if last_insert_rowid < 1 {
// println!("last_insert_rowid {}", last_insert_rowid);

View File

@ -0,0 +1 @@

View File

@ -12,25 +12,23 @@ use ahash::AHasher;
use bytes::{Buf, Bytes, BytesMut};
use lazy_static::lazy_static;
use parking_lot::RwLock;
use sqlx::Sqlite;
use tokio::{
fs::{File, OpenOptions, remove_file, rename},
// io::{self, AsyncReadExt, AsyncWriteExt, BufReader, BufWriter},
fs::{remove_file, rename, File, OpenOptions},
io::{self, AsyncReadExt, AsyncSeekExt, AsyncWriteExt, BufReader, BufWriter},
};
use sqlx::Sqlite;
use blog_common::result::Error;
use crate::db::model::Tag;
use crate::{
db::{self, DATA_SOURCE},
util::{crypt, snowflake},
db::{self, model::Tag, DATA_SOURCE},
util::{crypt, result::Result, snowflake},
};
use crate::util::result::Result;
pub async fn list() -> Result<Vec<String>> {
let tag_list = sqlx::query_as::<Sqlite, Tag>("SELECT name FROM tag ORDER BY created_at DESC")
.fetch_all(&DATA_SOURCE.get().unwrap().sqlite).await?;
.fetch_all(&DATA_SOURCE.get().unwrap().sqlite)
.await?;
let name_list = tag_list.iter().map(|i| i.name.clone()).collect::<Vec<String>>();
Ok(name_list)
}
@ -48,7 +46,8 @@ pub async fn get_names(id_array: Vec<i64>) -> Result<Vec<String>> {
sql.push('-');
sql.replace(",-", ") ORDER BY created_at DESC");
let tag_list = sqlx::query_as::<Sqlite, Tag>(sql.as_str())
.fetch_all(&DATA_SOURCE.get().unwrap().sqlite).await?;
.fetch_all(&DATA_SOURCE.get().unwrap().sqlite)
.await?;
let name_list = tag_list.iter().map(|i| i.name.clone()).collect::<Vec<String>>();
Ok(name_list)
}
@ -65,12 +64,15 @@ pub(super) async fn record_usage(post_id: u64, tags: &Vec<String>) -> Result<()>
for tag in tags.iter() {
query = query.bind(tag);
}
let tags = query.fetch_all(&DATA_SOURCE.get().unwrap().sqlite)
.await?;
let tags = query.fetch_all(&DATA_SOURCE.get().unwrap().sqlite).await?;
let post_id = post_id as i64;
for tag in tags {
sqlx::query("INSERT INTO tag_usage(post_id, tag_id)VALUES(?,?)").bind(post_id).bind(tag.id).execute(&DATA_SOURCE.get().unwrap().sqlite).await?;
sqlx::query("INSERT INTO tag_usage(post_id, tag_id)VALUES(?,?)")
.bind(post_id)
.bind(tag.id)
.execute(&DATA_SOURCE.get().unwrap().sqlite)
.await?;
}
Ok(())
}
}

View File

@ -1,9 +1,6 @@
use chrono::prelude::*;
use sqlx::{
Sqlite,
};
use sqlx::Sqlite;
use blog_common::{
dto::user::{RegisterParams, UserInfo},
@ -11,13 +8,31 @@ use blog_common::{
};
use crate::{
db::{self, DATA_SOURCE},
util::{crypt, snowflake},
db::{self, model::User, DATA_SOURCE},
util::{crypt, result::Result, snowflake},
};
use crate::db::model::User;
use crate::util::result::Result;
use sqlx::Row;
pub async fn have_user() -> bool {
let row = match sqlx::query("SELECT COUNT(*) FROM user")
.fetch_one(&DATA_SOURCE.get().unwrap().sqlite)
.await {
Ok(r) => r,
Err(e) => {
eprintln!("{}", e);
return false;
},
};
let r = match row.try_get::<i64, usize>(1) {
Ok(r) => r,
Err(e) => {
eprintln!("{}", e);
return false;
},
};
r > 0
}
pub async fn register(username: &str, password: &str) -> Result<UserInfo> {
let r = sqlx::query("SELECT id FROM user WHERE username = ?")
.bind(username)

View File

@ -1,13 +1,6 @@
use warp::{
Rejection, Reply,
};
use warp::{Rejection, Reply};
pub async fn index() -> Result<impl Reply, Rejection> {
let s = include_str!("../asset/page/index.html");
Ok(warp::reply::html(s))
}
pub async fn about() -> Result<impl Reply, Rejection> {
let s = include_str!("../asset/page/about.html");
Ok(warp::reply::html(s))
// let s = include_str!("../asset/page/index.html");
Ok(warp::reply::html(""))
}

View File

@ -11,10 +11,7 @@ use warp::{
};
use blog_common::{
dto::{
post::UploadImage,
user::UserInfo,
},
dto::{post::UploadImage, user::UserInfo},
result::{Error, ErrorResponse},
val,
};
@ -22,10 +19,12 @@ use blog_common::{
use crate::{
db::user,
facade::{auth_cookie, response_data, response_err},
util::common,
util::io::{self, SupportFileType},
service::status,
image::image,
service::status,
util::{
common,
io::{self, SupportFileType},
},
};
pub async fn verify_image(token: Option<String>) -> Result<WarpResponse, Rejection> {
@ -55,7 +54,8 @@ pub async fn upload(user: Option<UserInfo>, data: FormData) -> Result<impl Reply
let file_info = io::save_upload_file(
data,
&[SupportFileType::Png, SupportFileType::Jpg, SupportFileType::Gif],
).await;
)
.await;
if let Err(e) = file_info {
return Ok(response_err(500, e));
}
@ -65,26 +65,23 @@ pub async fn upload(user: Option<UserInfo>, data: FormData) -> Result<impl Reply
Ok(response_data(&d))
}
pub async fn save(
filename: String,
user: Option<UserInfo>,
body: impl Buf,
) -> Result<impl Reply, Rejection> {
pub async fn save(filename: String, user: Option<UserInfo>, body: impl Buf) -> Result<impl Reply, Rejection> {
if user.is_none() {
return Ok(response_err(500, Error::NotAuthed));
}
let filename = match urlencoding::decode(&filename){
let filename = match urlencoding::decode(&filename) {
Ok(f) => f,
Err(e) => {
eprintln!("{:#?}", e);
return Ok(response_err(500, Error::BadRequest));
}
},
};
let file_info = io::save_upload_stream(
filename,
body,
&[SupportFileType::Png, SupportFileType::Jpg, SupportFileType::Gif],
).await;
)
.await;
if let Err(e) = file_info {
return Ok(response_err(500, e));
}

View File

@ -0,0 +1,28 @@
use warp::{
Rejection, Reply,
};
use crate::db::user;
use crate::service::status;
const CONFIG_HTML:&'static str = include_str!("../asset/page/config.html");
const LOGIN_HTML:&'static str = include_str!("../asset/page/login.html");
const REG_HTML:&'static str = include_str!("../asset/page/reg.html");
pub async fn index(token: Option<String>) -> Result<impl Reply, Rejection> {
let html;
if user::have_user().await {
if matches!(token, Some(t) if status::check_auth(&t).is_ok()) {
html = CONFIG_HTML;
} else {
html = LOGIN_HTML;
}
} else {
html = REG_HTML;
}
Ok(warp::reply::html(html))
}
pub async fn config(token: Option<String>) -> Result<impl Reply, Rejection> {
Ok(warp::reply::html(CONFIG_HTML))
}

View File

@ -1,8 +1,9 @@
pub(crate) mod user;
pub(crate) mod post;
pub(crate) mod image;
pub(crate) mod tag;
pub(crate) mod asset;
pub(crate) mod image;
pub(crate) mod post;
pub(crate) mod tag;
pub(crate) mod user;
pub(crate) mod management;
use core::{convert::Infallible, result::Result};

View File

@ -23,8 +23,8 @@ use blog_common::{
use crate::{
db::post,
facade::{auth_cookie, response_data, response_err},
util::common,
service::status,
util::common,
};
pub async fn list(mut page_num: u8) -> Result<impl Reply, Rejection> {

View File

@ -1,8 +1,6 @@
use core::{convert::Infallible, result::Result};
use warp::{
Rejection, Reply,
};
use warp::{Rejection, Reply};
use crate::{
db::tag,

View File

@ -1,11 +1,7 @@
use core::{convert::Infallible, result::Result};
use bytes::Buf;
use hyper::header::{self, HeaderMap, HeaderValue};
use serde::Serialize;
use warp::{
filters::multipart::FormData,
http::{response::Response, StatusCode},
reply::{Json, Response as WarpResponse},
Rejection, Reply,
};
@ -13,7 +9,6 @@ use warp::{
use blog_common::{
dto::{
user::{LoginParams, RegisterParams, UserInfo, UserInfoWrapper},
Response as ApiResponse,
},
result::{Error, ErrorResponse},
val,
@ -22,17 +17,25 @@ use blog_common::{
use crate::{
db::user,
facade::{auth_cookie, response_data, response_err},
util::common,
service::status,
util::common,
};
pub async fn register(params: RegisterParams) -> Result<impl Reply, Rejection> {
if params.password1 != params.password2 {
return Ok(response_err(500, Error::BadRequest).into_response());
if user::have_user().await {
return Ok(response_err(500, Error::BusinessException("已有管理用户,若忘记密码,请使用“找回密码”功能".to_string())).into_response());
}
if params.email.len() < 6 || params.password1.len() < 5 {
return Ok(response_err(500, Error::BadRequest).into_response());
if params.password1.len() < 3 {
return Ok(response_err(500, Error::BusinessException("输入的密码不能少于3位".to_string())).into_response());
}
if params.email.len() < 5 || !common::EMAIL_REGEX.is_match(&params.email) {
return Ok(response_err(500, Error::BusinessException("输入的邮箱地址不合法".to_string())).into_response());
}
if params.password1 != params.password2 {
return Ok(response_err(500, Error::BusinessException("登录密码与确认密码不一致".to_string())).into_response());
}
match user::register(&params.email, &params.password1).await {
@ -60,8 +63,12 @@ pub async fn login(token: Option<String>, params: LoginParams) -> Result<WarpRes
return Ok(response_err(500, Error::InvalidSessionId).into_response());
}
if params.email.len() < 6 || params.password.len() < 5 {
return Ok(response_err(500, Error::LoginFailed).into_response());
if params.password.len() < 3 {
return Ok(response_err(500, Error::BusinessException("输入的密码不能少于3位".to_string())).into_response());
}
if params.email.len() < 5 || !common::EMAIL_REGEX.is_match(&params.email) {
return Ok(response_err(500, Error::BusinessException("输入的邮箱地址不合法".to_string())).into_response());
}
let token = token.unwrap();

View File

@ -3,21 +3,18 @@ use std::{io::Write, path::Path, vec::Vec};
use bytes::{buf::BufMut, Bytes, BytesMut};
use image::{
self,
codecs::jpeg::JpegEncoder,
// png::PngEncoder,
codecs::png::{CompressionType, FilterType, PngEncoder},
codecs::{
jpeg::JpegEncoder,
png::{CompressionType, FilterType, PngEncoder},
},
ColorType, DynamicImage, GenericImage, GenericImageView, ImageBuffer, ImageFormat, Luma, Rgb, Rgba, RgbaImage,
};
use rand::{thread_rng, Rng};
use tokio::fs::copy;
use blog_common::{
dto::UploadFileInfo,
result::{Error},
};
use blog_common::{dto::UploadFileInfo, result::Error};
use crate::util::val;
use crate::util::result::Result;
use crate::util::{result::Result, val};
pub type ImageWidth = u32;
pub type ImageHeight = u32;
@ -82,7 +79,12 @@ pub fn gen_verify_image(numbers: &[u8]) -> Bytes {
img.put_pixel(
x,
y,
Rgba([rng.gen_range(0..=255), rng.gen_range(0..=255), rng.gen_range(0..=255), 100]),
Rgba([
rng.gen_range(0..=255),
rng.gen_range(0..=255),
rng.gen_range(0..=255),
100,
]),
);
} else {
img.put_pixel(x + x_offset, y, *pixel);

View File

@ -3,15 +3,14 @@ use tokio::{
sync::oneshot,
};
use blog_backend::{db, serve::server, service};
use blog_backend::util::result;
use blog_backend::{db, serve::server, service, util::result};
fn main() -> result::Result<()> {
let runtime = Builder::new_multi_thread()
.worker_threads(4)
.enable_all()
.thread_name("songday-web-service")
.thread_stack_size(64 * 1024)
.thread_name("Songday-blog-service")
.thread_stack_size(1024 * 1024)
.build()?;
let (tx, rx) = oneshot::channel::<()>();

View File

@ -1 +1 @@
pub mod server;
pub mod server;

View File

@ -2,7 +2,7 @@ use std::{convert::Infallible, net::SocketAddr, sync::Arc};
use futures::future::Future;
use tokio::sync::oneshot::Receiver;
use warp::{self, Filter, reject, Rejection, Server};
use warp::{self, reject, Filter, Rejection, Server};
use blog_common::{
dto::{
@ -12,8 +12,12 @@ use blog_common::{
val,
};
use crate::{db::DataSource, util::result::Result, service::status};
use crate::facade::{self, asset, image, post, tag, user};
use crate::{
db::DataSource,
facade::{self, asset, image, post, tag, user, management},
service::status,
util::result::Result,
};
#[derive(Debug)]
struct FilterError;
@ -66,11 +70,17 @@ fn auth() -> impl Filter<Extract = (Option<UserInfo>,), Error = Infallible> + Cl
pub async fn create_warp_server(address: &str, receiver: Receiver<()>) -> Result<impl Future<Output = ()> + 'static> {
let index = warp::get().and(warp::path::end()).and_then(asset::index);
let about = warp::get()
.and(warp::path("about"))
let management = warp::get()
.and(warp::path("management"))
.and(warp::path::end())
.and(warp::get())
.and_then(asset::about);
.and(warp::cookie::optional(val::AUTH_HEADER_NAME))
.and_then(management::index);
let config = warp::get()
.and(warp::path("management"))
.and(warp::path("config"))
.and(warp::path::end())
.and(warp::cookie::optional(val::AUTH_HEADER_NAME))
.and_then(management::config);
let user_login = warp::post()
.and(warp::path("user"))
.and(warp::path("login"))
@ -172,7 +182,8 @@ pub async fn create_warp_server(address: &str, receiver: Receiver<()>) -> Result
.build();
let routes = index
.or(about)
.or(management)
.or(config)
.or(user_login)
.or(user_register)
.or(user_logout)

View File

@ -1,58 +0,0 @@
use std::{collections::HashMap, path::Path, sync::Arc};
use bytes::Buf;
use v_htmlescape;
use warp::filters::multipart::{FormData, Part};
use blog_common::{
dto::{
blog::{BlogDetail, NewBlog, UploadImage},
PaginationData,
},
result::Error,
};
use crate::{
db::blog,
image::image,
util::io::{self, SupportFileType},
};
use crate::db::model::Tag;
use crate::util::result::Result;
pub async fn list(mut page_num: u8) -> Result<PaginationData<Vec<BlogDetail>>> {
if page_num < 1 {
page_num = 1;
}
blog::list(page_num, crate::var::BLOG_PAGE_SIZE).await
}
pub async fn tags() -> Result<Vec<Tag>> { blog::tags() }
pub async fn list_by_tag(tag: String, mut page_num: u8) -> Result<PaginationData<Vec<BlogDetail>>> {
let tag = urlencoding::decode(&tag)?;
if page_num < 1 {
page_num = 1;
}
blog::list_by_tag(tag, page_num, crate::var::BLOG_PAGE_SIZE).await
}
pub async fn save(mut blog: NewBlog) -> Result<BlogDetail> {
if blog.title.len() < 3 || blog.title.len() > 60 {
return Err(Error::SaveBlogFailed.into());
}
if blog.content.len() < 5 || blog.content.len() > 65535 {
return Err(Error::SaveBlogFailed.into());
}
blog.content = format!("{}", v_htmlescape::escape(&blog.content));
blog::save(blog).await
}
pub async fn show(id: u64) -> Result<BlogDetail> {
if id < 10000 {
return Err(Error::CannotFoundBlog.into());
}
blog::show(id).await
}

View File

@ -6,19 +6,20 @@ use warp::filters::multipart::{FormData, Part};
use blog_common::{
dto::{
post::{PostDetail, NewPost, UploadImage},
post::{NewPost, PostDetail, UploadImage},
PaginationData,
},
result::Error,
};
use crate::{
db::post,
db::{model::Tag, post},
image::image,
util::io::{self, SupportFileType},
util::{
io::{self, SupportFileType},
result::Result,
},
};
use crate::db::model::Tag;
use crate::util::result::Result;
pub async fn upload(data: FormData) -> Result<UploadImage> {
let file_info = io::save_upload_file(

View File

@ -1,2 +1,2 @@
pub mod status;
mod image;
pub mod status;

View File

@ -1,25 +0,0 @@
use blog_common::{dto::user::UserInfo, result::Error};
use crate::{
db::{DataSource, SqlParam, user},
service::status,
};
use crate::util::result::{ErrorWrapper, Result};
pub async fn register(token: &str, email: &str, password: &str) -> Result<UserInfo> {
if email.len() < 6 || password.len() < 5 {
return Err(ErrorWrapper(Error::RegisterFailed));
}
let u = user::register(email, password).await?;
status::user_online(&token, u.clone());
Ok(u)
}
pub async fn login(token: &str, email: &str, password: &str) -> Result<UserInfo> {
if email.len() < 6 || password.len() < 5 {
return Err(ErrorWrapper(Error::LoginFailed));
}
let u = user::login(email, password).await?;
status::user_online(&token, u.clone());
Ok(u)
}

View File

@ -1,5 +1,7 @@
use rand::{rngs::OsRng, RngCore};
use regex::Regex;
use uuid::Uuid;
use lazy_static::lazy_static;
pub fn simple_uuid_with_name(name: &[u8]) -> String {
let uuid = Uuid::new_v5(&Uuid::NAMESPACE_URL, name);
@ -12,3 +14,7 @@ pub fn simple_uuid() -> String {
simple_uuid_with_name(&salt)
}
lazy_static! {
pub static ref EMAIL_REGEX: Regex = Regex::new(r"[^@ \t\r\n]+@[^@ \t\r\n]+\.[^@ \t\r\n]+").unwrap();
}

View File

@ -2,7 +2,7 @@ use base64;
use rand::{rngs::OsRng, RngCore};
use scrypt::{
password_hash::{PasswordHash, PasswordHasher, PasswordVerifier, SaltString},
Scrypt
Scrypt,
};
// use subtle::ConstantTimeEq;
@ -12,7 +12,10 @@ pub fn encrypt_password(password: &str) -> String {
}
fn encrypt_password_with_salt(password: &[u8], salt: &SaltString) -> String {
Scrypt.hash_password_simple(password, salt.as_ref()).unwrap().to_string()
Scrypt
.hash_password_simple(password, salt.as_ref())
.unwrap()
.to_string()
}
pub fn verify_password(password: &str, encrypted_password: &str) -> bool {

View File

@ -1,7 +1,7 @@
pub(crate) mod common;
pub(crate) mod crypt;
pub(crate) mod io;
pub(crate) mod num;
pub(crate) mod snowflake;
pub mod result;
pub(crate) mod common;
pub(crate) mod crypt;
pub(crate) mod io;
pub(crate) mod num;
pub mod result;
pub(crate) mod snowflake;
pub(crate) mod val;

View File

@ -1,14 +1,15 @@
use std::vec::Vec;
use std::rc::Rc;
use std::{rc::Rc, vec::Vec};
use rand::{thread_rng, Rng};
use rand::distributions::uniform::{SampleUniform, SampleRange};
use rand::{
distributions::uniform::{SampleRange, SampleUniform},
thread_rng, Rng,
};
// const NUMERIC: [u8; 10] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
pub fn rand_numbers<T>(min: T, max: T, amount: usize) -> Vec<T>
where
T: SampleUniform + PartialOrd + Copy,
where
T: SampleUniform + PartialOrd + Copy,
{
let mut d = Vec::<T>::with_capacity(amount);
let mut rng = thread_rng();

View File

@ -5,8 +5,8 @@ use serde::{Deserialize, Serialize};
use crate::result::ErrorResponse;
pub mod post;
pub mod user;
mod setting;
pub mod user;
//https://stackoverflow.com/questions/49953960/cannot-resolve-t-serdedeserializea-when-deriving-deserialize-on-a-generic
//https://stackoverflow.com/questions/54761790/how-to-deserialize-with-for-a-container-using-serde-in-rust

View File

@ -4,4 +4,4 @@ pub struct Setting {
pub license: String,
pub manager_user: String,
pub manager_password: String,
}
}

View File

@ -20,7 +20,7 @@ pub enum Error {
SerdeError,
#[error("Page not found")]
NotFound,
#[error("Bad request")]
#[error("请求参数不合法,请检查输入是否正确")]
BadRequest,
#[error("Method not allowed")]
MethodNotAllowed,
@ -28,11 +28,11 @@ pub enum Error {
InternalServerError,
// business
#[error("Invalid session id")]
#[error("无效的 Session ID")]
InvalidSessionId,
#[error("Invalid verify code")]
#[error("无效的验证码")]
InvalidVerifyCode,
#[error("Current user have not authorized, please login again")]
#[error("登录信息失效,请重新登录")]
NotAuthed,
#[error("Login failed")]
LoginFailed,
@ -58,6 +58,9 @@ pub enum Error {
ReadBlogIdDataByTagFailed,
#[error("Saving blog id data by tag failed")]
SaveBlogIdDataByTagFailed,
#[error("{0}")]
BusinessException(String),
}
#[derive(Debug, Deserialize, Serialize)]

758
frontend/dist/index-75330f91aa5baa0a.js vendored Normal file
View File

@ -0,0 +1,758 @@
let wasm;
let cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
cachedTextDecoder.decode();
let cachegetUint8Memory0 = null;
function getUint8Memory0() {
if (cachegetUint8Memory0 === null || cachegetUint8Memory0.buffer !== wasm.memory.buffer) {
cachegetUint8Memory0 = new Uint8Array(wasm.memory.buffer);
}
return cachegetUint8Memory0;
}
function getStringFromWasm0(ptr, len) {
return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len));
}
const heap = new Array(32).fill(undefined);
heap.push(undefined, null, true, false);
let heap_next = heap.length;
function addHeapObject(obj) {
if (heap_next === heap.length) heap.push(heap.length + 1);
const idx = heap_next;
heap_next = heap[idx];
heap[idx] = obj;
return idx;
}
function getObject(idx) { return heap[idx]; }
function dropObject(idx) {
if (idx < 36) return;
heap[idx] = heap_next;
heap_next = idx;
}
function takeObject(idx) {
const ret = getObject(idx);
dropObject(idx);
return ret;
}
let WASM_VECTOR_LEN = 0;
let cachedTextEncoder = new TextEncoder('utf-8');
const encodeString = (typeof cachedTextEncoder.encodeInto === 'function'
? function (arg, view) {
return cachedTextEncoder.encodeInto(arg, view);
}
: function (arg, view) {
const buf = cachedTextEncoder.encode(arg);
view.set(buf);
return {
read: arg.length,
written: buf.length
};
});
function passStringToWasm0(arg, malloc, realloc) {
if (realloc === undefined) {
const buf = cachedTextEncoder.encode(arg);
const ptr = malloc(buf.length);
getUint8Memory0().subarray(ptr, ptr + buf.length).set(buf);
WASM_VECTOR_LEN = buf.length;
return ptr;
}
let len = arg.length;
let ptr = malloc(len);
const mem = getUint8Memory0();
let offset = 0;
for (; offset < len; offset++) {
const code = arg.charCodeAt(offset);
if (code > 0x7F) break;
mem[ptr + offset] = code;
}
if (offset !== len) {
if (offset !== 0) {
arg = arg.slice(offset);
}
ptr = realloc(ptr, len, len = offset + arg.length * 3);
const view = getUint8Memory0().subarray(ptr + offset, ptr + len);
const ret = encodeString(arg, view);
offset += ret.written;
}
WASM_VECTOR_LEN = offset;
return ptr;
}
function isLikeNone(x) {
return x === undefined || x === null;
}
let cachegetInt32Memory0 = null;
function getInt32Memory0() {
if (cachegetInt32Memory0 === null || cachegetInt32Memory0.buffer !== wasm.memory.buffer) {
cachegetInt32Memory0 = new Int32Array(wasm.memory.buffer);
}
return cachegetInt32Memory0;
}
function debugString(val) {
// primitive types
const type = typeof val;
if (type == 'number' || type == 'boolean' || val == null) {
return `${val}`;
}
if (type == 'string') {
return `"${val}"`;
}
if (type == 'symbol') {
const description = val.description;
if (description == null) {
return 'Symbol';
} else {
return `Symbol(${description})`;
}
}
if (type == 'function') {
const name = val.name;
if (typeof name == 'string' && name.length > 0) {
return `Function(${name})`;
} else {
return 'Function';
}
}
// objects
if (Array.isArray(val)) {
const length = val.length;
let debug = '[';
if (length > 0) {
debug += debugString(val[0]);
}
for(let i = 1; i < length; i++) {
debug += ', ' + debugString(val[i]);
}
debug += ']';
return debug;
}
// Test for built-in
const builtInMatches = /\[object ([^\]]+)\]/.exec(toString.call(val));
let className;
if (builtInMatches.length > 1) {
className = builtInMatches[1];
} else {
// Failed to match the standard '[object ClassName]'
return toString.call(val);
}
if (className == 'Object') {
// we're a user defined class or Object
// JSON.stringify avoids problems with cycles, and is generally much
// easier than looping through ownProperties of `val`.
try {
return 'Object(' + JSON.stringify(val) + ')';
} catch (_) {
return 'Object';
}
}
// errors
if (val instanceof Error) {
return `${val.name}: ${val.message}\n${val.stack}`;
}
// TODO we could test for more things here, like `Set`s and `Map`s.
return className;
}
function makeMutClosure(arg0, arg1, dtor, f) {
const state = { a: arg0, b: arg1, cnt: 1, dtor };
const real = (...args) => {
// First up with a closure we increment the internal reference
// count. This ensures that the Rust closure environment won't
// be deallocated while we're invoking it.
state.cnt++;
const a = state.a;
state.a = 0;
try {
return f(a, state.b, ...args);
} finally {
if (--state.cnt === 0) {
wasm.__wbindgen_export_2.get(state.dtor)(a, state.b);
} else {
state.a = a;
}
}
};
real.original = state;
return real;
}
let stack_pointer = 32;
function addBorrowedObject(obj) {
if (stack_pointer == 1) throw new Error('out of js stack');
heap[--stack_pointer] = obj;
return stack_pointer;
}
function __wbg_adapter_24(arg0, arg1, arg2) {
try {
wasm._dyn_core__ops__function__FnMut___A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h77e9687c6edbcb34(arg0, arg1, addBorrowedObject(arg2));
} finally {
heap[stack_pointer++] = undefined;
}
}
function __wbg_adapter_27(arg0, arg1, arg2) {
wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h8c8ed20052ee0288(arg0, arg1, addHeapObject(arg2));
}
/**
*/
export function run_app() {
wasm.run_app();
}
function handleError(f) {
return function () {
try {
return f.apply(this, arguments);
} catch (e) {
wasm.__wbindgen_exn_store(addHeapObject(e));
}
};
}
async function load(module, imports) {
if (typeof Response === 'function' && module instanceof Response) {
if (typeof WebAssembly.instantiateStreaming === 'function') {
try {
return await WebAssembly.instantiateStreaming(module, imports);
} catch (e) {
if (module.headers.get('Content-Type') != 'application/wasm') {
console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e);
} else {
throw e;
}
}
}
const bytes = await module.arrayBuffer();
return await WebAssembly.instantiate(bytes, imports);
} else {
const instance = await WebAssembly.instantiate(module, imports);
if (instance instanceof WebAssembly.Instance) {
return { instance, module };
} else {
return instance;
}
}
}
async function init(input) {
if (typeof input === 'undefined') {
input = new URL('index-75330f91aa5baa0a_bg.wasm', import.meta.url);
}
const imports = {};
imports.wbg = {};
imports.wbg.__wbindgen_string_new = function(arg0, arg1) {
var ret = getStringFromWasm0(arg0, arg1);
return addHeapObject(ret);
};
imports.wbg.__wbindgen_object_clone_ref = function(arg0) {
var ret = getObject(arg0);
return addHeapObject(ret);
};
imports.wbg.__wbindgen_is_undefined = function(arg0) {
var ret = getObject(arg0) === undefined;
return ret;
};
imports.wbg.__wbg_Window_6f26ab8994cdec9b = function(arg0) {
var ret = getObject(arg0).Window;
return addHeapObject(ret);
};
imports.wbg.__wbg_WorkerGlobalScope_65696f271e05e492 = function(arg0) {
var ret = getObject(arg0).WorkerGlobalScope;
return addHeapObject(ret);
};
imports.wbg.__wbindgen_cb_drop = function(arg0) {
const obj = takeObject(arg0).original;
if (obj.cnt-- == 1) {
obj.a = 0;
return true;
}
var ret = false;
return ret;
};
imports.wbg.__wbindgen_object_drop_ref = function(arg0) {
takeObject(arg0);
};
imports.wbg.__wbg_instanceof_Window_fa4595281eb5ba83 = function(arg0) {
var ret = getObject(arg0) instanceof Window;
return ret;
};
imports.wbg.__wbg_document_d8cce4c1031c64eb = function(arg0) {
var ret = getObject(arg0).document;
return isLikeNone(ret) ? 0 : addHeapObject(ret);
};
imports.wbg.__wbg_location_f8de588551329bf4 = function(arg0) {
var ret = getObject(arg0).location;
return addHeapObject(ret);
};
imports.wbg.__wbg_history_ea580f62f8cb1285 = handleError(function(arg0) {
var ret = getObject(arg0).history;
return addHeapObject(ret);
});
imports.wbg.__wbg_localStorage_a79a5d8ee7487fcb = handleError(function(arg0) {
var ret = getObject(arg0).localStorage;
return isLikeNone(ret) ? 0 : addHeapObject(ret);
});
imports.wbg.__wbg_sessionStorage_dea744376f5440ac = handleError(function(arg0) {
var ret = getObject(arg0).sessionStorage;
return isLikeNone(ret) ? 0 : addHeapObject(ret);
});
imports.wbg.__wbg_fetch_6c1ec0777d07eee3 = function(arg0, arg1, arg2) {
var ret = getObject(arg0).fetch(getObject(arg1), getObject(arg2));
return addHeapObject(ret);
};
imports.wbg.__wbg_createElement_695120dd76150487 = handleError(function(arg0, arg1, arg2) {
var ret = getObject(arg0).createElement(getStringFromWasm0(arg1, arg2));
return addHeapObject(ret);
});
imports.wbg.__wbg_createElementNS_9e443d140d5b4a33 = handleError(function(arg0, arg1, arg2, arg3, arg4) {
var ret = getObject(arg0).createElementNS(arg1 === 0 ? undefined : getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4));
return addHeapObject(ret);
});
imports.wbg.__wbg_createTextNode_6f0cfbce3a2487fb = function(arg0, arg1, arg2) {
var ret = getObject(arg0).createTextNode(getStringFromWasm0(arg1, arg2));
return addHeapObject(ret);
};
imports.wbg.__wbg_querySelector_5cba5f6b2ed68e05 = handleError(function(arg0, arg1, arg2) {
var ret = getObject(arg0).querySelector(getStringFromWasm0(arg1, arg2));
return isLikeNone(ret) ? 0 : addHeapObject(ret);
});
imports.wbg.__wbg_pathname_bbcab59ebce24546 = handleError(function(arg0, arg1) {
var ret = getObject(arg1).pathname;
var ptr0 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
var len0 = WASM_VECTOR_LEN;
getInt32Memory0()[arg0 / 4 + 1] = len0;
getInt32Memory0()[arg0 / 4 + 0] = ptr0;
});
imports.wbg.__wbg_search_63bdf6fe2b15d1d4 = handleError(function(arg0, arg1) {
var ret = getObject(arg1).search;
var ptr0 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
var len0 = WASM_VECTOR_LEN;
getInt32Memory0()[arg0 / 4 + 1] = len0;
getInt32Memory0()[arg0 / 4 + 0] = ptr0;
});
imports.wbg.__wbg_hash_f1a1e37355e44338 = handleError(function(arg0, arg1) {
var ret = getObject(arg1).hash;
var ptr0 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
var len0 = WASM_VECTOR_LEN;
getInt32Memory0()[arg0 / 4 + 1] = len0;
getInt32Memory0()[arg0 / 4 + 0] = ptr0;
});
imports.wbg.__wbg_newwithstrsequencesequence_68686c6e9a188d2f = handleError(function(arg0) {
var ret = new Headers(getObject(arg0));
return addHeapObject(ret);
});
imports.wbg.__wbg_instanceof_HtmlSelectElement_3d87bb1722a1aab7 = function(arg0) {
var ret = getObject(arg0) instanceof HTMLSelectElement;
return ret;
};
imports.wbg.__wbg_newwithstrandinit_18c41e1aaab4972f = handleError(function(arg0, arg1, arg2) {
var ret = new Request(getStringFromWasm0(arg0, arg1), getObject(arg2));
return addHeapObject(ret);
});
imports.wbg.__wbg_status_050df54e85254c67 = function(arg0) {
var ret = getObject(arg0).status;
return ret;
};
imports.wbg.__wbg_headers_b803c3e004351cb0 = function(arg0) {
var ret = getObject(arg0).headers;
return addHeapObject(ret);
};
imports.wbg.__wbg_arrayBuffer_c5e630358019dfa0 = handleError(function(arg0) {
var ret = getObject(arg0).arrayBuffer();
return addHeapObject(ret);
});
imports.wbg.__wbg_text_5332e729fad5779e = handleError(function(arg0) {
var ret = getObject(arg0).text();
return addHeapObject(ret);
});
imports.wbg.__wbg_readyState_ffd9215b205bbc7e = function(arg0) {
var ret = getObject(arg0).readyState;
return ret;
};
imports.wbg.__wbg_result_0f2e720d85f5b799 = handleError(function(arg0) {
var ret = getObject(arg0).result;
return addHeapObject(ret);
});
imports.wbg.__wbg_new_549a5d72a89fabbc = handleError(function() {
var ret = new FileReader();
return addHeapObject(ret);
});
imports.wbg.__wbg_abort_4ce1d711728e85aa = function(arg0) {
getObject(arg0).abort();
};
imports.wbg.__wbg_readAsArrayBuffer_66a1d5aa15dd98a7 = handleError(function(arg0, arg1) {
getObject(arg0).readAsArrayBuffer(getObject(arg1));
});
imports.wbg.__wbg_instanceof_HtmlTextAreaElement_1bd106832e7a2d85 = function(arg0) {
var ret = getObject(arg0) instanceof HTMLTextAreaElement;
return ret;
};
imports.wbg.__wbg_value_022eba9b8dd4fb1e = function(arg0, arg1) {
var ret = getObject(arg1).value;
var ptr0 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
var len0 = WASM_VECTOR_LEN;
getInt32Memory0()[arg0 / 4 + 1] = len0;
getInt32Memory0()[arg0 / 4 + 0] = ptr0;
};
imports.wbg.__wbg_setvalue_d3112c6f38991024 = function(arg0, arg1, arg2) {
getObject(arg0).value = getStringFromWasm0(arg1, arg2);
};
imports.wbg.__wbg_signal_564fb4b932a62647 = function(arg0) {
var ret = getObject(arg0).signal;
return addHeapObject(ret);
};
imports.wbg.__wbg_new_b25ae9c0ad6843ae = handleError(function() {
var ret = new AbortController();
return addHeapObject(ret);
});
imports.wbg.__wbg_abort_9c58ad5988ed06e1 = function(arg0) {
getObject(arg0).abort();
};
imports.wbg.__wbg_instanceof_HtmlButtonElement_3d160e69f22feabe = function(arg0) {
var ret = getObject(arg0) instanceof HTMLButtonElement;
return ret;
};
imports.wbg.__wbg_settype_3a62f424c2f2cc6e = function(arg0, arg1, arg2) {
getObject(arg0).type = getStringFromWasm0(arg1, arg2);
};
imports.wbg.__wbg_now_9f22124bc74da886 = function(arg0) {
var ret = getObject(arg0).now();
return ret;
};
imports.wbg.__wbg_namespaceURI_e79b3e59fe6e51eb = function(arg0, arg1) {
var ret = getObject(arg1).namespaceURI;
var ptr0 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
var len0 = WASM_VECTOR_LEN;
getInt32Memory0()[arg0 / 4 + 1] = len0;
getInt32Memory0()[arg0 / 4 + 0] = ptr0;
};
imports.wbg.__wbg_setinnerHTML_a8b2c66f141a2b24 = function(arg0, arg1, arg2) {
getObject(arg0).innerHTML = getStringFromWasm0(arg1, arg2);
};
imports.wbg.__wbg_getAttribute_3d19bb0ff8904532 = function(arg0, arg1, arg2, arg3) {
var ret = getObject(arg1).getAttribute(getStringFromWasm0(arg2, arg3));
var ptr0 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
var len0 = WASM_VECTOR_LEN;
getInt32Memory0()[arg0 / 4 + 1] = len0;
getInt32Memory0()[arg0 / 4 + 0] = ptr0;
};
imports.wbg.__wbg_removeAttribute_4bc290dbe2b7214f = handleError(function(arg0, arg1, arg2) {
getObject(arg0).removeAttribute(getStringFromWasm0(arg1, arg2));
});
imports.wbg.__wbg_setAttribute_fb8737b4573a65f8 = handleError(function(arg0, arg1, arg2, arg3, arg4) {
getObject(arg0).setAttribute(getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4));
});
imports.wbg.__wbg_log_8485ead621ceded9 = function(arg0) {
console.log(getObject(arg0));
};
imports.wbg.__wbg_instanceof_HtmlInputElement_bcbf72cd9188bbf5 = function(arg0) {
var ret = getObject(arg0) instanceof HTMLInputElement;
return ret;
};
imports.wbg.__wbg_setchecked_c59c4e3455f1971c = function(arg0, arg1) {
getObject(arg0).checked = arg1 !== 0;
};
imports.wbg.__wbg_files_75aaa5e919bf42c4 = function(arg0) {
var ret = getObject(arg0).files;
return isLikeNone(ret) ? 0 : addHeapObject(ret);
};
imports.wbg.__wbg_settype_78a0fe790fa56fa7 = function(arg0, arg1, arg2) {
getObject(arg0).type = getStringFromWasm0(arg1, arg2);
};
imports.wbg.__wbg_value_9c8f7cca5ded6671 = function(arg0, arg1) {
var ret = getObject(arg1).value;
var ptr0 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
var len0 = WASM_VECTOR_LEN;
getInt32Memory0()[arg0 / 4 + 1] = len0;
getInt32Memory0()[arg0 / 4 + 0] = ptr0;
};
imports.wbg.__wbg_setvalue_44d4bd0ac437904f = function(arg0, arg1, arg2) {
getObject(arg0).value = getStringFromWasm0(arg1, arg2);
};
imports.wbg.__wbg_fetch_045d28bb4e9368fb = function(arg0, arg1, arg2) {
var ret = getObject(arg0).fetch(getObject(arg1), getObject(arg2));
return addHeapObject(ret);
};
imports.wbg.__wbg_preventDefault_2a53c6dce5093030 = function(arg0) {
getObject(arg0).preventDefault();
};
imports.wbg.__wbg_addEventListener_bb3090f03a1e2df6 = handleError(function(arg0, arg1, arg2, arg3, arg4) {
getObject(arg0).addEventListener(getStringFromWasm0(arg1, arg2), getObject(arg3), getObject(arg4));
});
imports.wbg.__wbg_removeEventListener_fd27aefbf65efcfb = handleError(function(arg0, arg1, arg2, arg3, arg4) {
getObject(arg0).removeEventListener(getStringFromWasm0(arg1, arg2), getObject(arg3), arg4 !== 0);
});
imports.wbg.__wbg_instanceof_PopStateEvent_a695582c8f771c6d = function(arg0) {
var ret = getObject(arg0) instanceof PopStateEvent;
return ret;
};
imports.wbg.__wbg_state_2705fc307f614d01 = function(arg0) {
var ret = getObject(arg0).state;
return addHeapObject(ret);
};
imports.wbg.__wbg_name_2db5213e1d312b59 = function(arg0, arg1) {
var ret = getObject(arg1).name;
var ptr0 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
var len0 = WASM_VECTOR_LEN;
getInt32Memory0()[arg0 / 4 + 1] = len0;
getInt32Memory0()[arg0 / 4 + 0] = ptr0;
};
imports.wbg.__wbg_state_3f3bf78ca919bce7 = handleError(function(arg0) {
var ret = getObject(arg0).state;
return addHeapObject(ret);
});
imports.wbg.__wbg_pushState_10c51a6fb23b182f = handleError(function(arg0, arg1, arg2, arg3, arg4, arg5) {
getObject(arg0).pushState(getObject(arg1), getStringFromWasm0(arg2, arg3), arg4 === 0 ? undefined : getStringFromWasm0(arg4, arg5));
});
imports.wbg.__wbg_replaceState_084b0aa9320d3fa3 = handleError(function(arg0, arg1, arg2, arg3, arg4, arg5) {
getObject(arg0).replaceState(getObject(arg1), getStringFromWasm0(arg2, arg3), arg4 === 0 ? undefined : getStringFromWasm0(arg4, arg5));
});
imports.wbg.__wbg_nodeName_55cf450b6364b57f = function(arg0, arg1) {
var ret = getObject(arg1).nodeName;
var ptr0 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
var len0 = WASM_VECTOR_LEN;
getInt32Memory0()[arg0 / 4 + 1] = len0;
getInt32Memory0()[arg0 / 4 + 0] = ptr0;
};
imports.wbg.__wbg_lastChild_6362c4c702857757 = function(arg0) {
var ret = getObject(arg0).lastChild;
return isLikeNone(ret) ? 0 : addHeapObject(ret);
};
imports.wbg.__wbg_setnodeValue_80e9e070bf4261d2 = function(arg0, arg1, arg2) {
getObject(arg0).nodeValue = arg1 === 0 ? undefined : getStringFromWasm0(arg1, arg2);
};
imports.wbg.__wbg_textContent_04ca15fd48e65efe = function(arg0, arg1) {
var ret = getObject(arg1).textContent;
var ptr0 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
var len0 = WASM_VECTOR_LEN;
getInt32Memory0()[arg0 / 4 + 1] = len0;
getInt32Memory0()[arg0 / 4 + 0] = ptr0;
};
imports.wbg.__wbg_appendChild_9ba4c99688714f13 = handleError(function(arg0, arg1) {
var ret = getObject(arg0).appendChild(getObject(arg1));
return addHeapObject(ret);
});
imports.wbg.__wbg_insertBefore_9ddb982d7f5d6824 = handleError(function(arg0, arg1, arg2) {
var ret = getObject(arg0).insertBefore(getObject(arg1), getObject(arg2));
return addHeapObject(ret);
});
imports.wbg.__wbg_removeChild_e02df31f6d70392a = handleError(function(arg0, arg1) {
var ret = getObject(arg0).removeChild(getObject(arg1));
return addHeapObject(ret);
});
imports.wbg.__wbg_getItem_3fc9a85a5c86c097 = handleError(function(arg0, arg1, arg2, arg3) {
var ret = getObject(arg1).getItem(getStringFromWasm0(arg2, arg3));
var ptr0 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
var len0 = WASM_VECTOR_LEN;
getInt32Memory0()[arg0 / 4 + 1] = len0;
getInt32Memory0()[arg0 / 4 + 0] = ptr0;
});
imports.wbg.__wbg_removeItem_608dad41f63cff4c = handleError(function(arg0, arg1, arg2) {
getObject(arg0).removeItem(getStringFromWasm0(arg1, arg2));
});
imports.wbg.__wbg_setItem_99592651ffc703f6 = handleError(function(arg0, arg1, arg2, arg3, arg4) {
getObject(arg0).setItem(getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4));
});
imports.wbg.__wbg_new_04918f9bdadadf45 = function() {
var ret = new Array();
return addHeapObject(ret);
};
imports.wbg.__wbg_get_40375c2067f479fc = function(arg0, arg1) {
var ret = getObject(arg0)[arg1 >>> 0];
return addHeapObject(ret);
};
imports.wbg.__wbg_from_87d2b71ada3c04df = function(arg0) {
var ret = Array.from(getObject(arg0));
return addHeapObject(ret);
};
imports.wbg.__wbg_push_60db4345d488a9b8 = function(arg0, arg1) {
var ret = getObject(arg0).push(getObject(arg1));
return ret;
};
imports.wbg.__wbg_toString_7ba29b72020636b1 = function(arg0) {
var ret = getObject(arg0).toString();
return addHeapObject(ret);
};
imports.wbg.__wbg_newnoargs_179d393e4626fcf7 = function(arg0, arg1) {
var ret = new Function(getStringFromWasm0(arg0, arg1));
return addHeapObject(ret);
};
imports.wbg.__wbg_call_8487a9f580e47219 = handleError(function(arg0, arg1) {
var ret = getObject(arg0).call(getObject(arg1));
return addHeapObject(ret);
});
imports.wbg.__wbg_next_9bb15512a3ee3434 = handleError(function(arg0) {
var ret = getObject(arg0).next();
return addHeapObject(ret);
});
imports.wbg.__wbg_next_cb5f2b7832bb897e = function(arg0) {
var ret = getObject(arg0).next;
return addHeapObject(ret);
};
imports.wbg.__wbg_done_16917a81a3b84f69 = function(arg0) {
var ret = getObject(arg0).done;
return ret;
};
imports.wbg.__wbg_value_f66e28875493aed6 = function(arg0) {
var ret = getObject(arg0).value;
return addHeapObject(ret);
};
imports.wbg.__wbg_is_736e7316d8240b8e = function(arg0, arg1) {
var ret = Object.is(getObject(arg0), getObject(arg1));
return ret;
};
imports.wbg.__wbg_new_b0b535e7b597e9c1 = function() {
var ret = new Object();
return addHeapObject(ret);
};
imports.wbg.__wbg_iterator_09cc2e58591459c9 = function() {
var ret = Symbol.iterator;
return addHeapObject(ret);
};
imports.wbg.__wbg_resolve_dcf7d6a479f5b166 = function(arg0) {
var ret = Promise.resolve(getObject(arg0));
return addHeapObject(ret);
};
imports.wbg.__wbg_then_16d483233321aac8 = function(arg0, arg1) {
var ret = getObject(arg0).then(getObject(arg1));
return addHeapObject(ret);
};
imports.wbg.__wbg_then_c95977e365944fff = function(arg0, arg1, arg2) {
var ret = getObject(arg0).then(getObject(arg1), getObject(arg2));
return addHeapObject(ret);
};
imports.wbg.__wbg_globalThis_a2669bee93faee43 = handleError(function() {
var ret = globalThis.globalThis;
return addHeapObject(ret);
});
imports.wbg.__wbg_self_eeabd9085c04fc17 = handleError(function() {
var ret = self.self;
return addHeapObject(ret);
});
imports.wbg.__wbg_window_f110c13310da2c8f = handleError(function() {
var ret = window.window;
return addHeapObject(ret);
});
imports.wbg.__wbg_global_a5584d717f4d6761 = handleError(function() {
var ret = global.global;
return addHeapObject(ret);
});
imports.wbg.__wbg_new_139e70222494b1ff = function(arg0) {
var ret = new Uint8Array(getObject(arg0));
return addHeapObject(ret);
};
imports.wbg.__wbg_newwithbyteoffsetandlength_836859e5deb44d3f = function(arg0, arg1, arg2) {
var ret = new Uint8Array(getObject(arg0), arg1 >>> 0, arg2 >>> 0);
return addHeapObject(ret);
};
imports.wbg.__wbg_length_2cfa674c2a529bc1 = function(arg0) {
var ret = getObject(arg0).length;
return ret;
};
imports.wbg.__wbg_set_d771848e3c7935bb = function(arg0, arg1, arg2) {
getObject(arg0).set(getObject(arg1), arg2 >>> 0);
};
imports.wbg.__wbg_buffer_e35e010c3ba9f945 = function(arg0) {
var ret = getObject(arg0).buffer;
return addHeapObject(ret);
};
imports.wbg.__wbindgen_is_function = function(arg0) {
var ret = typeof(getObject(arg0)) === 'function';
return ret;
};
imports.wbg.__wbindgen_is_object = function(arg0) {
const val = getObject(arg0);
var ret = typeof(val) === 'object' && val !== null;
return ret;
};
imports.wbg.__wbg_get_a96a2f48856bb1c3 = handleError(function(arg0, arg1) {
var ret = Reflect.get(getObject(arg0), getObject(arg1));
return addHeapObject(ret);
});
imports.wbg.__wbg_set_c1d44124a051a5e7 = handleError(function(arg0, arg1, arg2) {
var ret = Reflect.set(getObject(arg0), getObject(arg1), getObject(arg2));
return ret;
});
imports.wbg.__wbindgen_string_get = function(arg0, arg1) {
const obj = getObject(arg1);
var ret = typeof(obj) === 'string' ? obj : undefined;
var ptr0 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
var len0 = WASM_VECTOR_LEN;
getInt32Memory0()[arg0 / 4 + 1] = len0;
getInt32Memory0()[arg0 / 4 + 0] = ptr0;
};
imports.wbg.__wbindgen_debug_string = function(arg0, arg1) {
var ret = debugString(getObject(arg1));
var ptr0 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
var len0 = WASM_VECTOR_LEN;
getInt32Memory0()[arg0 / 4 + 1] = len0;
getInt32Memory0()[arg0 / 4 + 0] = ptr0;
};
imports.wbg.__wbindgen_throw = function(arg0, arg1) {
throw new Error(getStringFromWasm0(arg0, arg1));
};
imports.wbg.__wbindgen_memory = function() {
var ret = wasm.memory;
return addHeapObject(ret);
};
imports.wbg.__wbindgen_closure_wrapper13033 = function(arg0, arg1, arg2) {
var ret = makeMutClosure(arg0, arg1, 666, __wbg_adapter_24);
return addHeapObject(ret);
};
imports.wbg.__wbindgen_closure_wrapper14244 = function(arg0, arg1, arg2) {
var ret = makeMutClosure(arg0, arg1, 736, __wbg_adapter_27);
return addHeapObject(ret);
};
if (typeof input === 'string' || (typeof Request === 'function' && input instanceof Request) || (typeof URL === 'function' && input instanceof URL)) {
input = fetch(input);
}
const { instance, module } = await load(await input, imports);
wasm = instance.exports;
init.__wbindgen_wasm_module = module;
wasm.__wbindgen_start();
return wasm;
}
export default init;

Binary file not shown.

14
frontend/dist/index.html vendored Normal file
View File

@ -0,0 +1,14 @@
<!DOCTYPE html><html lang="en"><head>
<meta charset="utf-8">
<title>70年代、80年代、90年代怀旧、复古、回忆</title>
<link rel="stylesheet" href="asset/main.css">
<style type="text/css">
body{padding:20px}
.tar{text-align:right}
.tac{text-align:center}
.tag-btn{color:white;border-radius:4px;text-shadow:0 1px 1px rgba(0, 0, 0, 0.2);background:rgb(28, 184, 65);margin-right:6px}
.tag-link{margin-right:6px}
</style>
<script type="module">import init from '/index-75330f91aa5baa0a.js';init('/index-75330f91aa5baa0a_bg.wasm');</script></head>
<body>
</body></html>

View File

@ -3,11 +3,7 @@
<head>
<meta charset="utf-8">
<title>70年代、80年代、90年代怀旧、复古、回忆</title>
<script type="module">
import init from "./songday.js"
init()
</script>
<link rel="stylesheet" href="main.css">
<link rel="stylesheet" href="asset/purecss.min.css">
<style type="text/css">
body{padding:20px}
.tar{text-align:right}

View File

@ -85,7 +85,7 @@ impl Component for Model {
match msg {
Msg::Authenticated(user) => {
ConsoleService::log("signed in");
store::save(CommonVar::AUTH_HEADER_NAME, Some(user.access_token));
store::save(CommonVal::AUTH_HEADER_NAME, Some(user.access_token));
ConsoleService::log("saved auth to store");
self.user = Some(user.user_info);
return true;
@ -96,7 +96,7 @@ impl Component for Model {
self.fetch_task = Some(r);
},
Msg::LogoutResponse(Ok::<String, _>(s)) => {
store::save(CommonVar::AUTH_HEADER_NAME, None);
store::save(CommonVal::AUTH_HEADER_NAME, None);
ConsoleService::log("signed out");
self.user = None;
self.fetch_task = None;
@ -181,7 +181,7 @@ impl Component for Model {
fn rendered(&mut self, first_render: bool) {
// Get current user info if a token is available when mounted
if first_render {
let token = store::get(CommonVar::AUTH_HEADER_NAME);
let token = store::get(CommonVal::AUTH_HEADER_NAME);
if token.is_some() {
// let token = token.as_ref().unwrap();
let r = request::get(val::USER_INFO_URL, self.link.callback(Msg::UserInfoResponse));

View File

@ -6,7 +6,7 @@ use yew::{
};
use yew_router::{agent::RouteRequest::ChangeRoute, prelude::*};
use blog_common::dto::post::{PostDetail, NewPost, Tag};
use blog_common::dto::post::{NewPost, PostDetail, Tag};
use crate::{
app::AppRoute,

View File

@ -10,7 +10,7 @@ use yew::{
use yew_router::{agent::RouteRequest::ChangeRoute, prelude::*};
use blog_common::dto::{
post::{PostDetail, NewPost},
post::{NewPost, PostDetail},
PaginationData,
};