mirror of
https://github.com/Nutomic/ibis.git
synced 2024-11-22 18:41:09 +00:00
split api into separate files
This commit is contained in:
parent
02db60ba15
commit
f8da5ae965
7 changed files with 234 additions and 198 deletions
|
@ -1,46 +1,21 @@
|
||||||
use crate::database::article::{ArticleView, DbArticle, DbArticleForm};
|
use crate::database::article::{ArticleView, DbArticle, DbArticleForm};
|
||||||
use crate::database::conflict::{ApiConflict, DbConflict, DbConflictForm};
|
use crate::database::conflict::{ApiConflict, DbConflict, DbConflictForm};
|
||||||
use crate::database::edit::{DbEdit, DbEditForm};
|
use crate::database::edit::{DbEdit, DbEditForm};
|
||||||
use crate::database::instance::{DbInstance, InstanceView};
|
use crate::database::instance::DbInstance;
|
||||||
use crate::database::user::{DbLocalUser, DbPerson};
|
|
||||||
use crate::database::version::EditVersion;
|
use crate::database::version::EditVersion;
|
||||||
use crate::database::MyDataHandle;
|
use crate::database::MyDataHandle;
|
||||||
use crate::error::MyResult;
|
use crate::error::MyResult;
|
||||||
use crate::federation::activities::create_article::CreateArticle;
|
use crate::federation::activities::create_article::CreateArticle;
|
||||||
use crate::federation::activities::follow::Follow;
|
|
||||||
use crate::federation::activities::submit_article_update;
|
use crate::federation::activities::submit_article_update;
|
||||||
use crate::utils::generate_article_version;
|
use crate::utils::generate_article_version;
|
||||||
use activitypub_federation::config::Data;
|
use activitypub_federation::config::Data;
|
||||||
use activitypub_federation::fetch::object_id::ObjectId;
|
use activitypub_federation::fetch::object_id::ObjectId;
|
||||||
use anyhow::anyhow;
|
|
||||||
use axum::extract::Query;
|
use axum::extract::Query;
|
||||||
use axum::routing::{get, post};
|
use axum::Form;
|
||||||
use axum::{Form, Json, Router};
|
use axum::Json;
|
||||||
use axum_macros::debug_handler;
|
use axum_macros::debug_handler;
|
||||||
use bcrypt::verify;
|
|
||||||
use chrono::Utc;
|
|
||||||
use diffy::create_patch;
|
use diffy::create_patch;
|
||||||
use futures::future::try_join_all;
|
|
||||||
use jsonwebtoken::{encode, EncodingKey, Header};
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use url::Url;
|
|
||||||
|
|
||||||
pub fn api_routes() -> Router {
|
|
||||||
Router::new()
|
|
||||||
.route(
|
|
||||||
"/article",
|
|
||||||
get(get_article).post(create_article).patch(edit_article),
|
|
||||||
)
|
|
||||||
.route("/article/fork", post(fork_article))
|
|
||||||
.route("/edit_conflicts", get(edit_conflicts))
|
|
||||||
.route("/resolve_instance", get(resolve_instance))
|
|
||||||
.route("/resolve_article", get(resolve_article))
|
|
||||||
.route("/instance", get(get_local_instance))
|
|
||||||
.route("/instance/follow", post(follow_instance))
|
|
||||||
.route("/search", get(search_article))
|
|
||||||
.route("/user/register", post(register_user))
|
|
||||||
.route("/user/login", post(login_user))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
pub struct CreateArticleData {
|
pub struct CreateArticleData {
|
||||||
|
@ -49,7 +24,7 @@ pub struct CreateArticleData {
|
||||||
|
|
||||||
/// Create a new article with empty text, and federate it to followers.
|
/// Create a new article with empty text, and federate it to followers.
|
||||||
#[debug_handler]
|
#[debug_handler]
|
||||||
async fn create_article(
|
pub(in crate::api) async fn create_article(
|
||||||
data: Data<MyDataHandle>,
|
data: Data<MyDataHandle>,
|
||||||
Form(create_article): Form<CreateArticleData>,
|
Form(create_article): Form<CreateArticleData>,
|
||||||
) -> MyResult<Json<ArticleView>> {
|
) -> MyResult<Json<ArticleView>> {
|
||||||
|
@ -98,7 +73,7 @@ pub struct EditArticleData {
|
||||||
///
|
///
|
||||||
/// Conflicts are stored in the database so they can be retrieved later from `/api/v3/edit_conflicts`.
|
/// Conflicts are stored in the database so they can be retrieved later from `/api/v3/edit_conflicts`.
|
||||||
#[debug_handler]
|
#[debug_handler]
|
||||||
async fn edit_article(
|
pub(in crate::api) async fn edit_article(
|
||||||
data: Data<MyDataHandle>,
|
data: Data<MyDataHandle>,
|
||||||
Form(edit_form): Form<EditArticleData>,
|
Form(edit_form): Form<EditArticleData>,
|
||||||
) -> MyResult<Json<Option<ApiConflict>>> {
|
) -> MyResult<Json<Option<ApiConflict>>> {
|
||||||
|
@ -144,7 +119,7 @@ pub struct GetArticleData {
|
||||||
|
|
||||||
/// Retrieve an article by ID. It must already be stored in the local database.
|
/// Retrieve an article by ID. It must already be stored in the local database.
|
||||||
#[debug_handler]
|
#[debug_handler]
|
||||||
async fn get_article(
|
pub(in crate::api) async fn get_article(
|
||||||
Query(query): Query<GetArticleData>,
|
Query(query): Query<GetArticleData>,
|
||||||
data: Data<MyDataHandle>,
|
data: Data<MyDataHandle>,
|
||||||
) -> MyResult<Json<ArticleView>> {
|
) -> MyResult<Json<ArticleView>> {
|
||||||
|
@ -154,97 +129,6 @@ async fn get_article(
|
||||||
)?))
|
)?))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize)]
|
|
||||||
pub struct ResolveObject {
|
|
||||||
pub id: Url,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Fetch a remote instance actor. This automatically synchronizes the remote articles collection to
|
|
||||||
/// the local instance, and allows for interactions such as following.
|
|
||||||
#[debug_handler]
|
|
||||||
async fn resolve_instance(
|
|
||||||
Query(query): Query<ResolveObject>,
|
|
||||||
data: Data<MyDataHandle>,
|
|
||||||
) -> MyResult<Json<DbInstance>> {
|
|
||||||
let instance: DbInstance = ObjectId::from(query.id).dereference(&data).await?;
|
|
||||||
Ok(Json(instance))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Fetch a remote article, including edits collection. Allows viewing and editing. Note that new
|
|
||||||
/// article changes can only be received if we follow the instance, or if it is refetched manually.
|
|
||||||
#[debug_handler]
|
|
||||||
async fn resolve_article(
|
|
||||||
Query(query): Query<ResolveObject>,
|
|
||||||
data: Data<MyDataHandle>,
|
|
||||||
) -> MyResult<Json<ArticleView>> {
|
|
||||||
let article: DbArticle = ObjectId::from(query.id).dereference(&data).await?;
|
|
||||||
let edits = DbEdit::read_for_article(&article, &data.db_connection)?;
|
|
||||||
let latest_version = edits.last().unwrap().hash.clone();
|
|
||||||
Ok(Json(ArticleView {
|
|
||||||
article,
|
|
||||||
edits,
|
|
||||||
latest_version,
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Retrieve the local instance info.
|
|
||||||
#[debug_handler]
|
|
||||||
async fn get_local_instance(data: Data<MyDataHandle>) -> MyResult<Json<InstanceView>> {
|
|
||||||
let local_instance = DbInstance::read_local_view(&data.db_connection)?;
|
|
||||||
Ok(Json(local_instance))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, Debug)]
|
|
||||||
pub struct FollowInstance {
|
|
||||||
pub id: i32,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Make the local instance follow a given remote instance, to receive activities about new and
|
|
||||||
/// updated articles.
|
|
||||||
#[debug_handler]
|
|
||||||
async fn follow_instance(
|
|
||||||
data: Data<MyDataHandle>,
|
|
||||||
Form(query): Form<FollowInstance>,
|
|
||||||
) -> MyResult<()> {
|
|
||||||
let local_instance = DbInstance::read_local_instance(&data.db_connection)?;
|
|
||||||
let target = DbInstance::read(query.id, &data.db_connection)?;
|
|
||||||
let pending = !target.local;
|
|
||||||
DbInstance::follow(local_instance.id, target.id, pending, &data)?;
|
|
||||||
let instance = DbInstance::read(query.id, &data.db_connection)?;
|
|
||||||
Follow::send(local_instance, instance, &data).await?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get a list of all unresolved edit conflicts.
|
|
||||||
#[debug_handler]
|
|
||||||
async fn edit_conflicts(data: Data<MyDataHandle>) -> MyResult<Json<Vec<ApiConflict>>> {
|
|
||||||
let conflicts = DbConflict::list(&data.db_connection)?;
|
|
||||||
let conflicts: Vec<ApiConflict> = try_join_all(conflicts.into_iter().map(|c| {
|
|
||||||
let data = data.reset_request_count();
|
|
||||||
async move { c.to_api_conflict(&data).await }
|
|
||||||
}))
|
|
||||||
.await?
|
|
||||||
.into_iter()
|
|
||||||
.flatten()
|
|
||||||
.collect();
|
|
||||||
Ok(Json(conflicts))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, Clone)]
|
|
||||||
pub struct SearchArticleData {
|
|
||||||
pub query: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Search articles for matching title or body text.
|
|
||||||
#[debug_handler]
|
|
||||||
async fn search_article(
|
|
||||||
Query(query): Query<SearchArticleData>,
|
|
||||||
data: Data<MyDataHandle>,
|
|
||||||
) -> MyResult<Json<Vec<DbArticle>>> {
|
|
||||||
let article = DbArticle::search(&query.query, &data.db_connection)?;
|
|
||||||
Ok(Json(article))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
pub struct ForkArticleData {
|
pub struct ForkArticleData {
|
||||||
// TODO: could add optional param new_title so there is no problem with title collision
|
// TODO: could add optional param new_title so there is no problem with title collision
|
||||||
|
@ -256,7 +140,7 @@ pub struct ForkArticleData {
|
||||||
/// Fork a remote article to local instance. This is useful if there are disagreements about
|
/// Fork a remote article to local instance. This is useful if there are disagreements about
|
||||||
/// how an article should be edited.
|
/// how an article should be edited.
|
||||||
#[debug_handler]
|
#[debug_handler]
|
||||||
async fn fork_article(
|
pub(in crate::api) async fn fork_article(
|
||||||
data: Data<MyDataHandle>,
|
data: Data<MyDataHandle>,
|
||||||
Form(fork_form): Form<ForkArticleData>,
|
Form(fork_form): Form<ForkArticleData>,
|
||||||
) -> MyResult<Json<ArticleView>> {
|
) -> MyResult<Json<ArticleView>> {
|
||||||
|
@ -298,69 +182,3 @@ async fn fork_article(
|
||||||
|
|
||||||
Ok(Json(DbArticle::read_view(article.id, &data.db_connection)?))
|
Ok(Json(DbArticle::read_view(article.id, &data.db_connection)?))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
|
||||||
pub struct Claims {
|
|
||||||
/// local_user.id
|
|
||||||
pub sub: String,
|
|
||||||
/// hostname
|
|
||||||
pub iss: String,
|
|
||||||
/// Creation time as unix timestamp
|
|
||||||
pub iat: i64,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn generate_login_token(
|
|
||||||
local_user: DbLocalUser,
|
|
||||||
data: &Data<MyDataHandle>,
|
|
||||||
) -> MyResult<LoginResponse> {
|
|
||||||
let hostname = data.domain().to_string();
|
|
||||||
let claims = Claims {
|
|
||||||
sub: local_user.id.to_string(),
|
|
||||||
iss: hostname,
|
|
||||||
iat: Utc::now().timestamp(),
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: move to config
|
|
||||||
let key = EncodingKey::from_secret("secret".as_bytes());
|
|
||||||
let jwt = encode(&Header::default(), &claims, &key)?;
|
|
||||||
Ok(LoginResponse { jwt })
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize)]
|
|
||||||
pub struct RegisterUserData {
|
|
||||||
pub name: String,
|
|
||||||
pub password: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize)]
|
|
||||||
pub struct LoginResponse {
|
|
||||||
pub jwt: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[debug_handler]
|
|
||||||
async fn register_user(
|
|
||||||
data: Data<MyDataHandle>,
|
|
||||||
Form(form): Form<RegisterUserData>,
|
|
||||||
) -> MyResult<Json<LoginResponse>> {
|
|
||||||
let user = DbPerson::create_local(form.name, form.password, &data)?;
|
|
||||||
Ok(Json(generate_login_token(user.local_user, &data)?))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize)]
|
|
||||||
pub struct LoginUserData {
|
|
||||||
name: String,
|
|
||||||
password: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[debug_handler]
|
|
||||||
async fn login_user(
|
|
||||||
data: Data<MyDataHandle>,
|
|
||||||
Form(form): Form<LoginUserData>,
|
|
||||||
) -> MyResult<Json<LoginResponse>> {
|
|
||||||
let user = DbPerson::read_local_from_name(&form.name, &data)?;
|
|
||||||
let valid = verify(&form.password, &user.local_user.password_encrypted)?;
|
|
||||||
if !valid {
|
|
||||||
return Err(anyhow!("Invalid login").into());
|
|
||||||
}
|
|
||||||
Ok(Json(generate_login_token(user.local_user, &data)?))
|
|
||||||
}
|
|
38
src/api/instance.rs
Normal file
38
src/api/instance.rs
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
use crate::database::instance::{DbInstance, InstanceView};
|
||||||
|
use crate::database::MyDataHandle;
|
||||||
|
use crate::error::MyResult;
|
||||||
|
use crate::federation::activities::follow::Follow;
|
||||||
|
use activitypub_federation::config::Data;
|
||||||
|
use axum::{Form, Json};
|
||||||
|
use axum_macros::debug_handler;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
/// Retrieve the local instance info.
|
||||||
|
#[debug_handler]
|
||||||
|
pub(in crate::api) async fn get_local_instance(
|
||||||
|
data: Data<MyDataHandle>,
|
||||||
|
) -> MyResult<Json<InstanceView>> {
|
||||||
|
let local_instance = DbInstance::read_local_view(&data.db_connection)?;
|
||||||
|
Ok(Json(local_instance))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize, Debug)]
|
||||||
|
pub struct FollowInstance {
|
||||||
|
pub id: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Make the local instance follow a given remote instance, to receive activities about new and
|
||||||
|
/// updated articles.
|
||||||
|
#[debug_handler]
|
||||||
|
pub(in crate::api) async fn follow_instance(
|
||||||
|
data: Data<MyDataHandle>,
|
||||||
|
Form(query): Form<FollowInstance>,
|
||||||
|
) -> MyResult<()> {
|
||||||
|
let local_instance = DbInstance::read_local_instance(&data.db_connection)?;
|
||||||
|
let target = DbInstance::read(query.id, &data.db_connection)?;
|
||||||
|
let pending = !target.local;
|
||||||
|
DbInstance::follow(local_instance.id, target.id, pending, &data)?;
|
||||||
|
let instance = DbInstance::read(query.id, &data.db_connection)?;
|
||||||
|
Follow::send(local_instance, instance, &data).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
105
src/api/mod.rs
Normal file
105
src/api/mod.rs
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
use crate::api::article::create_article;
|
||||||
|
use crate::api::article::{edit_article, fork_article, get_article};
|
||||||
|
use crate::api::instance::follow_instance;
|
||||||
|
use crate::api::instance::get_local_instance;
|
||||||
|
use crate::api::user::login_user;
|
||||||
|
use crate::api::user::register_user;
|
||||||
|
use crate::database::article::{ArticleView, DbArticle};
|
||||||
|
use crate::database::conflict::{ApiConflict, DbConflict};
|
||||||
|
use crate::database::edit::DbEdit;
|
||||||
|
use crate::database::instance::DbInstance;
|
||||||
|
use crate::database::MyDataHandle;
|
||||||
|
use crate::error::MyResult;
|
||||||
|
use activitypub_federation::config::Data;
|
||||||
|
use activitypub_federation::fetch::object_id::ObjectId;
|
||||||
|
use axum::extract::Query;
|
||||||
|
use axum::routing::{get, post};
|
||||||
|
use axum::{Json, Router};
|
||||||
|
use axum_macros::debug_handler;
|
||||||
|
use futures::future::try_join_all;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
|
pub mod article;
|
||||||
|
pub mod instance;
|
||||||
|
pub mod user;
|
||||||
|
|
||||||
|
pub fn api_routes() -> Router {
|
||||||
|
Router::new()
|
||||||
|
.route(
|
||||||
|
"/article",
|
||||||
|
get(get_article).post(create_article).patch(edit_article),
|
||||||
|
)
|
||||||
|
.route("/article/fork", post(fork_article))
|
||||||
|
.route("/edit_conflicts", get(edit_conflicts))
|
||||||
|
.route("/resolve_instance", get(resolve_instance))
|
||||||
|
.route("/resolve_article", get(resolve_article))
|
||||||
|
.route("/instance", get(get_local_instance))
|
||||||
|
.route("/instance/follow", post(follow_instance))
|
||||||
|
.route("/search", get(search_article))
|
||||||
|
.route("/user/register", post(register_user))
|
||||||
|
.route("/user/login", post(login_user))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
pub struct ResolveObject {
|
||||||
|
pub id: Url,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Fetch a remote instance actor. This automatically synchronizes the remote articles collection to
|
||||||
|
/// the local instance, and allows for interactions such as following.
|
||||||
|
#[debug_handler]
|
||||||
|
async fn resolve_instance(
|
||||||
|
Query(query): Query<ResolveObject>,
|
||||||
|
data: Data<MyDataHandle>,
|
||||||
|
) -> MyResult<Json<DbInstance>> {
|
||||||
|
let instance: DbInstance = ObjectId::from(query.id).dereference(&data).await?;
|
||||||
|
Ok(Json(instance))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Fetch a remote article, including edits collection. Allows viewing and editing. Note that new
|
||||||
|
/// article changes can only be received if we follow the instance, or if it is refetched manually.
|
||||||
|
#[debug_handler]
|
||||||
|
async fn resolve_article(
|
||||||
|
Query(query): Query<ResolveObject>,
|
||||||
|
data: Data<MyDataHandle>,
|
||||||
|
) -> MyResult<Json<ArticleView>> {
|
||||||
|
let article: DbArticle = ObjectId::from(query.id).dereference(&data).await?;
|
||||||
|
let edits = DbEdit::read_for_article(&article, &data.db_connection)?;
|
||||||
|
let latest_version = edits.last().unwrap().hash.clone();
|
||||||
|
Ok(Json(ArticleView {
|
||||||
|
article,
|
||||||
|
edits,
|
||||||
|
latest_version,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a list of all unresolved edit conflicts.
|
||||||
|
#[debug_handler]
|
||||||
|
async fn edit_conflicts(data: Data<MyDataHandle>) -> MyResult<Json<Vec<ApiConflict>>> {
|
||||||
|
let conflicts = DbConflict::list(&data.db_connection)?;
|
||||||
|
let conflicts: Vec<ApiConflict> = try_join_all(conflicts.into_iter().map(|c| {
|
||||||
|
let data = data.reset_request_count();
|
||||||
|
async move { c.to_api_conflict(&data).await }
|
||||||
|
}))
|
||||||
|
.await?
|
||||||
|
.into_iter()
|
||||||
|
.flatten()
|
||||||
|
.collect();
|
||||||
|
Ok(Json(conflicts))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize, Clone)]
|
||||||
|
pub struct SearchArticleData {
|
||||||
|
pub query: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Search articles for matching title or body text.
|
||||||
|
#[debug_handler]
|
||||||
|
async fn search_article(
|
||||||
|
Query(query): Query<SearchArticleData>,
|
||||||
|
data: Data<MyDataHandle>,
|
||||||
|
) -> MyResult<Json<Vec<DbArticle>>> {
|
||||||
|
let article = DbArticle::search(&query.query, &data.db_connection)?;
|
||||||
|
Ok(Json(article))
|
||||||
|
}
|
77
src/api/user.rs
Normal file
77
src/api/user.rs
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
use crate::database::user::{DbLocalUser, DbPerson};
|
||||||
|
use crate::database::MyDataHandle;
|
||||||
|
use crate::error::MyResult;
|
||||||
|
use activitypub_federation::config::Data;
|
||||||
|
use anyhow::anyhow;
|
||||||
|
use axum::{Form, Json};
|
||||||
|
use axum_macros::debug_handler;
|
||||||
|
use bcrypt::verify;
|
||||||
|
use chrono::Utc;
|
||||||
|
use jsonwebtoken::{encode, EncodingKey, Header};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub struct Claims {
|
||||||
|
/// local_user.id
|
||||||
|
pub sub: String,
|
||||||
|
/// hostname
|
||||||
|
pub iss: String,
|
||||||
|
/// Creation time as unix timestamp
|
||||||
|
pub iat: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(in crate::api) fn generate_login_token(
|
||||||
|
local_user: DbLocalUser,
|
||||||
|
data: &Data<MyDataHandle>,
|
||||||
|
) -> MyResult<LoginResponse> {
|
||||||
|
let hostname = data.domain().to_string();
|
||||||
|
let claims = Claims {
|
||||||
|
sub: local_user.id.to_string(),
|
||||||
|
iss: hostname,
|
||||||
|
iat: Utc::now().timestamp(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: move to config
|
||||||
|
let key = EncodingKey::from_secret("secret".as_bytes());
|
||||||
|
let jwt = encode(&Header::default(), &claims, &key)?;
|
||||||
|
Ok(LoginResponse { jwt })
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
pub struct RegisterUserData {
|
||||||
|
pub name: String,
|
||||||
|
pub password: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
pub struct LoginResponse {
|
||||||
|
pub jwt: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[debug_handler]
|
||||||
|
pub(in crate::api) async fn register_user(
|
||||||
|
data: Data<MyDataHandle>,
|
||||||
|
Form(form): Form<RegisterUserData>,
|
||||||
|
) -> MyResult<Json<LoginResponse>> {
|
||||||
|
let user = DbPerson::create_local(form.name, form.password, &data)?;
|
||||||
|
Ok(Json(generate_login_token(user.local_user, &data)?))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
pub struct LoginUserData {
|
||||||
|
name: String,
|
||||||
|
password: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[debug_handler]
|
||||||
|
pub(in crate::api) async fn login_user(
|
||||||
|
data: Data<MyDataHandle>,
|
||||||
|
Form(form): Form<LoginUserData>,
|
||||||
|
) -> MyResult<Json<LoginResponse>> {
|
||||||
|
let user = DbPerson::read_local_from_name(&form.name, &data)?;
|
||||||
|
let valid = verify(&form.password, &user.local_user.password_encrypted)?;
|
||||||
|
if !valid {
|
||||||
|
return Err(anyhow!("Invalid login").into());
|
||||||
|
}
|
||||||
|
Ok(Json(generate_login_token(user.local_user, &data)?))
|
||||||
|
}
|
|
@ -1,4 +1,3 @@
|
||||||
use crate::api::api_routes;
|
|
||||||
use crate::database::instance::{DbInstance, DbInstanceForm};
|
use crate::database::instance::{DbInstance, DbInstanceForm};
|
||||||
use crate::database::MyData;
|
use crate::database::MyData;
|
||||||
use crate::error::MyResult;
|
use crate::error::MyResult;
|
||||||
|
@ -8,6 +7,7 @@ use activitypub_federation::config::{FederationConfig, FederationMiddleware};
|
||||||
use activitypub_federation::fetch::collection_id::CollectionId;
|
use activitypub_federation::fetch::collection_id::CollectionId;
|
||||||
use activitypub_federation::fetch::object_id::ObjectId;
|
use activitypub_federation::fetch::object_id::ObjectId;
|
||||||
use activitypub_federation::http_signatures::generate_actor_keypair;
|
use activitypub_federation::http_signatures::generate_actor_keypair;
|
||||||
|
use api::api_routes;
|
||||||
use axum::{Router, Server};
|
use axum::{Router, Server};
|
||||||
use chrono::Local;
|
use chrono::Local;
|
||||||
use diesel::Connection;
|
use diesel::Connection;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use fediwiki::api::{
|
use fediwiki::api::article::{CreateArticleData, EditArticleData, GetArticleData};
|
||||||
CreateArticleData, EditArticleData, FollowInstance, GetArticleData, ResolveObject,
|
use fediwiki::api::instance::FollowInstance;
|
||||||
};
|
use fediwiki::api::ResolveObject;
|
||||||
use fediwiki::database::article::ArticleView;
|
use fediwiki::database::article::ArticleView;
|
||||||
use fediwiki::database::conflict::ApiConflict;
|
use fediwiki::database::conflict::ApiConflict;
|
||||||
use fediwiki::database::instance::DbInstance;
|
use fediwiki::database::instance::DbInstance;
|
||||||
|
@ -20,7 +20,6 @@ use std::thread::{sleep, spawn};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use tokio::task::JoinHandle;
|
use tokio::task::JoinHandle;
|
||||||
use tracing::log::LevelFilter;
|
use tracing::log::LevelFilter;
|
||||||
use tracing::warn;
|
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
pub static CLIENT: Lazy<Client> = Lazy::new(Client::new);
|
pub static CLIENT: Lazy<Client> = Lazy::new(Client::new);
|
||||||
|
|
|
@ -7,10 +7,9 @@ use crate::common::{
|
||||||
get_query, post, TestData, TEST_ARTICLE_DEFAULT_TEXT,
|
get_query, post, TestData, TEST_ARTICLE_DEFAULT_TEXT,
|
||||||
};
|
};
|
||||||
use common::get;
|
use common::get;
|
||||||
use fediwiki::api::{
|
use fediwiki::api::article::{EditArticleData, ForkArticleData};
|
||||||
EditArticleData, ForkArticleData, LoginResponse, RegisterUserData, ResolveObject,
|
use fediwiki::api::user::{LoginResponse, RegisterUserData};
|
||||||
SearchArticleData,
|
use fediwiki::api::{ResolveObject, SearchArticleData};
|
||||||
};
|
|
||||||
use fediwiki::database::article::{ArticleView, DbArticle};
|
use fediwiki::database::article::{ArticleView, DbArticle};
|
||||||
use fediwiki::database::conflict::ApiConflict;
|
use fediwiki::database::conflict::ApiConflict;
|
||||||
use fediwiki::database::instance::{DbInstance, InstanceView};
|
use fediwiki::database::instance::{DbInstance, InstanceView};
|
||||||
|
|
Loading…
Reference in a new issue