1
0
Fork 0
mirror of https://github.com/Nutomic/ibis.git synced 2025-02-02 22:41:35 +00:00

Rename IbisData to IbisContext

This commit is contained in:
Felix Ableitner 2025-01-21 15:50:24 +01:00
parent 696ba19a2f
commit 3d1beefe14
40 changed files with 598 additions and 550 deletions

View file

@ -5,7 +5,7 @@ use crate::{
article::DbArticleForm, article::DbArticleForm,
conflict::{DbConflict, DbConflictForm}, conflict::{DbConflict, DbConflictForm},
edit::DbEditForm, edit::DbEditForm,
IbisData, IbisContext,
}, },
federation::activities::{create_article::CreateArticle, submit_article_update}, federation::activities::{create_article::CreateArticle, submit_article_update},
utils::{ utils::{
@ -50,13 +50,13 @@ use diffy::create_patch;
#[debug_handler] #[debug_handler]
pub(in crate::backend::api) async fn create_article( pub(in crate::backend::api) async fn create_article(
user: Extension<LocalUserView>, user: Extension<LocalUserView>,
data: Data<IbisData>, context: Data<IbisContext>,
Form(mut params): Form<CreateArticleParams>, Form(mut params): Form<CreateArticleParams>,
) -> MyResult<Json<DbArticleView>> { ) -> MyResult<Json<DbArticleView>> {
params.title = validate_article_title(&params.title)?; params.title = validate_article_title(&params.title)?;
validate_not_empty(&params.text)?; validate_not_empty(&params.text)?;
let local_instance = DbInstance::read_local(&data)?; let local_instance = DbInstance::read_local(&context)?;
let ap_id = ObjectId::parse(&format!( let ap_id = ObjectId::parse(&format!(
"{}://{}/article/{}", "{}://{}/article/{}",
http_protocol_str(), http_protocol_str(),
@ -70,23 +70,23 @@ pub(in crate::backend::api) async fn create_article(
instance_id: local_instance.id, instance_id: local_instance.id,
local: true, local: true,
protected: false, protected: false,
approved: !data.config.options.article_approval, approved: !context.config.options.article_approval,
}; };
let article = DbArticle::create(form, &data)?; let article = DbArticle::create(form, &context)?;
let edit_data = EditArticleParams { let edit_data = EditArticleParams {
article_id: article.id, article_id: article.id,
new_text: params.text, new_text: params.text,
summary: params.summary, summary: params.summary,
previous_version_id: article.latest_edit_version(&data)?, previous_version_id: article.latest_edit_version(&context)?,
resolve_conflict_id: None, resolve_conflict_id: None,
}; };
let _ = edit_article(user, data.reset_request_count(), Form(edit_data)).await?; let _ = edit_article(user, context.reset_request_count(), Form(edit_data)).await?;
// allow reading unapproved article here // allow reading unapproved article here
let article_view = DbArticle::read_view(article.id, &data)?; let article_view = DbArticle::read_view(article.id, &context)?;
CreateArticle::send_to_followers(article_view.article.clone(), &data).await?; CreateArticle::send_to_followers(article_view.article.clone(), &context).await?;
Ok(Json(article_view)) Ok(Json(article_view))
} }
@ -103,15 +103,15 @@ pub(in crate::backend::api) async fn create_article(
#[debug_handler] #[debug_handler]
pub(in crate::backend::api) async fn edit_article( pub(in crate::backend::api) async fn edit_article(
Extension(user): Extension<LocalUserView>, Extension(user): Extension<LocalUserView>,
data: Data<IbisData>, context: Data<IbisContext>,
Form(mut params): Form<EditArticleParams>, Form(mut params): Form<EditArticleParams>,
) -> MyResult<Json<Option<ApiConflict>>> { ) -> MyResult<Json<Option<ApiConflict>>> {
validate_not_empty(&params.new_text)?; validate_not_empty(&params.new_text)?;
// resolve conflict if any // resolve conflict if any
if let Some(resolve_conflict_id) = params.resolve_conflict_id { if let Some(resolve_conflict_id) = params.resolve_conflict_id {
DbConflict::delete(resolve_conflict_id, user.person.id, &data)?; DbConflict::delete(resolve_conflict_id, user.person.id, &context)?;
} }
let original_article = DbArticle::read_view(params.article_id, &data)?; let original_article = DbArticle::read_view(params.article_id, &context)?;
if params.new_text == original_article.article.text { if params.new_text == original_article.article.text {
return Err(anyhow!("Edit contains no changes").into()); return Err(anyhow!("Edit contains no changes").into());
} }
@ -123,7 +123,7 @@ pub(in crate::backend::api) async fn edit_article(
if !params.new_text.ends_with('\n') { if !params.new_text.ends_with('\n') {
params.new_text.push('\n'); params.new_text.push('\n');
} }
let local_link = format!("](https://{}", data.config.federation.domain); let local_link = format!("](https://{}", context.config.federation.domain);
if params.new_text.contains(&local_link) { if params.new_text.contains(&local_link) {
return Err(anyhow!("Links to local instance don't work over federation").into()); return Err(anyhow!("Links to local instance don't work over federation").into());
} }
@ -139,18 +139,18 @@ pub(in crate::backend::api) async fn edit_article(
params.previous_version_id, params.previous_version_id,
&original_article.article, &original_article.article,
user.person.id, user.person.id,
&data, &context,
) )
.await?; .await?;
Ok(Json(None)) Ok(Json(None))
} else { } else {
// There have been other changes since this edit was initiated. Get the common ancestor // There have been other changes since this edit was initiated. Get the common ancestor
// version and generate a diff to find out what exactly has changed. // version and generate a diff to find out what exactly has changed.
let edits = DbEdit::list_for_article(original_article.article.id, &data)?; let edits = DbEdit::list_for_article(original_article.article.id, &context)?;
let ancestor = generate_article_version(&edits, &params.previous_version_id)?; let ancestor = generate_article_version(&edits, &params.previous_version_id)?;
let patch = create_patch(&ancestor, &new_text); let patch = create_patch(&ancestor, &new_text);
let previous_version = DbEdit::read(&params.previous_version_id, &data)?; let previous_version = DbEdit::read(&params.previous_version_id, &context)?;
let form = DbConflictForm { let form = DbConflictForm {
hash: EditVersion::new(&patch.to_string()), hash: EditVersion::new(&patch.to_string()),
diff: patch.to_string(), diff: patch.to_string(),
@ -159,8 +159,8 @@ pub(in crate::backend::api) async fn edit_article(
article_id: original_article.article.id, article_id: original_article.article.id,
previous_version_id: previous_version.hash, previous_version_id: previous_version.hash,
}; };
let conflict = DbConflict::create(&form, &data)?; let conflict = DbConflict::create(&form, &context)?;
Ok(Json(conflict.to_api_conflict(&data).await?)) Ok(Json(conflict.to_api_conflict(&context).await?))
} }
} }
@ -168,19 +168,19 @@ pub(in crate::backend::api) async fn edit_article(
#[debug_handler] #[debug_handler]
pub(in crate::backend::api) async fn get_article( pub(in crate::backend::api) async fn get_article(
Query(query): Query<GetArticleParams>, Query(query): Query<GetArticleParams>,
data: Data<IbisData>, context: Data<IbisContext>,
) -> MyResult<Json<DbArticleView>> { ) -> MyResult<Json<DbArticleView>> {
match (query.title, query.id) { match (query.title, query.id) {
(Some(title), None) => Ok(Json(DbArticle::read_view_title( (Some(title), None) => Ok(Json(DbArticle::read_view_title(
&title, &title,
query.domain, query.domain,
&data, &context,
)?)), )?)),
(None, Some(id)) => { (None, Some(id)) => {
if query.domain.is_some() { if query.domain.is_some() {
return Err(anyhow!("Cant combine id and instance_domain").into()); return Err(anyhow!("Cant combine id and instance_domain").into());
} }
let article = DbArticle::read_view(id, &data)?; let article = DbArticle::read_view(id, &context)?;
Ok(Json(article)) Ok(Json(article))
} }
_ => Err(anyhow!("Must pass exactly one of title, id").into()), _ => Err(anyhow!("Must pass exactly one of title, id").into()),
@ -190,12 +190,12 @@ pub(in crate::backend::api) async fn get_article(
#[debug_handler] #[debug_handler]
pub(in crate::backend::api) async fn list_articles( pub(in crate::backend::api) async fn list_articles(
Query(query): Query<ListArticlesParams>, Query(query): Query<ListArticlesParams>,
data: Data<IbisData>, context: Data<IbisContext>,
) -> MyResult<Json<Vec<DbArticle>>> { ) -> MyResult<Json<Vec<DbArticle>>> {
Ok(Json(DbArticle::read_all( Ok(Json(DbArticle::read_all(
query.only_local, query.only_local,
query.instance_id, query.instance_id,
&data, &context,
)?)) )?))
} }
@ -204,14 +204,14 @@ pub(in crate::backend::api) async fn list_articles(
#[debug_handler] #[debug_handler]
pub(in crate::backend::api) async fn fork_article( pub(in crate::backend::api) async fn fork_article(
Extension(_user): Extension<LocalUserView>, Extension(_user): Extension<LocalUserView>,
data: Data<IbisData>, context: Data<IbisContext>,
Form(mut params): Form<ForkArticleParams>, Form(mut params): Form<ForkArticleParams>,
) -> MyResult<Json<DbArticleView>> { ) -> MyResult<Json<DbArticleView>> {
// TODO: lots of code duplicated from create_article(), can move it into helper // TODO: lots of code duplicated from create_article(), can move it into helper
let original_article = DbArticle::read_view(params.article_id, &data)?; let original_article = DbArticle::read_view(params.article_id, &context)?;
params.new_title = validate_article_title(&params.new_title)?; params.new_title = validate_article_title(&params.new_title)?;
let local_instance = DbInstance::read_local(&data)?; let local_instance = DbInstance::read_local(&context)?;
let ap_id = ObjectId::parse(&format!( let ap_id = ObjectId::parse(&format!(
"{}://{}/article/{}", "{}://{}/article/{}",
http_protocol_str(), http_protocol_str(),
@ -225,14 +225,14 @@ pub(in crate::backend::api) async fn fork_article(
instance_id: local_instance.id, instance_id: local_instance.id,
local: true, local: true,
protected: false, protected: false,
approved: !data.config.options.article_approval, approved: !context.config.options.article_approval,
}; };
let article = DbArticle::create(form, &data)?; let article = DbArticle::create(form, &context)?;
// copy edits to new article // copy edits to new article
// this could also be done in sql // this could also be done in sql
let edits = DbEdit::list_for_article(original_article.article.id, &data)?; let edits = DbEdit::list_for_article(original_article.article.id, &context)?;
for e in edits { for e in edits {
let ap_id = DbEditForm::generate_ap_id(&article, &e.hash)?; let ap_id = DbEditForm::generate_ap_id(&article, &e.hash)?;
let form = DbEditForm { let form = DbEditForm {
@ -246,12 +246,12 @@ pub(in crate::backend::api) async fn fork_article(
published: Utc::now(), published: Utc::now(),
pending: false, pending: false,
}; };
DbEdit::create(&form, &data)?; DbEdit::create(&form, &context)?;
} }
CreateArticle::send_to_followers(article.clone(), &data).await?; CreateArticle::send_to_followers(article.clone(), &context).await?;
Ok(Json(DbArticle::read_view(article.id, &data)?)) Ok(Json(DbArticle::read_view(article.id, &context)?))
} }
/// Fetch a remote article, including edits collection. Allows viewing and editing. Note that new /// Fetch a remote article, including edits collection. Allows viewing and editing. Note that new
@ -259,12 +259,12 @@ pub(in crate::backend::api) async fn fork_article(
#[debug_handler] #[debug_handler]
pub(super) async fn resolve_article( pub(super) async fn resolve_article(
Query(query): Query<ResolveObjectParams>, Query(query): Query<ResolveObjectParams>,
data: Data<IbisData>, context: Data<IbisContext>,
) -> MyResult<Json<DbArticleView>> { ) -> MyResult<Json<DbArticleView>> {
let article: DbArticle = ObjectId::from(query.id).dereference(&data).await?; let article: DbArticle = ObjectId::from(query.id).dereference(&context).await?;
let instance = DbInstance::read(article.instance_id, &data)?; let instance = DbInstance::read(article.instance_id, &context)?;
let comments = DbComment::read_for_article(article.id, &data)?; let comments = DbComment::read_for_article(article.id, &context)?;
let latest_version = article.latest_edit_version(&data)?; let latest_version = article.latest_edit_version(&context)?;
Ok(Json(DbArticleView { Ok(Json(DbArticleView {
article, article,
instance, instance,
@ -277,23 +277,23 @@ pub(super) async fn resolve_article(
#[debug_handler] #[debug_handler]
pub(super) async fn search_article( pub(super) async fn search_article(
Query(query): Query<SearchArticleParams>, Query(query): Query<SearchArticleParams>,
data: Data<IbisData>, context: Data<IbisContext>,
) -> MyResult<Json<Vec<DbArticle>>> { ) -> MyResult<Json<Vec<DbArticle>>> {
if query.query.is_empty() { if query.query.is_empty() {
return Err(anyhow!("Query is empty").into()); return Err(anyhow!("Query is empty").into());
} }
let article = DbArticle::search(&query.query, &data)?; let article = DbArticle::search(&query.query, &context)?;
Ok(Json(article)) Ok(Json(article))
} }
#[debug_handler] #[debug_handler]
pub(in crate::backend::api) async fn protect_article( pub(in crate::backend::api) async fn protect_article(
Extension(user): Extension<LocalUserView>, Extension(user): Extension<LocalUserView>,
data: Data<IbisData>, context: Data<IbisContext>,
Form(params): Form<ProtectArticleParams>, Form(params): Form<ProtectArticleParams>,
) -> MyResult<Json<DbArticle>> { ) -> MyResult<Json<DbArticle>> {
check_is_admin(&user)?; check_is_admin(&user)?;
let article = DbArticle::update_protected(params.article_id, params.protected, &data)?; let article = DbArticle::update_protected(params.article_id, params.protected, &context)?;
Ok(Json(article)) Ok(Json(article))
} }
@ -301,14 +301,14 @@ pub(in crate::backend::api) async fn protect_article(
#[debug_handler] #[debug_handler]
pub async fn approve_article( pub async fn approve_article(
Extension(user): Extension<LocalUserView>, Extension(user): Extension<LocalUserView>,
data: Data<IbisData>, context: Data<IbisContext>,
Form(params): Form<ApproveArticleParams>, Form(params): Form<ApproveArticleParams>,
) -> MyResult<Json<()>> { ) -> MyResult<Json<()>> {
check_is_admin(&user)?; check_is_admin(&user)?;
if params.approve { if params.approve {
DbArticle::update_approved(params.article_id, true, &data)?; DbArticle::update_approved(params.article_id, true, &context)?;
} else { } else {
DbArticle::delete(params.article_id, &data)?; DbArticle::delete(params.article_id, &context)?;
} }
Ok(Json(())) Ok(Json(()))
} }
@ -317,9 +317,9 @@ pub async fn approve_article(
#[debug_handler] #[debug_handler]
pub async fn delete_conflict( pub async fn delete_conflict(
Extension(user): Extension<LocalUserView>, Extension(user): Extension<LocalUserView>,
data: Data<IbisData>, context: Data<IbisContext>,
Form(params): Form<DeleteConflictParams>, Form(params): Form<DeleteConflictParams>,
) -> MyResult<Json<()>> { ) -> MyResult<Json<()>> {
DbConflict::delete(params.conflict_id, user.person.id, &data)?; DbConflict::delete(params.conflict_id, user.person.id, &context)?;
Ok(Json(())) Ok(Json(()))
} }

View file

@ -2,7 +2,7 @@ use crate::{
backend::{ backend::{
database::{ database::{
comment::{DbCommentInsertForm, DbCommentUpdateForm}, comment::{DbCommentInsertForm, DbCommentUpdateForm},
IbisData, IbisContext,
}, },
federation::activities::comment::{ federation::activities::comment::{
create_or_update_comment::CreateOrUpdateComment, create_or_update_comment::CreateOrUpdateComment,
@ -29,13 +29,13 @@ use chrono::Utc;
#[debug_handler] #[debug_handler]
pub(in crate::backend::api) async fn create_comment( pub(in crate::backend::api) async fn create_comment(
user: Extension<LocalUserView>, user: Extension<LocalUserView>,
data: Data<IbisData>, context: Data<IbisContext>,
Form(params): Form<CreateCommentParams>, Form(params): Form<CreateCommentParams>,
) -> MyResult<Json<DbCommentView>> { ) -> MyResult<Json<DbCommentView>> {
validate_not_empty(&params.content)?; validate_not_empty(&params.content)?;
let mut depth = 0; let mut depth = 0;
if let Some(parent_id) = params.parent_id { if let Some(parent_id) = params.parent_id {
let parent = DbComment::read(parent_id, &data)?; let parent = DbComment::read(parent_id, &context)?;
if parent.deleted { if parent.deleted {
return Err(anyhow!("Cant reply to deleted comment").into()); return Err(anyhow!("Cant reply to deleted comment").into());
} }
@ -57,18 +57,18 @@ pub(in crate::backend::api) async fn create_comment(
published: Utc::now(), published: Utc::now(),
updated: None, updated: None,
}; };
let comment = DbComment::create(form, &data)?; let comment = DbComment::create(form, &context)?;
// Set the ap_id which contains db id (so it is not know before inserting) // Set the ap_id which contains db id (so it is not know before inserting)
let proto = http_protocol_str(); let proto = http_protocol_str();
let ap_id = format!("{}://{}/comment/{}", proto, data.domain(), comment.id.0).parse()?; let ap_id = format!("{}://{}/comment/{}", proto, context.domain(), comment.id.0).parse()?;
let form = DbCommentUpdateForm { let form = DbCommentUpdateForm {
ap_id: Some(ap_id), ap_id: Some(ap_id),
..Default::default() ..Default::default()
}; };
let comment = DbComment::update(form, comment.id, &data)?; let comment = DbComment::update(form, comment.id, &context)?;
CreateOrUpdateComment::send(&comment.comment, &data).await?; CreateOrUpdateComment::send(&comment.comment, &context).await?;
Ok(Json(comment)) Ok(Json(comment))
} }
@ -76,7 +76,7 @@ pub(in crate::backend::api) async fn create_comment(
#[debug_handler] #[debug_handler]
pub(in crate::backend::api) async fn edit_comment( pub(in crate::backend::api) async fn edit_comment(
user: Extension<LocalUserView>, user: Extension<LocalUserView>,
data: Data<IbisData>, context: Data<IbisContext>,
Form(params): Form<EditCommentParams>, Form(params): Form<EditCommentParams>,
) -> MyResult<Json<DbCommentView>> { ) -> MyResult<Json<DbCommentView>> {
if let Some(content) = &params.content { if let Some(content) = &params.content {
@ -85,7 +85,7 @@ pub(in crate::backend::api) async fn edit_comment(
if params.content.is_none() && params.deleted.is_none() { if params.content.is_none() && params.deleted.is_none() {
return Err(anyhow!("Edit has no parameters").into()); return Err(anyhow!("Edit has no parameters").into());
} }
let orig_comment = DbComment::read(params.id, &data)?; let orig_comment = DbComment::read(params.id, &context)?;
if orig_comment.creator_id != user.person.id { if orig_comment.creator_id != user.person.id {
return Err(anyhow!("Cannot edit comment created by another user").into()); return Err(anyhow!("Cannot edit comment created by another user").into());
} }
@ -95,17 +95,17 @@ pub(in crate::backend::api) async fn edit_comment(
updated: Some(Utc::now()), updated: Some(Utc::now()),
..Default::default() ..Default::default()
}; };
let comment = DbComment::update(form, params.id, &data)?; let comment = DbComment::update(form, params.id, &context)?;
// federate // federate
if orig_comment.content != comment.comment.content { if orig_comment.content != comment.comment.content {
CreateOrUpdateComment::send(&comment.comment, &data).await?; CreateOrUpdateComment::send(&comment.comment, &context).await?;
} }
if !orig_comment.deleted && comment.comment.deleted { if !orig_comment.deleted && comment.comment.deleted {
DeleteComment::send(&comment.comment, &data).await?; DeleteComment::send(&comment.comment, &context).await?;
} }
if orig_comment.deleted && !comment.comment.deleted { if orig_comment.deleted && !comment.comment.deleted {
UndoDeleteComment::send(&comment.comment, &data).await?; UndoDeleteComment::send(&comment.comment, &context).await?;
} }
Ok(Json(comment)) Ok(Json(comment))

View file

@ -1,5 +1,9 @@
use crate::{ use crate::{
backend::{database::IbisData, federation::activities::follow::Follow, utils::error::MyResult}, backend::{
database::IbisContext,
federation::activities::follow::Follow,
utils::error::MyResult,
},
common::{ common::{
instance::{DbInstance, FollowInstanceParams, GetInstanceParams, InstanceView}, instance::{DbInstance, FollowInstanceParams, GetInstanceParams, InstanceView},
user::LocalUserView, user::LocalUserView,
@ -14,10 +18,10 @@ use axum_macros::debug_handler;
/// Retrieve details about an instance. If no id is provided, return local instance. /// Retrieve details about an instance. If no id is provided, return local instance.
#[debug_handler] #[debug_handler]
pub(in crate::backend::api) async fn get_instance( pub(in crate::backend::api) async fn get_instance(
data: Data<IbisData>, context: Data<IbisContext>,
Form(params): Form<GetInstanceParams>, Form(params): Form<GetInstanceParams>,
) -> MyResult<Json<InstanceView>> { ) -> MyResult<Json<InstanceView>> {
let local_instance = DbInstance::read_view(params.id, &data)?; let local_instance = DbInstance::read_view(params.id, &context)?;
Ok(Json(local_instance)) Ok(Json(local_instance))
} }
@ -26,14 +30,14 @@ pub(in crate::backend::api) async fn get_instance(
#[debug_handler] #[debug_handler]
pub(in crate::backend::api) async fn follow_instance( pub(in crate::backend::api) async fn follow_instance(
Extension(user): Extension<LocalUserView>, Extension(user): Extension<LocalUserView>,
data: Data<IbisData>, context: Data<IbisContext>,
Form(params): Form<FollowInstanceParams>, Form(params): Form<FollowInstanceParams>,
) -> MyResult<Json<SuccessResponse>> { ) -> MyResult<Json<SuccessResponse>> {
let target = DbInstance::read(params.id, &data)?; let target = DbInstance::read(params.id, &context)?;
let pending = !target.local; let pending = !target.local;
DbInstance::follow(&user.person, &target, pending, &data)?; DbInstance::follow(&user.person, &target, pending, &context)?;
let instance = DbInstance::read(params.id, &data)?; let instance = DbInstance::read(params.id, &context)?;
Follow::send(user.person, &instance, &data).await?; Follow::send(user.person, &instance, &context).await?;
Ok(Json(SuccessResponse::default())) Ok(Json(SuccessResponse::default()))
} }
@ -42,16 +46,16 @@ pub(in crate::backend::api) async fn follow_instance(
#[debug_handler] #[debug_handler]
pub(super) async fn resolve_instance( pub(super) async fn resolve_instance(
Query(params): Query<ResolveObjectParams>, Query(params): Query<ResolveObjectParams>,
data: Data<IbisData>, context: Data<IbisContext>,
) -> MyResult<Json<DbInstance>> { ) -> MyResult<Json<DbInstance>> {
let instance: DbInstance = ObjectId::from(params.id).dereference(&data).await?; let instance: DbInstance = ObjectId::from(params.id).dereference(&context).await?;
Ok(Json(instance)) Ok(Json(instance))
} }
#[debug_handler] #[debug_handler]
pub(in crate::backend::api) async fn list_remote_instances( pub(in crate::backend::api) async fn list_remote_instances(
data: Data<IbisData>, context: Data<IbisContext>,
) -> MyResult<Json<Vec<DbInstance>>> { ) -> MyResult<Json<Vec<DbInstance>>> {
let instances = DbInstance::read_remote(&data)?; let instances = DbInstance::read_remote(&context)?;
Ok(Json(instances)) Ok(Json(instances))
} }

View file

@ -16,7 +16,7 @@ use crate::{
instance::{follow_instance, get_instance, resolve_instance}, instance::{follow_instance, get_instance, resolve_instance},
user::{get_user, login_user, logout_user, register_user}, user::{get_user, login_user, logout_user, register_user},
}, },
database::IbisData, database::IbisContext,
utils::error::MyResult, utils::error::MyResult,
}, },
common::{ common::{
@ -83,12 +83,12 @@ fn check_is_admin(user: &LocalUserView) -> MyResult<()> {
#[debug_handler] #[debug_handler]
pub(in crate::backend::api) async fn site_view( pub(in crate::backend::api) async fn site_view(
data: Data<IbisData>, context: Data<IbisContext>,
user: Option<Extension<LocalUserView>>, user: Option<Extension<LocalUserView>>,
) -> MyResult<Json<SiteView>> { ) -> MyResult<Json<SiteView>> {
Ok(Json(SiteView { Ok(Json(SiteView {
my_profile: user.map(|u| u.0), my_profile: user.map(|u| u.0),
config: data.config.options.clone(), config: context.config.options.clone(),
})) }))
} }
@ -97,7 +97,7 @@ pub(in crate::backend::api) async fn site_view(
pub async fn edit_list( pub async fn edit_list(
Query(query): Query<GetEditList>, Query(query): Query<GetEditList>,
user: Option<Extension<LocalUserView>>, user: Option<Extension<LocalUserView>>,
data: Data<IbisData>, context: Data<IbisContext>,
) -> MyResult<Json<Vec<EditView>>> { ) -> MyResult<Json<Vec<EditView>>> {
let params = if let Some(article_id) = query.article_id { let params = if let Some(article_id) = query.article_id {
ViewEditParams::ArticleId(article_id) ViewEditParams::ArticleId(article_id)
@ -106,7 +106,7 @@ pub async fn edit_list(
} else { } else {
return Err(anyhow!("Must provide article_id or person_id").into()); return Err(anyhow!("Must provide article_id or person_id").into());
}; };
Ok(Json(DbEdit::view(params, &user.map(|u| u.0), &data)?)) Ok(Json(DbEdit::view(params, &user.map(|u| u.0), &context)?))
} }
/// Trims the string param, and converts to None if it is empty /// Trims the string param, and converts to None if it is empty

View file

@ -1,7 +1,7 @@
use super::{check_is_admin, empty_to_none}; use super::{check_is_admin, empty_to_none};
use crate::{ use crate::{
backend::{ backend::{
database::{conflict::DbConflict, read_jwt_secret, IbisData}, database::{conflict::DbConflict, read_jwt_secret, IbisContext},
utils::{ utils::{
error::MyResult, error::MyResult,
validate::{validate_display_name, validate_user_name}, validate::{validate_display_name, validate_user_name},
@ -54,8 +54,8 @@ struct Claims {
pub exp: u64, pub exp: u64,
} }
fn generate_login_token(person: &DbPerson, data: &Data<IbisData>) -> MyResult<String> { fn generate_login_token(person: &DbPerson, context: &Data<IbisContext>) -> MyResult<String> {
let hostname = data.domain().to_string(); let hostname = context.domain().to_string();
let claims = Claims { let claims = Claims {
sub: person.username.clone(), sub: person.username.clone(),
iss: hostname, iss: hostname,
@ -63,58 +63,58 @@ fn generate_login_token(person: &DbPerson, data: &Data<IbisData>) -> MyResult<St
exp: get_current_timestamp() + 60 * 60 * 24 * 365, exp: get_current_timestamp() + 60 * 60 * 24 * 365,
}; };
let secret = read_jwt_secret(data)?; let secret = read_jwt_secret(context)?;
let key = EncodingKey::from_secret(secret.as_bytes()); let key = EncodingKey::from_secret(secret.as_bytes());
let jwt = encode(&Header::default(), &claims, &key)?; let jwt = encode(&Header::default(), &claims, &key)?;
Ok(jwt) Ok(jwt)
} }
pub async fn validate(jwt: &str, data: &IbisData) -> MyResult<LocalUserView> { pub async fn validate(jwt: &str, context: &IbisContext) -> MyResult<LocalUserView> {
let validation = Validation::default(); let validation = Validation::default();
let secret = read_jwt_secret(data)?; let secret = read_jwt_secret(context)?;
let key = DecodingKey::from_secret(secret.as_bytes()); let key = DecodingKey::from_secret(secret.as_bytes());
let claims = decode::<Claims>(jwt, &key, &validation)?; let claims = decode::<Claims>(jwt, &key, &validation)?;
DbPerson::read_local_from_name(&claims.claims.sub, data) DbPerson::read_local_from_name(&claims.claims.sub, context)
} }
#[debug_handler] #[debug_handler]
pub(in crate::backend::api) async fn register_user( pub(in crate::backend::api) async fn register_user(
data: Data<IbisData>, context: Data<IbisContext>,
jar: CookieJar, jar: CookieJar,
Form(params): Form<RegisterUserParams>, Form(params): Form<RegisterUserParams>,
) -> MyResult<(CookieJar, Json<LocalUserView>)> { ) -> MyResult<(CookieJar, Json<LocalUserView>)> {
if !data.config.options.registration_open { if !context.config.options.registration_open {
return Err(anyhow!("Registration is closed").into()); return Err(anyhow!("Registration is closed").into());
} }
validate_user_name(&params.username)?; validate_user_name(&params.username)?;
let user = DbPerson::create_local(params.username, params.password, false, &data)?; let user = DbPerson::create_local(params.username, params.password, false, &context)?;
let token = generate_login_token(&user.person, &data)?; let token = generate_login_token(&user.person, &context)?;
let jar = jar.add(create_cookie(token, &data)); let jar = jar.add(create_cookie(token, &context));
Ok((jar, Json(user))) Ok((jar, Json(user)))
} }
#[debug_handler] #[debug_handler]
pub(in crate::backend::api) async fn login_user( pub(in crate::backend::api) async fn login_user(
data: Data<IbisData>, context: Data<IbisContext>,
jar: CookieJar, jar: CookieJar,
Form(params): Form<LoginUserParams>, Form(params): Form<LoginUserParams>,
) -> MyResult<(CookieJar, Json<LocalUserView>)> { ) -> MyResult<(CookieJar, Json<LocalUserView>)> {
let user = DbPerson::read_local_from_name(&params.username, &data)?; let user = DbPerson::read_local_from_name(&params.username, &context)?;
let valid = verify(&params.password, &user.local_user.password_encrypted)?; let valid = verify(&params.password, &user.local_user.password_encrypted)?;
if !valid { if !valid {
return Err(anyhow!("Invalid login").into()); return Err(anyhow!("Invalid login").into());
} }
let token = generate_login_token(&user.person, &data)?; let token = generate_login_token(&user.person, &context)?;
let jar = jar.add(create_cookie(token, &data)); let jar = jar.add(create_cookie(token, &context));
Ok((jar, Json(user))) Ok((jar, Json(user)))
} }
fn create_cookie(jwt: String, data: &Data<IbisData>) -> Cookie<'static> { fn create_cookie(jwt: String, context: &Data<IbisContext>) -> Cookie<'static> {
let mut cookie = Cookie::build((AUTH_COOKIE, jwt)); let mut cookie = Cookie::build((AUTH_COOKIE, jwt));
// Must not set cookie domain on localhost // Must not set cookie domain on localhost
// https://stackoverflow.com/a/1188145 // https://stackoverflow.com/a/1188145
let domain = data.domain().to_string(); let domain = context.domain().to_string();
if !domain.starts_with("localhost") && !domain.starts_with("127.0.0.1") { if !domain.starts_with("localhost") && !domain.starts_with("127.0.0.1") {
cookie = cookie.domain(domain); cookie = cookie.domain(domain);
} }
@ -131,45 +131,45 @@ fn create_cookie(jwt: String, data: &Data<IbisData>) -> Cookie<'static> {
#[debug_handler] #[debug_handler]
pub(in crate::backend::api) async fn logout_user( pub(in crate::backend::api) async fn logout_user(
data: Data<IbisData>, context: Data<IbisContext>,
jar: CookieJar, jar: CookieJar,
) -> MyResult<(CookieJar, Json<SuccessResponse>)> { ) -> MyResult<(CookieJar, Json<SuccessResponse>)> {
let jar = jar.remove(create_cookie(String::new(), &data)); let jar = jar.remove(create_cookie(String::new(), &context));
Ok((jar, Json(SuccessResponse::default()))) Ok((jar, Json(SuccessResponse::default())))
} }
#[debug_handler] #[debug_handler]
pub(in crate::backend::api) async fn get_user( pub(in crate::backend::api) async fn get_user(
params: Query<GetUserParams>, params: Query<GetUserParams>,
data: Data<IbisData>, context: Data<IbisContext>,
) -> MyResult<Json<DbPerson>> { ) -> MyResult<Json<DbPerson>> {
Ok(Json(DbPerson::read_from_name( Ok(Json(DbPerson::read_from_name(
&params.name, &params.name,
&params.domain, &params.domain,
&data, &context,
)?)) )?))
} }
#[debug_handler] #[debug_handler]
pub(in crate::backend::api) async fn update_user_profile( pub(in crate::backend::api) async fn update_user_profile(
data: Data<IbisData>, context: Data<IbisContext>,
Form(mut params): Form<UpdateUserParams>, Form(mut params): Form<UpdateUserParams>,
) -> MyResult<Json<SuccessResponse>> { ) -> MyResult<Json<SuccessResponse>> {
empty_to_none(&mut params.display_name); empty_to_none(&mut params.display_name);
empty_to_none(&mut params.bio); empty_to_none(&mut params.bio);
validate_display_name(&params.display_name)?; validate_display_name(&params.display_name)?;
DbPerson::update_profile(&params, &data)?; DbPerson::update_profile(&params, &context)?;
Ok(Json(SuccessResponse::default())) Ok(Json(SuccessResponse::default()))
} }
#[debug_handler] #[debug_handler]
pub(crate) async fn list_notifications( pub(crate) async fn list_notifications(
Extension(user): Extension<LocalUserView>, Extension(user): Extension<LocalUserView>,
data: Data<IbisData>, context: Data<IbisContext>,
) -> MyResult<Json<Vec<Notification>>> { ) -> MyResult<Json<Vec<Notification>>> {
let conflicts = DbConflict::list(&user.person, &data)?; let conflicts = DbConflict::list(&user.person, &context)?;
let conflicts: Vec<_> = try_join_all(conflicts.into_iter().map(|c| { let conflicts: Vec<_> = try_join_all(conflicts.into_iter().map(|c| {
let data = data.reset_request_count(); let data = context.reset_request_count();
async move { c.to_api_conflict(&data).await } async move { c.to_api_conflict(&data).await }
})) }))
.await?; .await?;
@ -180,7 +180,7 @@ pub(crate) async fn list_notifications(
.collect(); .collect();
if check_is_admin(&user).is_ok() { if check_is_admin(&user).is_ok() {
let articles = DbArticle::list_approval_required(&data)?; let articles = DbArticle::list_approval_required(&context)?;
notifications.extend( notifications.extend(
articles articles
.into_iter() .into_iter()
@ -195,13 +195,13 @@ pub(crate) async fn list_notifications(
#[debug_handler] #[debug_handler]
pub(crate) async fn count_notifications( pub(crate) async fn count_notifications(
Extension(user): Extension<LocalUserView>, Extension(user): Extension<LocalUserView>,
data: Data<IbisData>, context: Data<IbisContext>,
) -> MyResult<Json<usize>> { ) -> MyResult<Json<usize>> {
let mut count = 0; let mut count = 0;
let conflicts = DbConflict::list(&user.person, &data)?; let conflicts = DbConflict::list(&user.person, &context)?;
count += conflicts.len(); count += conflicts.len();
if check_is_admin(&user).is_ok() { if check_is_admin(&user).is_ok() {
let articles = DbArticle::list_approval_required(&data)?; let articles = DbArticle::list_approval_required(&context)?;
count += articles.len(); count += articles.len();
} }

View file

@ -2,7 +2,7 @@ use crate::{
backend::{ backend::{
database::{ database::{
schema::{article, edit, instance}, schema::{article, edit, instance},
IbisData, IbisContext,
}, },
federation::objects::edits_collection::DbEditCollection, federation::objects::edits_collection::DbEditCollection,
utils::error::MyResult, utils::error::MyResult,
@ -46,15 +46,15 @@ impl DbArticle {
Ok(CollectionId::parse(&format!("{}/edits", self.ap_id))?) Ok(CollectionId::parse(&format!("{}/edits", self.ap_id))?)
} }
pub fn create(form: DbArticleForm, data: &IbisData) -> MyResult<Self> { pub fn create(form: DbArticleForm, context: &IbisContext) -> MyResult<Self> {
let mut conn = data.db_pool.get()?; let mut conn = context.db_pool.get()?;
Ok(insert_into(article::table) Ok(insert_into(article::table)
.values(form) .values(form)
.get_result(conn.deref_mut())?) .get_result(conn.deref_mut())?)
} }
pub fn create_or_update(form: DbArticleForm, data: &IbisData) -> MyResult<Self> { pub fn create_or_update(form: DbArticleForm, context: &IbisContext) -> MyResult<Self> {
let mut conn = data.db_pool.get()?; let mut conn = context.db_pool.get()?;
Ok(insert_into(article::table) Ok(insert_into(article::table)
.values(&form) .values(&form)
.on_conflict(article::dsl::ap_id) .on_conflict(article::dsl::ap_id)
@ -63,48 +63,48 @@ impl DbArticle {
.get_result(conn.deref_mut())?) .get_result(conn.deref_mut())?)
} }
pub fn update_text(id: ArticleId, text: &str, data: &IbisData) -> MyResult<Self> { pub fn update_text(id: ArticleId, text: &str, context: &IbisContext) -> MyResult<Self> {
let mut conn = data.db_pool.get()?; let mut conn = context.db_pool.get()?;
Ok(diesel::update(article::dsl::article.find(id)) Ok(diesel::update(article::dsl::article.find(id))
.set(article::dsl::text.eq(text)) .set(article::dsl::text.eq(text))
.get_result::<Self>(conn.deref_mut())?) .get_result::<Self>(conn.deref_mut())?)
} }
pub fn update_protected(id: ArticleId, locked: bool, data: &IbisData) -> MyResult<Self> { pub fn update_protected(id: ArticleId, locked: bool, context: &IbisContext) -> MyResult<Self> {
let mut conn = data.db_pool.get()?; let mut conn = context.db_pool.get()?;
Ok(diesel::update(article::dsl::article.find(id)) Ok(diesel::update(article::dsl::article.find(id))
.set(article::dsl::protected.eq(locked)) .set(article::dsl::protected.eq(locked))
.get_result::<Self>(conn.deref_mut())?) .get_result::<Self>(conn.deref_mut())?)
} }
pub fn update_approved(id: ArticleId, approved: bool, data: &IbisData) -> MyResult<Self> { pub fn update_approved(id: ArticleId, approved: bool, context: &IbisContext) -> MyResult<Self> {
let mut conn = data.db_pool.get()?; let mut conn = context.db_pool.get()?;
Ok(diesel::update(article::dsl::article.find(id)) Ok(diesel::update(article::dsl::article.find(id))
.set(article::dsl::approved.eq(approved)) .set(article::dsl::approved.eq(approved))
.get_result::<Self>(conn.deref_mut())?) .get_result::<Self>(conn.deref_mut())?)
} }
pub fn delete(id: ArticleId, data: &IbisData) -> MyResult<Self> { pub fn delete(id: ArticleId, context: &IbisContext) -> MyResult<Self> {
let mut conn = data.db_pool.get()?; let mut conn = context.db_pool.get()?;
Ok(diesel::delete(article::dsl::article.find(id)).get_result::<Self>(conn.deref_mut())?) Ok(diesel::delete(article::dsl::article.find(id)).get_result::<Self>(conn.deref_mut())?)
} }
pub fn read(id: ArticleId, data: &IbisData) -> MyResult<Self> { pub fn read(id: ArticleId, context: &IbisContext) -> MyResult<Self> {
let mut conn = data.db_pool.get()?; let mut conn = context.db_pool.get()?;
Ok(article::table Ok(article::table
.find(id) .find(id)
.get_result::<Self>(conn.deref_mut())?) .get_result::<Self>(conn.deref_mut())?)
} }
pub fn read_view(id: ArticleId, data: &IbisData) -> MyResult<DbArticleView> { pub fn read_view(id: ArticleId, context: &IbisContext) -> MyResult<DbArticleView> {
let mut conn = data.db_pool.get()?; let mut conn = context.db_pool.get()?;
let query = article::table let query = article::table
.find(id) .find(id)
.inner_join(instance::table) .inner_join(instance::table)
.into_boxed(); .into_boxed();
let (article, instance): (DbArticle, DbInstance) = query.get_result(conn.deref_mut())?; let (article, instance): (DbArticle, DbInstance) = query.get_result(conn.deref_mut())?;
let comments = DbComment::read_for_article(article.id, data)?; let comments = DbComment::read_for_article(article.id, context)?;
let latest_version = article.latest_edit_version(data)?; let latest_version = article.latest_edit_version(context)?;
Ok(DbArticleView { Ok(DbArticleView {
article, article,
instance, instance,
@ -116,9 +116,9 @@ impl DbArticle {
pub fn read_view_title( pub fn read_view_title(
title: &str, title: &str,
domain: Option<String>, domain: Option<String>,
data: &IbisData, context: &IbisContext,
) -> MyResult<DbArticleView> { ) -> MyResult<DbArticleView> {
let mut conn = data.db_pool.get()?; let mut conn = context.db_pool.get()?;
let (article, instance): (DbArticle, DbInstance) = { let (article, instance): (DbArticle, DbInstance) = {
let query = article::table let query = article::table
.inner_join(instance::table) .inner_join(instance::table)
@ -131,8 +131,8 @@ impl DbArticle {
}; };
query.get_result(conn.deref_mut())? query.get_result(conn.deref_mut())?
}; };
let comments = DbComment::read_for_article(article.id, data)?; let comments = DbComment::read_for_article(article.id, context)?;
let latest_version = article.latest_edit_version(data)?; let latest_version = article.latest_edit_version(context)?;
Ok(DbArticleView { Ok(DbArticleView {
article, article,
instance, instance,
@ -141,8 +141,8 @@ impl DbArticle {
}) })
} }
pub fn read_from_ap_id(ap_id: &ObjectId<DbArticle>, data: &IbisData) -> MyResult<Self> { pub fn read_from_ap_id(ap_id: &ObjectId<DbArticle>, context: &IbisContext) -> MyResult<Self> {
let mut conn = data.db_pool.get()?; let mut conn = context.db_pool.get()?;
Ok(article::table Ok(article::table
.filter(article::dsl::ap_id.eq(ap_id)) .filter(article::dsl::ap_id.eq(ap_id))
.get_result(conn.deref_mut())?) .get_result(conn.deref_mut())?)
@ -154,9 +154,9 @@ impl DbArticle {
pub fn read_all( pub fn read_all(
only_local: Option<bool>, only_local: Option<bool>,
instance_id: Option<InstanceId>, instance_id: Option<InstanceId>,
data: &IbisData, context: &IbisContext,
) -> MyResult<Vec<Self>> { ) -> MyResult<Vec<Self>> {
let mut conn = data.db_pool.get()?; let mut conn = context.db_pool.get()?;
let mut query = article::table let mut query = article::table
.inner_join(edit::table) .inner_join(edit::table)
.inner_join(instance::table) .inner_join(instance::table)
@ -175,8 +175,8 @@ impl DbArticle {
Ok(query.get_results(&mut conn)?) Ok(query.get_results(&mut conn)?)
} }
pub fn search(query: &str, data: &IbisData) -> MyResult<Vec<Self>> { pub fn search(query: &str, context: &IbisContext) -> MyResult<Vec<Self>> {
let mut conn = data.db_pool.get()?; let mut conn = context.db_pool.get()?;
let replaced = query let replaced = query
.replace('%', "\\%") .replace('%', "\\%")
.replace('_', "\\_") .replace('_', "\\_")
@ -191,8 +191,8 @@ impl DbArticle {
.get_results(conn.deref_mut())?) .get_results(conn.deref_mut())?)
} }
pub fn latest_edit_version(&self, data: &IbisData) -> MyResult<EditVersion> { pub fn latest_edit_version(&self, context: &IbisContext) -> MyResult<EditVersion> {
let mut conn = data.db_pool.get()?; let mut conn = context.db_pool.get()?;
let latest_version: Option<EditVersion> = edit::table let latest_version: Option<EditVersion> = edit::table
.filter(edit::dsl::article_id.eq(self.id)) .filter(edit::dsl::article_id.eq(self.id))
.order_by(edit::dsl::id.desc()) .order_by(edit::dsl::id.desc())
@ -206,8 +206,8 @@ impl DbArticle {
} }
} }
pub fn list_approval_required(data: &IbisData) -> MyResult<Vec<Self>> { pub fn list_approval_required(context: &IbisContext) -> MyResult<Vec<Self>> {
let mut conn = data.db_pool.get()?; let mut conn = context.db_pool.get()?;
let query = article::table let query = article::table
.group_by(article::dsl::id) .group_by(article::dsl::id)
.filter(article::dsl::approved.eq(false)) .filter(article::dsl::approved.eq(false))

View file

@ -1,6 +1,6 @@
use super::{ use super::{
schema::{comment, person}, schema::{comment, person},
IbisData, IbisContext,
}; };
use crate::{ use crate::{
backend::utils::error::MyResult, backend::utils::error::MyResult,
@ -48,8 +48,8 @@ pub struct DbCommentUpdateForm {
} }
impl DbComment { impl DbComment {
pub fn create(form: DbCommentInsertForm, data: &IbisData) -> MyResult<Self> { pub fn create(form: DbCommentInsertForm, context: &IbisContext) -> MyResult<Self> {
let mut conn = data.db_pool.get()?; let mut conn = context.db_pool.get()?;
Ok(insert_into(comment::table) Ok(insert_into(comment::table)
.values(form) .values(form)
.get_result(conn.deref_mut())?) .get_result(conn.deref_mut())?)
@ -58,18 +58,18 @@ impl DbComment {
pub fn update( pub fn update(
form: DbCommentUpdateForm, form: DbCommentUpdateForm,
id: CommentId, id: CommentId,
data: &IbisData, context: &IbisContext,
) -> MyResult<DbCommentView> { ) -> MyResult<DbCommentView> {
let mut conn = data.db_pool.get()?; let mut conn = context.db_pool.get()?;
let comment: DbComment = update(comment::table.find(id)) let comment: DbComment = update(comment::table.find(id))
.set(form) .set(form)
.get_result(conn.deref_mut())?; .get_result(conn.deref_mut())?;
let creator = DbPerson::read(comment.creator_id, data)?; let creator = DbPerson::read(comment.creator_id, context)?;
Ok(DbCommentView { comment, creator }) Ok(DbCommentView { comment, creator })
} }
pub fn create_or_update(form: DbCommentInsertForm, data: &IbisData) -> MyResult<Self> { pub fn create_or_update(form: DbCommentInsertForm, context: &IbisContext) -> MyResult<Self> {
let mut conn = data.db_pool.get()?; let mut conn = context.db_pool.get()?;
Ok(insert_into(comment::table) Ok(insert_into(comment::table)
.values(&form) .values(&form)
.on_conflict(comment::dsl::ap_id) .on_conflict(comment::dsl::ap_id)
@ -78,24 +78,24 @@ impl DbComment {
.get_result(conn.deref_mut())?) .get_result(conn.deref_mut())?)
} }
pub fn read(id: CommentId, data: &IbisData) -> MyResult<Self> { pub fn read(id: CommentId, context: &IbisContext) -> MyResult<Self> {
let mut conn = data.db_pool.get()?; let mut conn = context.db_pool.get()?;
Ok(comment::table Ok(comment::table
.find(id) .find(id)
.get_result::<Self>(conn.deref_mut())?) .get_result::<Self>(conn.deref_mut())?)
} }
pub fn read_view(id: CommentId, data: &IbisData) -> MyResult<DbCommentView> { pub fn read_view(id: CommentId, context: &IbisContext) -> MyResult<DbCommentView> {
let mut conn = data.db_pool.get()?; let mut conn = context.db_pool.get()?;
let comment = comment::table let comment = comment::table
.find(id) .find(id)
.get_result::<Self>(conn.deref_mut())?; .get_result::<Self>(conn.deref_mut())?;
let creator = DbPerson::read(comment.creator_id, data)?; let creator = DbPerson::read(comment.creator_id, context)?;
Ok(DbCommentView { comment, creator }) Ok(DbCommentView { comment, creator })
} }
pub fn read_from_ap_id(ap_id: &ObjectId<DbComment>, data: &IbisData) -> MyResult<Self> { pub fn read_from_ap_id(ap_id: &ObjectId<DbComment>, context: &IbisContext) -> MyResult<Self> {
let mut conn = data.db_pool.get()?; let mut conn = context.db_pool.get()?;
Ok(comment::table Ok(comment::table
.filter(comment::dsl::ap_id.eq(ap_id)) .filter(comment::dsl::ap_id.eq(ap_id))
.get_result(conn.deref_mut())?) .get_result(conn.deref_mut())?)
@ -103,9 +103,9 @@ impl DbComment {
pub fn read_for_article( pub fn read_for_article(
article_id: ArticleId, article_id: ArticleId,
data: &IbisData, context: &IbisContext,
) -> MyResult<Vec<DbCommentView>> { ) -> MyResult<Vec<DbCommentView>> {
let mut conn = data.db_pool.get()?; let mut conn = context.db_pool.get()?;
let comments = comment::table let comments = comment::table
.inner_join(person::table) .inner_join(person::table)
.filter(comment::article_id.eq(article_id)) .filter(comment::article_id.eq(article_id))

View file

@ -2,7 +2,7 @@ use crate::{
backend::{ backend::{
database::{ database::{
schema::{conflict, edit}, schema::{conflict, edit},
IbisData, IbisContext,
}, },
federation::activities::submit_article_update, federation::activities::submit_article_update,
utils::{error::MyResult, generate_article_version}, utils::{error::MyResult, generate_article_version},
@ -57,23 +57,23 @@ pub struct DbConflictForm {
} }
impl DbConflict { impl DbConflict {
pub fn create(form: &DbConflictForm, data: &IbisData) -> MyResult<Self> { pub fn create(form: &DbConflictForm, context: &IbisContext) -> MyResult<Self> {
let mut conn = data.db_pool.get()?; let mut conn = context.db_pool.get()?;
Ok(insert_into(conflict::table) Ok(insert_into(conflict::table)
.values(form) .values(form)
.get_result(conn.deref_mut())?) .get_result(conn.deref_mut())?)
} }
pub fn list(person: &DbPerson, data: &IbisData) -> MyResult<Vec<Self>> { pub fn list(person: &DbPerson, context: &IbisContext) -> MyResult<Vec<Self>> {
let mut conn = data.db_pool.get()?; let mut conn = context.db_pool.get()?;
Ok(conflict::table Ok(conflict::table
.filter(conflict::dsl::creator_id.eq(person.id)) .filter(conflict::dsl::creator_id.eq(person.id))
.get_results(conn.deref_mut())?) .get_results(conn.deref_mut())?)
} }
/// Delete merge conflict which was created by specific user /// Delete merge conflict which was created by specific user
pub fn delete(id: ConflictId, creator_id: PersonId, data: &IbisData) -> MyResult<()> { pub fn delete(id: ConflictId, creator_id: PersonId, context: &IbisContext) -> MyResult<()> {
let mut conn = data.db_pool.get()?; let mut conn = context.db_pool.get()?;
let conflict: Self = delete( let conflict: Self = delete(
conflict::table conflict::table
.filter(conflict::dsl::creator_id.eq(creator_id)) .filter(conflict::dsl::creator_id.eq(creator_id))
@ -89,13 +89,16 @@ impl DbConflict {
Ok(()) Ok(())
} }
pub async fn to_api_conflict(&self, data: &Data<IbisData>) -> MyResult<Option<ApiConflict>> { pub async fn to_api_conflict(
let article = DbArticle::read_view(self.article_id, data)?; &self,
context: &Data<IbisContext>,
) -> MyResult<Option<ApiConflict>> {
let article = DbArticle::read_view(self.article_id, context)?;
// Make sure to get latest version from origin so that all conflicts can be resolved // Make sure to get latest version from origin so that all conflicts can be resolved
let original_article = article.article.ap_id.dereference_forced(data).await?; let original_article = article.article.ap_id.dereference_forced(context).await?;
// create common ancestor version // create common ancestor version
let edits = DbEdit::list_for_article(original_article.id, data)?; let edits = DbEdit::list_for_article(original_article.id, context)?;
let ancestor = generate_article_version(&edits, &self.previous_version_id)?; let ancestor = generate_article_version(&edits, &self.previous_version_id)?;
let patch = Patch::from_str(&self.diff)?; let patch = Patch::from_str(&self.diff)?;
@ -111,10 +114,10 @@ impl DbConflict {
self.previous_version_id.clone(), self.previous_version_id.clone(),
&original_article, &original_article,
self.creator_id, self.creator_id,
data, context,
) )
.await?; .await?;
DbConflict::delete(self.id, self.creator_id, data)?; DbConflict::delete(self.id, self.creator_id, context)?;
Ok(None) Ok(None)
} }
Err(three_way_merge) => { Err(three_way_merge) => {
@ -125,7 +128,7 @@ impl DbConflict {
three_way_merge, three_way_merge,
summary: self.summary.clone(), summary: self.summary.clone(),
article: original_article.clone(), article: original_article.clone(),
previous_version_id: original_article.latest_edit_version(data)?, previous_version_id: original_article.latest_edit_version(context)?,
published: self.published, published: self.published,
})) }))
} }

View file

@ -2,7 +2,7 @@ use crate::{
backend::{ backend::{
database::schema::{article, edit, person}, database::schema::{article, edit, person},
utils::error::MyResult, utils::error::MyResult,
IbisData, IbisContext,
}, },
common::{ common::{
article::{DbArticle, DbEdit, EditVersion, EditView}, article::{DbArticle, DbEdit, EditVersion, EditView},
@ -77,8 +77,8 @@ impl DbEditForm {
} }
impl DbEdit { impl DbEdit {
pub fn create(form: &DbEditForm, data: &IbisData) -> MyResult<Self> { pub fn create(form: &DbEditForm, context: &IbisContext) -> MyResult<Self> {
let mut conn = data.db_pool.get()?; let mut conn = context.db_pool.get()?;
Ok(insert_into(edit::table) Ok(insert_into(edit::table)
.values(form) .values(form)
.on_conflict(edit::dsl::ap_id) .on_conflict(edit::dsl::ap_id)
@ -87,22 +87,22 @@ impl DbEdit {
.get_result(conn.deref_mut())?) .get_result(conn.deref_mut())?)
} }
pub fn read(version: &EditVersion, data: &IbisData) -> MyResult<Self> { pub fn read(version: &EditVersion, context: &IbisContext) -> MyResult<Self> {
let mut conn = data.db_pool.get()?; let mut conn = context.db_pool.get()?;
Ok(edit::table Ok(edit::table
.filter(edit::dsl::hash.eq(version)) .filter(edit::dsl::hash.eq(version))
.get_result(conn.deref_mut())?) .get_result(conn.deref_mut())?)
} }
pub fn read_from_ap_id(ap_id: &ObjectId<DbEdit>, data: &IbisData) -> MyResult<Self> { pub fn read_from_ap_id(ap_id: &ObjectId<DbEdit>, context: &IbisContext) -> MyResult<Self> {
let mut conn = data.db_pool.get()?; let mut conn = context.db_pool.get()?;
Ok(edit::table Ok(edit::table
.filter(edit::dsl::ap_id.eq(ap_id)) .filter(edit::dsl::ap_id.eq(ap_id))
.get_result(conn.deref_mut())?) .get_result(conn.deref_mut())?)
} }
pub fn list_for_article(id: ArticleId, data: &IbisData) -> MyResult<Vec<Self>> { pub fn list_for_article(id: ArticleId, context: &IbisContext) -> MyResult<Vec<Self>> {
let mut conn = data.db_pool.get()?; let mut conn = context.db_pool.get()?;
Ok(edit::table Ok(edit::table
.filter(edit::article_id.eq(id)) .filter(edit::article_id.eq(id))
.order(edit::published) .order(edit::published)
@ -112,9 +112,9 @@ impl DbEdit {
pub fn view( pub fn view(
params: ViewEditParams, params: ViewEditParams,
user: &Option<LocalUserView>, user: &Option<LocalUserView>,
data: &IbisData, context: &IbisContext,
) -> MyResult<Vec<EditView>> { ) -> MyResult<Vec<EditView>> {
let mut conn = data.db_pool.get()?; let mut conn = context.db_pool.get()?;
let person_id = user.as_ref().map(|u| u.person.id).unwrap_or(PersonId(-1)); let person_id = user.as_ref().map(|u| u.person.id).unwrap_or(PersonId(-1));
let query = edit::table let query = edit::table
.inner_join(article::table) .inner_join(article::table)

View file

@ -2,7 +2,7 @@ use crate::{
backend::{ backend::{
database::{ database::{
schema::{article, comment, instance, instance_follow}, schema::{article, comment, instance, instance_follow},
IbisData, IbisContext,
}, },
federation::objects::{ federation::objects::{
articles_collection::DbArticleCollection, articles_collection::DbArticleCollection,
@ -48,8 +48,8 @@ pub struct DbInstanceForm {
} }
impl DbInstance { impl DbInstance {
pub fn create(form: &DbInstanceForm, data: &IbisData) -> MyResult<Self> { pub fn create(form: &DbInstanceForm, context: &IbisContext) -> MyResult<Self> {
let mut conn = data.db_pool.get()?; let mut conn = context.db_pool.get()?;
Ok(insert_into(instance::table) Ok(insert_into(instance::table)
.values(form) .values(form)
.on_conflict(instance::ap_id) .on_conflict(instance::ap_id)
@ -58,34 +58,37 @@ impl DbInstance {
.get_result(conn.deref_mut())?) .get_result(conn.deref_mut())?)
} }
pub fn read(id: InstanceId, data: &IbisData) -> MyResult<Self> { pub fn read(id: InstanceId, context: &IbisContext) -> MyResult<Self> {
let mut conn = data.db_pool.get()?; let mut conn = context.db_pool.get()?;
Ok(instance::table.find(id).get_result(conn.deref_mut())?) Ok(instance::table.find(id).get_result(conn.deref_mut())?)
} }
pub fn read_from_ap_id( pub fn read_from_ap_id(
ap_id: &ObjectId<DbInstance>, ap_id: &ObjectId<DbInstance>,
data: &Data<IbisData>, context: &Data<IbisContext>,
) -> MyResult<DbInstance> { ) -> MyResult<DbInstance> {
let mut conn = data.db_pool.get()?; let mut conn = context.db_pool.get()?;
Ok(instance::table Ok(instance::table
.filter(instance::ap_id.eq(ap_id)) .filter(instance::ap_id.eq(ap_id))
.get_result(conn.deref_mut())?) .get_result(conn.deref_mut())?)
} }
pub fn read_local(data: &IbisData) -> MyResult<Self> { pub fn read_local(context: &IbisContext) -> MyResult<Self> {
let mut conn = data.db_pool.get()?; let mut conn = context.db_pool.get()?;
Ok(instance::table Ok(instance::table
.filter(instance::local.eq(true)) .filter(instance::local.eq(true))
.get_result(conn.deref_mut())?) .get_result(conn.deref_mut())?)
} }
pub fn read_view(id: Option<InstanceId>, data: &Data<IbisData>) -> MyResult<InstanceView> { pub fn read_view(
id: Option<InstanceId>,
context: &Data<IbisContext>,
) -> MyResult<InstanceView> {
let instance = match id { let instance = match id {
Some(id) => DbInstance::read(id, data), Some(id) => DbInstance::read(id, context),
None => DbInstance::read_local(data), None => DbInstance::read_local(context),
}?; }?;
let followers = DbInstance::read_followers(instance.id, data)?; let followers = DbInstance::read_followers(instance.id, context)?;
Ok(InstanceView { Ok(InstanceView {
instance, instance,
@ -97,10 +100,10 @@ impl DbInstance {
follower: &DbPerson, follower: &DbPerson,
instance: &DbInstance, instance: &DbInstance,
pending_: bool, pending_: bool,
data: &Data<IbisData>, context: &Data<IbisContext>,
) -> MyResult<()> { ) -> MyResult<()> {
use instance_follow::dsl::{follower_id, instance_id, pending}; use instance_follow::dsl::{follower_id, instance_id, pending};
let mut conn = data.db_pool.get()?; let mut conn = context.db_pool.get()?;
let form = ( let form = (
instance_id.eq(instance.id), instance_id.eq(instance.id),
follower_id.eq(follower.id), follower_id.eq(follower.id),
@ -116,10 +119,10 @@ impl DbInstance {
Ok(()) Ok(())
} }
pub fn read_followers(id_: InstanceId, data: &IbisData) -> MyResult<Vec<DbPerson>> { pub fn read_followers(id_: InstanceId, context: &IbisContext) -> MyResult<Vec<DbPerson>> {
use crate::backend::database::schema::person; use crate::backend::database::schema::person;
use instance_follow::dsl::{follower_id, instance_id}; use instance_follow::dsl::{follower_id, instance_id};
let mut conn = data.db_pool.get()?; let mut conn = context.db_pool.get()?;
Ok(instance_follow::table Ok(instance_follow::table
.inner_join(person::table.on(follower_id.eq(person::id))) .inner_join(person::table.on(follower_id.eq(person::id)))
.filter(instance_id.eq(id_)) .filter(instance_id.eq(id_))
@ -127,8 +130,8 @@ impl DbInstance {
.get_results(conn.deref_mut())?) .get_results(conn.deref_mut())?)
} }
pub fn read_remote(data: &Data<IbisData>) -> MyResult<Vec<DbInstance>> { pub fn read_remote(context: &Data<IbisContext>) -> MyResult<Vec<DbInstance>> {
let mut conn = data.db_pool.get()?; let mut conn = context.db_pool.get()?;
Ok(instance::table Ok(instance::table
.filter(instance::local.eq(false)) .filter(instance::local.eq(false))
.get_results(conn.deref_mut())?) .get_results(conn.deref_mut())?)
@ -136,8 +139,11 @@ impl DbInstance {
/// Read the instance where an article is hosted, based on a comment id. /// Read the instance where an article is hosted, based on a comment id.
/// Note this may be different from the instance where the comment is hosted. /// Note this may be different from the instance where the comment is hosted.
pub fn read_for_comment(comment_id: CommentId, data: &Data<IbisData>) -> MyResult<DbInstance> { pub fn read_for_comment(
let mut conn = data.db_pool.get()?; comment_id: CommentId,
context: &Data<IbisContext>,
) -> MyResult<DbInstance> {
let mut conn = context.db_pool.get()?;
Ok(instance::table Ok(instance::table
.inner_join(article::table) .inner_join(article::table)
.inner_join(comment::table.on(comment::article_id.eq(article::id))) .inner_join(comment::table.on(comment::article_id.eq(article::id)))

View file

@ -1,5 +1,5 @@
use super::schema::instance_stats; use super::schema::instance_stats;
use crate::backend::{IbisData, MyResult}; use crate::backend::{IbisContext, MyResult};
use diesel::{query_dsl::methods::FindDsl, Queryable, RunQueryDsl, Selectable}; use diesel::{query_dsl::methods::FindDsl, Queryable, RunQueryDsl, Selectable};
use std::ops::DerefMut; use std::ops::DerefMut;
@ -15,8 +15,8 @@ pub struct InstanceStats {
} }
impl InstanceStats { impl InstanceStats {
pub fn read(data: &IbisData) -> MyResult<Self> { pub fn read(context: &IbisContext) -> MyResult<Self> {
let mut conn = data.db_pool.get()?; let mut conn = context.db_pool.get()?;
Ok(instance_stats::table.find(1).get_result(conn.deref_mut())?) Ok(instance_stats::table.find(1).get_result(conn.deref_mut())?)
} }
} }

View file

@ -19,13 +19,13 @@ pub mod user;
pub type DbPool = Pool<ConnectionManager<PgConnection>>; pub type DbPool = Pool<ConnectionManager<PgConnection>>;
#[derive(Clone)] #[derive(Clone)]
pub struct IbisData { pub struct IbisContext {
pub db_pool: DbPool, pub db_pool: DbPool,
pub config: IbisConfig, pub config: IbisConfig,
} }
pub fn read_jwt_secret(data: &IbisData) -> MyResult<String> { pub fn read_jwt_secret(context: &IbisContext) -> MyResult<String> {
let mut conn = data.db_pool.get()?; let mut conn = context.db_pool.get()?;
Ok(jwt_secret::table Ok(jwt_secret::table
.select(jwt_secret::dsl::secret) .select(jwt_secret::dsl::secret)
.first(conn.deref_mut())?) .first(conn.deref_mut())?)

View file

@ -2,7 +2,7 @@ use crate::{
backend::{ backend::{
database::{ database::{
schema::{instance, instance_follow, local_user, person}, schema::{instance, instance_follow, local_user, person},
IbisData, IbisContext,
}, },
utils::{error::MyResult, generate_keypair}, utils::{error::MyResult, generate_keypair},
}, },
@ -51,8 +51,8 @@ pub struct DbPersonForm {
} }
impl DbPerson { impl DbPerson {
pub fn create(person_form: &DbPersonForm, data: &Data<IbisData>) -> MyResult<Self> { pub fn create(person_form: &DbPersonForm, context: &Data<IbisContext>) -> MyResult<Self> {
let mut conn = data.db_pool.get()?; let mut conn = context.db_pool.get()?;
Ok(insert_into(person::table) Ok(insert_into(person::table)
.values(person_form) .values(person_form)
.on_conflict(person::dsl::ap_id) .on_conflict(person::dsl::ap_id)
@ -61,8 +61,8 @@ impl DbPerson {
.get_result::<DbPerson>(conn.deref_mut())?) .get_result::<DbPerson>(conn.deref_mut())?)
} }
pub fn read(id: PersonId, data: &IbisData) -> MyResult<DbPerson> { pub fn read(id: PersonId, context: &IbisContext) -> MyResult<DbPerson> {
let mut conn = data.db_pool.get()?; let mut conn = context.db_pool.get()?;
Ok(person::table.find(id).get_result(conn.deref_mut())?) Ok(person::table.find(id).get_result(conn.deref_mut())?)
} }
@ -70,10 +70,10 @@ impl DbPerson {
username: String, username: String,
password: String, password: String,
admin: bool, admin: bool,
data: &IbisData, context: &IbisContext,
) -> MyResult<LocalUserView> { ) -> MyResult<LocalUserView> {
let mut conn = data.db_pool.get()?; let mut conn = context.db_pool.get()?;
let domain = &data.config.federation.domain; let domain = &context.config.federation.domain;
let ap_id = ObjectId::parse(&format!( let ap_id = ObjectId::parse(&format!(
"{}://{domain}/user/{username}", "{}://{domain}/user/{username}",
http_protocol_str() http_protocol_str()
@ -115,9 +115,9 @@ impl DbPerson {
pub fn read_from_ap_id( pub fn read_from_ap_id(
ap_id: &ObjectId<DbPerson>, ap_id: &ObjectId<DbPerson>,
data: &Data<IbisData>, context: &Data<IbisContext>,
) -> MyResult<DbPerson> { ) -> MyResult<DbPerson> {
let mut conn = data.db_pool.get()?; let mut conn = context.db_pool.get()?;
Ok(person::table Ok(person::table
.filter(person::dsl::ap_id.eq(ap_id)) .filter(person::dsl::ap_id.eq(ap_id))
.get_result(conn.deref_mut())?) .get_result(conn.deref_mut())?)
@ -126,9 +126,9 @@ impl DbPerson {
pub fn read_from_name( pub fn read_from_name(
username: &str, username: &str,
domain: &Option<String>, domain: &Option<String>,
data: &Data<IbisData>, context: &Data<IbisContext>,
) -> MyResult<DbPerson> { ) -> MyResult<DbPerson> {
let mut conn = data.db_pool.get()?; let mut conn = context.db_pool.get()?;
let mut query = person::table let mut query = person::table
.filter(person::username.eq(username)) .filter(person::username.eq(username))
.select(person::all_columns) .select(person::all_columns)
@ -144,8 +144,8 @@ impl DbPerson {
Ok(query.get_result(conn.deref_mut())?) Ok(query.get_result(conn.deref_mut())?)
} }
pub fn update_profile(params: &UpdateUserParams, data: &Data<IbisData>) -> MyResult<()> { pub fn update_profile(params: &UpdateUserParams, context: &Data<IbisContext>) -> MyResult<()> {
let mut conn = data.db_pool.get()?; let mut conn = context.db_pool.get()?;
diesel::update(person::table.find(params.person_id)) diesel::update(person::table.find(params.person_id))
.set(( .set((
person::dsl::display_name.eq(&params.display_name), person::dsl::display_name.eq(&params.display_name),
@ -155,15 +155,15 @@ impl DbPerson {
Ok(()) Ok(())
} }
pub fn read_local_from_name(username: &str, data: &IbisData) -> MyResult<LocalUserView> { pub fn read_local_from_name(username: &str, context: &IbisContext) -> MyResult<LocalUserView> {
let mut conn = data.db_pool.get()?; let mut conn = context.db_pool.get()?;
let (person, local_user) = person::table let (person, local_user) = person::table
.inner_join(local_user::table) .inner_join(local_user::table)
.filter(person::dsl::local) .filter(person::dsl::local)
.filter(person::dsl::username.eq(username)) .filter(person::dsl::username.eq(username))
.get_result::<(DbPerson, DbLocalUser)>(conn.deref_mut())?; .get_result::<(DbPerson, DbLocalUser)>(conn.deref_mut())?;
// TODO: handle this in single query // TODO: handle this in single query
let following = Self::read_following(person.id, data)?; let following = Self::read_following(person.id, context)?;
Ok(LocalUserView { Ok(LocalUserView {
person, person,
local_user, local_user,
@ -171,9 +171,9 @@ impl DbPerson {
}) })
} }
fn read_following(id_: PersonId, data: &IbisData) -> MyResult<Vec<DbInstance>> { fn read_following(id_: PersonId, context: &IbisContext) -> MyResult<Vec<DbInstance>> {
use instance_follow::dsl::{follower_id, instance_id}; use instance_follow::dsl::{follower_id, instance_id};
let mut conn = data.db_pool.get()?; let mut conn = context.db_pool.get()?;
Ok(instance_follow::table Ok(instance_follow::table
.inner_join(instance::table.on(instance_id.eq(instance::dsl::id))) .inner_join(instance::table.on(instance_id.eq(instance::dsl::id)))
.filter(follower_id.eq(id_)) .filter(follower_id.eq(id_))
@ -182,13 +182,13 @@ impl DbPerson {
} }
/// Ghost user serves as placeholder for deleted accounts /// Ghost user serves as placeholder for deleted accounts
pub fn ghost(data: &Data<IbisData>) -> MyResult<DbPerson> { pub fn ghost(context: &Data<IbisContext>) -> MyResult<DbPerson> {
let username = "ghost"; let username = "ghost";
let read = DbPerson::read_from_name(username, &None, data); let read = DbPerson::read_from_name(username, &None, context);
if read.is_ok() { if read.is_ok() {
read read
} else { } else {
let domain = &data.config.federation.domain; let domain = &context.config.federation.domain;
let ap_id = ObjectId::parse(&format!( let ap_id = ObjectId::parse(&format!(
"{}://{domain}/user/{username}", "{}://{domain}/user/{username}",
http_protocol_str() http_protocol_str()
@ -206,7 +206,7 @@ impl DbPerson {
display_name: None, display_name: None,
bio: None, bio: None,
}; };
DbPerson::create(&person_form, data) DbPerson::create(&person_form, context)
} }
} }
} }

View file

@ -1,6 +1,6 @@
use crate::{ use crate::{
backend::{ backend::{
database::IbisData, database::IbisContext,
federation::{activities::follow::Follow, send_activity}, federation::{activities::follow::Follow, send_activity},
utils::{ utils::{
error::{Error, MyResult}, error::{Error, MyResult},
@ -32,10 +32,10 @@ impl Accept {
pub async fn send( pub async fn send(
local_instance: DbInstance, local_instance: DbInstance,
object: Follow, object: Follow,
data: &Data<IbisData>, context: &Data<IbisContext>,
) -> MyResult<()> { ) -> MyResult<()> {
let id = generate_activity_id(data)?; let id = generate_activity_id(context)?;
let follower = object.actor.dereference(data).await?; let follower = object.actor.dereference(context).await?;
let accept = Accept { let accept = Accept {
actor: local_instance.ap_id.clone(), actor: local_instance.ap_id.clone(),
object, object,
@ -46,7 +46,7 @@ impl Accept {
&local_instance, &local_instance,
accept, accept,
vec![follower.shared_inbox_or_inbox()], vec![follower.shared_inbox_or_inbox()],
data, context,
) )
.await?; .await?;
Ok(()) Ok(())
@ -55,7 +55,7 @@ impl Accept {
#[async_trait::async_trait] #[async_trait::async_trait]
impl ActivityHandler for Accept { impl ActivityHandler for Accept {
type DataType = IbisData; type DataType = IbisContext;
type Error = Error; type Error = Error;
fn id(&self) -> &Url { fn id(&self) -> &Url {
@ -66,15 +66,15 @@ impl ActivityHandler for Accept {
self.actor.inner() self.actor.inner()
} }
async fn verify(&self, _data: &Data<Self::DataType>) -> Result<(), Self::Error> { async fn verify(&self, _context: &Data<Self::DataType>) -> Result<(), Self::Error> {
Ok(()) Ok(())
} }
async fn receive(self, data: &Data<Self::DataType>) -> Result<(), Self::Error> { async fn receive(self, context: &Data<Self::DataType>) -> Result<(), Self::Error> {
// add to follows // add to follows
let person = self.object.actor.dereference_local(data).await?; let person = self.object.actor.dereference_local(context).await?;
let instance = self.actor.dereference(data).await?; let instance = self.actor.dereference(context).await?;
DbInstance::follow(&person, &instance, false, data)?; DbInstance::follow(&person, &instance, false, context)?;
Ok(()) Ok(())
} }
} }

View file

@ -1,6 +1,6 @@
use crate::{ use crate::{
backend::{ backend::{
database::IbisData, database::IbisContext,
federation::{routes::AnnouncableActivities, send_activity}, federation::{routes::AnnouncableActivities, send_activity},
utils::{ utils::{
error::{Error, MyResult}, error::{Error, MyResult},
@ -32,7 +32,7 @@ pub struct AnnounceActivity {
} }
impl AnnounceActivity { impl AnnounceActivity {
pub async fn send(object: AnnouncableActivities, context: &Data<IbisData>) -> MyResult<()> { pub async fn send(object: AnnouncableActivities, context: &Data<IbisContext>) -> MyResult<()> {
let id = generate_activity_id(context)?; let id = generate_activity_id(context)?;
let instance = DbInstance::read_local(context)?; let instance = DbInstance::read_local(context)?;
let announce = AnnounceActivity { let announce = AnnounceActivity {
@ -56,7 +56,7 @@ impl AnnounceActivity {
#[async_trait::async_trait] #[async_trait::async_trait]
impl ActivityHandler for AnnounceActivity { impl ActivityHandler for AnnounceActivity {
type DataType = IbisData; type DataType = IbisContext;
type Error = Error; type Error = Error;
fn id(&self) -> &Url { fn id(&self) -> &Url {

View file

@ -1,7 +1,7 @@
use super::generate_comment_activity_to; use super::generate_comment_activity_to;
use crate::{ use crate::{
backend::{ backend::{
database::IbisData, database::IbisContext,
federation::{ federation::{
objects::comment::ApubComment, objects::comment::ApubComment,
routes::AnnouncableActivities, routes::AnnouncableActivities,
@ -40,16 +40,16 @@ pub struct CreateOrUpdateComment {
} }
impl CreateOrUpdateComment { impl CreateOrUpdateComment {
pub async fn send(comment: &DbComment, data: &Data<IbisData>) -> MyResult<()> { pub async fn send(comment: &DbComment, context: &Data<IbisContext>) -> MyResult<()> {
let instance = DbInstance::read_for_comment(comment.id, data)?; let instance = DbInstance::read_for_comment(comment.id, context)?;
let kind = if comment.updated.is_none() { let kind = if comment.updated.is_none() {
CreateOrUpdateType::Create CreateOrUpdateType::Create
} else { } else {
CreateOrUpdateType::Update CreateOrUpdateType::Update
}; };
let object = comment.clone().into_json(data).await?; let object = comment.clone().into_json(context).await?;
let id = generate_activity_id(data)?; let id = generate_activity_id(context)?;
let activity = Self { let activity = Self {
actor: object.attributed_to.clone(), actor: object.attributed_to.clone(),
object, object,
@ -58,15 +58,15 @@ impl CreateOrUpdateComment {
id, id,
}; };
let activity = AnnouncableActivities::CreateOrUpdateComment(activity); let activity = AnnouncableActivities::CreateOrUpdateComment(activity);
let creator = DbPerson::read(comment.creator_id, data)?; let creator = DbPerson::read(comment.creator_id, context)?;
send_activity_to_instance(&creator, activity, &instance, data).await?; send_activity_to_instance(&creator, activity, &instance, context).await?;
Ok(()) Ok(())
} }
} }
#[async_trait::async_trait] #[async_trait::async_trait]
impl ActivityHandler for CreateOrUpdateComment { impl ActivityHandler for CreateOrUpdateComment {
type DataType = IbisData; type DataType = IbisContext;
type Error = Error; type Error = Error;
fn id(&self) -> &Url { fn id(&self) -> &Url {
@ -77,18 +77,18 @@ impl ActivityHandler for CreateOrUpdateComment {
self.actor.inner() self.actor.inner()
} }
async fn verify(&self, _data: &Data<Self::DataType>) -> Result<(), Self::Error> { async fn verify(&self, _context: &Data<Self::DataType>) -> Result<(), Self::Error> {
verify_domains_match(&self.id, self.object.id.inner())?; verify_domains_match(&self.id, self.object.id.inner())?;
verify_domains_match(&self.id, self.actor.inner())?; verify_domains_match(&self.id, self.actor.inner())?;
Ok(()) Ok(())
} }
async fn receive(self, data: &Data<Self::DataType>) -> Result<(), Self::Error> { async fn receive(self, context: &Data<Self::DataType>) -> Result<(), Self::Error> {
let comment = DbComment::from_json(self.object, data).await?; let comment = DbComment::from_json(self.object, context).await?;
let instance = DbInstance::read_for_comment(comment.id, data)?; let instance = DbInstance::read_for_comment(comment.id, context)?;
if instance.local { if instance.local {
Self::send(&comment, data).await?; Self::send(&comment, context).await?;
} }
Ok(()) Ok(())
} }

View file

@ -1,7 +1,7 @@
use super::generate_comment_activity_to; use super::generate_comment_activity_to;
use crate::{ use crate::{
backend::{ backend::{
database::{comment::DbCommentUpdateForm, IbisData}, database::{comment::DbCommentUpdateForm, IbisContext},
federation::{routes::AnnouncableActivities, send_activity_to_instance}, federation::{routes::AnnouncableActivities, send_activity_to_instance},
utils::{ utils::{
error::{Error, MyResult}, error::{Error, MyResult},
@ -38,9 +38,9 @@ impl DeleteComment {
comment: &DbComment, comment: &DbComment,
creator: &DbPerson, creator: &DbPerson,
instance: &DbInstance, instance: &DbInstance,
data: &Data<IbisData>, context: &Data<IbisContext>,
) -> MyResult<Self> { ) -> MyResult<Self> {
let id = generate_activity_id(data)?; let id = generate_activity_id(context)?;
Ok(DeleteComment { Ok(DeleteComment {
actor: creator.ap_id.clone(), actor: creator.ap_id.clone(),
object: comment.ap_id.clone(), object: comment.ap_id.clone(),
@ -49,19 +49,19 @@ impl DeleteComment {
id, id,
}) })
} }
pub async fn send(comment: &DbComment, data: &Data<IbisData>) -> MyResult<()> { pub async fn send(comment: &DbComment, context: &Data<IbisContext>) -> MyResult<()> {
let instance = DbInstance::read_for_comment(comment.id, data)?; let instance = DbInstance::read_for_comment(comment.id, context)?;
let creator = DbPerson::read(comment.creator_id, data)?; let creator = DbPerson::read(comment.creator_id, context)?;
let activity = Self::new(comment, &creator, &instance, data)?; let activity = Self::new(comment, &creator, &instance, context)?;
let activity = AnnouncableActivities::DeleteComment(activity); let activity = AnnouncableActivities::DeleteComment(activity);
send_activity_to_instance(&creator, activity, &instance, data).await?; send_activity_to_instance(&creator, activity, &instance, context).await?;
Ok(()) Ok(())
} }
} }
#[async_trait::async_trait] #[async_trait::async_trait]
impl ActivityHandler for DeleteComment { impl ActivityHandler for DeleteComment {
type DataType = IbisData; type DataType = IbisContext;
type Error = Error; type Error = Error;
fn id(&self) -> &Url { fn id(&self) -> &Url {
@ -72,24 +72,24 @@ impl ActivityHandler for DeleteComment {
self.actor.inner() self.actor.inner()
} }
async fn verify(&self, _data: &Data<Self::DataType>) -> Result<(), Self::Error> { async fn verify(&self, _context: &Data<Self::DataType>) -> Result<(), Self::Error> {
verify_domains_match(self.actor.inner(), &self.id)?; verify_domains_match(self.actor.inner(), &self.id)?;
verify_domains_match(self.actor.inner(), self.object.inner())?; verify_domains_match(self.actor.inner(), self.object.inner())?;
Ok(()) Ok(())
} }
async fn receive(self, data: &Data<Self::DataType>) -> Result<(), Self::Error> { async fn receive(self, context: &Data<Self::DataType>) -> Result<(), Self::Error> {
let form = DbCommentUpdateForm { let form = DbCommentUpdateForm {
deleted: Some(true), deleted: Some(true),
updated: Some(Utc::now()), updated: Some(Utc::now()),
..Default::default() ..Default::default()
}; };
let comment = self.object.dereference(data).await?; let comment = self.object.dereference(context).await?;
DbComment::update(form, comment.id, data)?; DbComment::update(form, comment.id, context)?;
let instance = DbInstance::read_for_comment(comment.id, data)?; let instance = DbInstance::read_for_comment(comment.id, context)?;
if instance.local { if instance.local {
Self::send(&comment, data).await?; Self::send(&comment, context).await?;
} }
Ok(()) Ok(())
} }

View file

@ -1,7 +1,7 @@
use super::{delete_comment::DeleteComment, generate_comment_activity_to}; use super::{delete_comment::DeleteComment, generate_comment_activity_to};
use crate::{ use crate::{
backend::{ backend::{
database::{comment::DbCommentUpdateForm, IbisData}, database::{comment::DbCommentUpdateForm, IbisContext},
federation::{routes::AnnouncableActivities, send_activity_to_instance}, federation::{routes::AnnouncableActivities, send_activity_to_instance},
utils::{ utils::{
error::{Error, MyResult}, error::{Error, MyResult},
@ -37,11 +37,11 @@ pub struct UndoDeleteComment {
} }
impl UndoDeleteComment { impl UndoDeleteComment {
pub async fn send(comment: &DbComment, data: &Data<IbisData>) -> MyResult<()> { pub async fn send(comment: &DbComment, context: &Data<IbisContext>) -> MyResult<()> {
let instance = DbInstance::read_for_comment(comment.id, data)?; let instance = DbInstance::read_for_comment(comment.id, context)?;
let id = generate_activity_id(data)?; let id = generate_activity_id(context)?;
let creator = DbPerson::read(comment.creator_id, data)?; let creator = DbPerson::read(comment.creator_id, context)?;
let object = DeleteComment::new(comment, &creator, &instance, data)?; let object = DeleteComment::new(comment, &creator, &instance, context)?;
let activity = UndoDeleteComment { let activity = UndoDeleteComment {
actor: creator.ap_id.clone(), actor: creator.ap_id.clone(),
object, object,
@ -50,14 +50,14 @@ impl UndoDeleteComment {
id, id,
}; };
let activity = AnnouncableActivities::UndoDeleteComment(activity); let activity = AnnouncableActivities::UndoDeleteComment(activity);
send_activity_to_instance(&creator, activity, &instance, data).await?; send_activity_to_instance(&creator, activity, &instance, context).await?;
Ok(()) Ok(())
} }
} }
#[async_trait::async_trait] #[async_trait::async_trait]
impl ActivityHandler for UndoDeleteComment { impl ActivityHandler for UndoDeleteComment {
type DataType = IbisData; type DataType = IbisContext;
type Error = Error; type Error = Error;
fn id(&self) -> &Url { fn id(&self) -> &Url {
@ -68,24 +68,24 @@ impl ActivityHandler for UndoDeleteComment {
self.actor.inner() self.actor.inner()
} }
async fn verify(&self, _data: &Data<Self::DataType>) -> Result<(), Self::Error> { async fn verify(&self, _context: &Data<Self::DataType>) -> Result<(), Self::Error> {
verify_urls_match(self.actor.inner(), self.object.actor.inner())?; verify_urls_match(self.actor.inner(), self.object.actor.inner())?;
verify_domains_match(self.actor.inner(), &self.id)?; verify_domains_match(self.actor.inner(), &self.id)?;
Ok(()) Ok(())
} }
async fn receive(self, data: &Data<Self::DataType>) -> Result<(), Self::Error> { async fn receive(self, context: &Data<Self::DataType>) -> Result<(), Self::Error> {
let form = DbCommentUpdateForm { let form = DbCommentUpdateForm {
deleted: Some(false), deleted: Some(false),
updated: Some(Utc::now()), updated: Some(Utc::now()),
..Default::default() ..Default::default()
}; };
let comment = self.object.object.dereference(data).await?; let comment = self.object.object.dereference(context).await?;
DbComment::update(form, comment.id, data)?; DbComment::update(form, comment.id, context)?;
let instance = DbInstance::read_for_comment(comment.id, data)?; let instance = DbInstance::read_for_comment(comment.id, context)?;
if instance.local { if instance.local {
Self::send(&comment, data).await?; Self::send(&comment, context).await?;
} }
Ok(()) Ok(())
} }

View file

@ -1,6 +1,6 @@
use crate::{ use crate::{
backend::{ backend::{
database::IbisData, database::IbisContext,
federation::objects::article::ApubArticle, federation::objects::article::ApubArticle,
utils::{ utils::{
error::{Error, MyResult}, error::{Error, MyResult},
@ -32,11 +32,14 @@ pub struct CreateArticle {
} }
impl CreateArticle { impl CreateArticle {
pub async fn send_to_followers(article: DbArticle, data: &Data<IbisData>) -> MyResult<()> { pub async fn send_to_followers(
let local_instance = DbInstance::read_local(data)?; article: DbArticle,
let object = article.clone().into_json(data).await?; context: &Data<IbisContext>,
let id = generate_activity_id(data)?; ) -> MyResult<()> {
let to = local_instance.follower_ids(data)?; let local_instance = DbInstance::read_local(context)?;
let object = article.clone().into_json(context).await?;
let id = generate_activity_id(context)?;
let to = local_instance.follower_ids(context)?;
let create = CreateArticle { let create = CreateArticle {
actor: local_instance.ap_id.clone(), actor: local_instance.ap_id.clone(),
to, to,
@ -45,14 +48,14 @@ impl CreateArticle {
id, id,
}; };
local_instance local_instance
.send_to_followers(create, vec![], data) .send_to_followers(create, vec![], context)
.await?; .await?;
Ok(()) Ok(())
} }
} }
#[async_trait::async_trait] #[async_trait::async_trait]
impl ActivityHandler for CreateArticle { impl ActivityHandler for CreateArticle {
type DataType = IbisData; type DataType = IbisContext;
type Error = Error; type Error = Error;
fn id(&self) -> &Url { fn id(&self) -> &Url {
@ -63,15 +66,17 @@ impl ActivityHandler for CreateArticle {
self.actor.inner() self.actor.inner()
} }
async fn verify(&self, _data: &Data<Self::DataType>) -> Result<(), Self::Error> { async fn verify(&self, _context: &Data<Self::DataType>) -> Result<(), Self::Error> {
Ok(()) Ok(())
} }
async fn receive(self, data: &Data<Self::DataType>) -> Result<(), Self::Error> { async fn receive(self, context: &Data<Self::DataType>) -> Result<(), Self::Error> {
let article = DbArticle::from_json(self.object.clone(), data).await?; let article = DbArticle::from_json(self.object.clone(), context).await?;
if article.local { if article.local {
let local_instance = DbInstance::read_local(data)?; let local_instance = DbInstance::read_local(context)?;
local_instance.send_to_followers(self, vec![], data).await?; local_instance
.send_to_followers(self, vec![], context)
.await?;
} }
Ok(()) Ok(())
} }

View file

@ -1,6 +1,6 @@
use crate::{ use crate::{
backend::{ backend::{
database::IbisData, database::IbisContext,
federation::{activities::accept::Accept, send_activity}, federation::{activities::accept::Accept, send_activity},
generate_activity_id, generate_activity_id,
utils::error::{Error, MyResult}, utils::error::{Error, MyResult},
@ -28,22 +28,26 @@ pub struct Follow {
} }
impl Follow { impl Follow {
pub async fn send(actor: DbPerson, to: &DbInstance, data: &Data<IbisData>) -> MyResult<()> { pub async fn send(
let id = generate_activity_id(data)?; actor: DbPerson,
to: &DbInstance,
context: &Data<IbisContext>,
) -> MyResult<()> {
let id = generate_activity_id(context)?;
let follow = Follow { let follow = Follow {
actor: actor.ap_id.clone(), actor: actor.ap_id.clone(),
object: to.ap_id.clone(), object: to.ap_id.clone(),
kind: Default::default(), kind: Default::default(),
id, id,
}; };
send_activity(&actor, follow, vec![to.shared_inbox_or_inbox()], data).await?; send_activity(&actor, follow, vec![to.shared_inbox_or_inbox()], context).await?;
Ok(()) Ok(())
} }
} }
#[async_trait::async_trait] #[async_trait::async_trait]
impl ActivityHandler for Follow { impl ActivityHandler for Follow {
type DataType = IbisData; type DataType = IbisContext;
type Error = Error; type Error = Error;
fn id(&self) -> &Url { fn id(&self) -> &Url {
@ -54,18 +58,18 @@ impl ActivityHandler for Follow {
self.actor.inner() self.actor.inner()
} }
async fn verify(&self, _data: &Data<Self::DataType>) -> Result<(), Self::Error> { async fn verify(&self, _context: &Data<Self::DataType>) -> Result<(), Self::Error> {
Ok(()) Ok(())
} }
async fn receive(self, data: &Data<Self::DataType>) -> Result<(), Self::Error> { async fn receive(self, context: &Data<Self::DataType>) -> Result<(), Self::Error> {
let actor = self.actor.dereference(data).await?; let actor = self.actor.dereference(context).await?;
let local_instance = DbInstance::read_local(data)?; let local_instance = DbInstance::read_local(context)?;
verify_urls_match(self.object.inner(), local_instance.ap_id.inner())?; verify_urls_match(self.object.inner(), local_instance.ap_id.inner())?;
DbInstance::follow(&actor, &local_instance, false, data)?; DbInstance::follow(&actor, &local_instance, false, context)?;
// send back an accept // send back an accept
Accept::send(local_instance, self, data).await?; Accept::send(local_instance, self, context).await?;
Ok(()) Ok(())
} }
} }

View file

@ -1,6 +1,6 @@
use crate::{ use crate::{
backend::{ backend::{
database::{edit::DbEditForm, IbisData}, database::{edit::DbEditForm, IbisContext},
federation::activities::{ federation::activities::{
update_local_article::UpdateLocalArticle, update_local_article::UpdateLocalArticle,
update_remote_article::UpdateRemoteArticle, update_remote_article::UpdateRemoteArticle,
@ -30,7 +30,7 @@ pub async fn submit_article_update(
previous_version: EditVersion, previous_version: EditVersion,
original_article: &DbArticle, original_article: &DbArticle,
creator_id: PersonId, creator_id: PersonId,
data: &Data<IbisData>, context: &Data<IbisContext>,
) -> Result<(), Error> { ) -> Result<(), Error> {
let mut form = DbEditForm::new( let mut form = DbEditForm::new(
original_article, original_article,
@ -41,16 +41,16 @@ pub async fn submit_article_update(
false, false,
)?; )?;
if original_article.local { if original_article.local {
let edit = DbEdit::create(&form, data)?; let edit = DbEdit::create(&form, context)?;
let updated_article = DbArticle::update_text(edit.article_id, &new_text, data)?; let updated_article = DbArticle::update_text(edit.article_id, &new_text, context)?;
UpdateLocalArticle::send(updated_article, vec![], data).await?; UpdateLocalArticle::send(updated_article, vec![], context).await?;
} else { } else {
// insert edit as pending, so only the creator can see it // insert edit as pending, so only the creator can see it
form.pending = true; form.pending = true;
let edit = DbEdit::create(&form, data)?; let edit = DbEdit::create(&form, context)?;
let instance = DbInstance::read(original_article.instance_id, data)?; let instance = DbInstance::read(original_article.instance_id, context)?;
UpdateRemoteArticle::send(edit, instance, data).await?; UpdateRemoteArticle::send(edit, instance, context).await?;
} }
Ok(()) Ok(())
} }

View file

@ -2,7 +2,7 @@ use crate::{
backend::{ backend::{
database::{ database::{
conflict::{DbConflict, DbConflictForm}, conflict::{DbConflict, DbConflictForm},
IbisData, IbisContext,
}, },
federation::{objects::edit::ApubEdit, send_activity}, federation::{objects::edit::ApubEdit, send_activity},
utils::{ utils::{
@ -38,10 +38,10 @@ impl RejectEdit {
pub async fn send( pub async fn send(
edit: ApubEdit, edit: ApubEdit,
user_instance: DbInstance, user_instance: DbInstance,
data: &Data<IbisData>, context: &Data<IbisContext>,
) -> MyResult<()> { ) -> MyResult<()> {
let local_instance = DbInstance::read_local(data)?; let local_instance = DbInstance::read_local(context)?;
let id = generate_activity_id(data)?; let id = generate_activity_id(context)?;
let reject = RejectEdit { let reject = RejectEdit {
actor: local_instance.ap_id.clone(), actor: local_instance.ap_id.clone(),
to: vec![user_instance.ap_id.into_inner()], to: vec![user_instance.ap_id.into_inner()],
@ -53,7 +53,7 @@ impl RejectEdit {
&local_instance, &local_instance,
reject, reject,
vec![Url::parse(&user_instance.inbox_url)?], vec![Url::parse(&user_instance.inbox_url)?],
data, context,
) )
.await?; .await?;
Ok(()) Ok(())
@ -62,7 +62,7 @@ impl RejectEdit {
#[async_trait::async_trait] #[async_trait::async_trait]
impl ActivityHandler for RejectEdit { impl ActivityHandler for RejectEdit {
type DataType = IbisData; type DataType = IbisContext;
type Error = Error; type Error = Error;
fn id(&self) -> &Url { fn id(&self) -> &Url {
@ -73,14 +73,14 @@ impl ActivityHandler for RejectEdit {
self.actor.inner() self.actor.inner()
} }
async fn verify(&self, _data: &Data<Self::DataType>) -> Result<(), Self::Error> { async fn verify(&self, _context: &Data<Self::DataType>) -> Result<(), Self::Error> {
Ok(()) Ok(())
} }
async fn receive(self, data: &Data<Self::DataType>) -> Result<(), Self::Error> { async fn receive(self, context: &Data<Self::DataType>) -> Result<(), Self::Error> {
// cant convert this to DbEdit as it tries to apply patch and fails // cant convert this to DbEdit as it tries to apply patch and fails
let article = self.object.object.dereference(data).await?; let article = self.object.object.dereference(context).await?;
let creator = self.object.attributed_to.dereference(data).await?; let creator = self.object.attributed_to.dereference(context).await?;
let form = DbConflictForm { let form = DbConflictForm {
hash: EditVersion::new(&self.object.content), hash: EditVersion::new(&self.object.content),
diff: self.object.content, diff: self.object.content,
@ -89,7 +89,7 @@ impl ActivityHandler for RejectEdit {
article_id: article.id, article_id: article.id,
previous_version_id: self.object.previous_version, previous_version_id: self.object.previous_version,
}; };
DbConflict::create(&form, data)?; DbConflict::create(&form, context)?;
Ok(()) Ok(())
} }
} }

View file

@ -1,6 +1,6 @@
use crate::{ use crate::{
backend::{ backend::{
database::IbisData, database::IbisContext,
federation::objects::article::ApubArticle, federation::objects::article::ApubArticle,
utils::{ utils::{
error::{Error, MyResult}, error::{Error, MyResult},
@ -36,22 +36,22 @@ impl UpdateLocalArticle {
pub async fn send( pub async fn send(
article: DbArticle, article: DbArticle,
extra_recipients: Vec<DbInstance>, extra_recipients: Vec<DbInstance>,
data: &Data<IbisData>, context: &Data<IbisContext>,
) -> MyResult<()> { ) -> MyResult<()> {
debug_assert!(article.local); debug_assert!(article.local);
let local_instance = DbInstance::read_local(data)?; let local_instance = DbInstance::read_local(context)?;
let id = generate_activity_id(data)?; let id = generate_activity_id(context)?;
let mut to = local_instance.follower_ids(data)?; let mut to = local_instance.follower_ids(context)?;
to.extend(extra_recipients.iter().map(|i| i.ap_id.inner().clone())); to.extend(extra_recipients.iter().map(|i| i.ap_id.inner().clone()));
let update = UpdateLocalArticle { let update = UpdateLocalArticle {
actor: local_instance.ap_id.clone(), actor: local_instance.ap_id.clone(),
to, to,
object: article.into_json(data).await?, object: article.into_json(context).await?,
kind: Default::default(), kind: Default::default(),
id, id,
}; };
local_instance local_instance
.send_to_followers(update, extra_recipients, data) .send_to_followers(update, extra_recipients, context)
.await?; .await?;
Ok(()) Ok(())
} }
@ -59,7 +59,7 @@ impl UpdateLocalArticle {
#[async_trait::async_trait] #[async_trait::async_trait]
impl ActivityHandler for UpdateLocalArticle { impl ActivityHandler for UpdateLocalArticle {
type DataType = IbisData; type DataType = IbisContext;
type Error = Error; type Error = Error;
fn id(&self) -> &Url { fn id(&self) -> &Url {
@ -70,13 +70,13 @@ impl ActivityHandler for UpdateLocalArticle {
self.actor.inner() self.actor.inner()
} }
async fn verify(&self, _data: &Data<Self::DataType>) -> Result<(), Self::Error> { async fn verify(&self, _context: &Data<Self::DataType>) -> Result<(), Self::Error> {
Ok(()) Ok(())
} }
/// Received on article follower instances (where article is always remote) /// Received on article follower instances (where article is always remote)
async fn receive(self, data: &Data<Self::DataType>) -> Result<(), Self::Error> { async fn receive(self, context: &Data<Self::DataType>) -> Result<(), Self::Error> {
DbArticle::from_json(self.object, data).await?; DbArticle::from_json(self.object, context).await?;
Ok(()) Ok(())
} }

View file

@ -1,6 +1,6 @@
use crate::{ use crate::{
backend::{ backend::{
database::IbisData, database::IbisContext,
federation::{ federation::{
activities::{reject::RejectEdit, update_local_article::UpdateLocalArticle}, activities::{reject::RejectEdit, update_local_article::UpdateLocalArticle},
objects::edit::ApubEdit, objects::edit::ApubEdit,
@ -45,14 +45,14 @@ impl UpdateRemoteArticle {
pub async fn send( pub async fn send(
edit: DbEdit, edit: DbEdit,
article_instance: DbInstance, article_instance: DbInstance,
data: &Data<IbisData>, context: &Data<IbisContext>,
) -> MyResult<()> { ) -> MyResult<()> {
let local_instance = DbInstance::read_local(data)?; let local_instance = DbInstance::read_local(context)?;
let id = generate_activity_id(data)?; let id = generate_activity_id(context)?;
let update = UpdateRemoteArticle { let update = UpdateRemoteArticle {
actor: local_instance.ap_id.clone(), actor: local_instance.ap_id.clone(),
to: vec![article_instance.ap_id.into_inner()], to: vec![article_instance.ap_id.into_inner()],
object: edit.into_json(data).await?, object: edit.into_json(context).await?,
kind: Default::default(), kind: Default::default(),
id, id,
}; };
@ -60,7 +60,7 @@ impl UpdateRemoteArticle {
&local_instance, &local_instance,
update, update,
vec![Url::parse(&article_instance.inbox_url)?], vec![Url::parse(&article_instance.inbox_url)?],
data, context,
) )
.await?; .await?;
Ok(()) Ok(())
@ -69,7 +69,7 @@ impl UpdateRemoteArticle {
#[async_trait::async_trait] #[async_trait::async_trait]
impl ActivityHandler for UpdateRemoteArticle { impl ActivityHandler for UpdateRemoteArticle {
type DataType = IbisData; type DataType = IbisContext;
type Error = Error; type Error = Error;
fn id(&self) -> &Url { fn id(&self) -> &Url {
@ -80,27 +80,31 @@ impl ActivityHandler for UpdateRemoteArticle {
self.actor.inner() self.actor.inner()
} }
async fn verify(&self, data: &Data<Self::DataType>) -> Result<(), Self::Error> { async fn verify(&self, context: &Data<Self::DataType>) -> Result<(), Self::Error> {
let article = DbArticle::read_from_ap_id(&self.object.object, data)?; let article = DbArticle::read_from_ap_id(&self.object.object, context)?;
can_edit_article(&article, false)?; can_edit_article(&article, false)?;
Ok(()) Ok(())
} }
/// Received on article origin instance /// Received on article origin instance
async fn receive(self, data: &Data<Self::DataType>) -> Result<(), Self::Error> { async fn receive(self, context: &Data<Self::DataType>) -> Result<(), Self::Error> {
let local_article = DbArticle::read_from_ap_id(&self.object.object, data)?; let local_article = DbArticle::read_from_ap_id(&self.object.object, context)?;
let patch = Patch::from_str(&self.object.content)?; let patch = Patch::from_str(&self.object.content)?;
match apply(&local_article.text, &patch) { match apply(&local_article.text, &patch) {
Ok(applied) => { Ok(applied) => {
let edit = DbEdit::from_json(self.object.clone(), data).await?; let edit = DbEdit::from_json(self.object.clone(), context).await?;
let article = DbArticle::update_text(edit.article_id, &applied, data)?; let article = DbArticle::update_text(edit.article_id, &applied, context)?;
UpdateLocalArticle::send(article, vec![self.actor.dereference(data).await?], data) UpdateLocalArticle::send(
.await?; article,
vec![self.actor.dereference(context).await?],
context,
)
.await?;
} }
Err(_e) => { Err(_e) => {
let user_instance = self.actor.dereference(data).await?; let user_instance = self.actor.dereference(context).await?;
RejectEdit::send(self.object.clone(), user_instance, data).await?; RejectEdit::send(self.object.clone(), user_instance, context).await?;
} }
} }

View file

@ -1,6 +1,6 @@
use super::utils::error::MyResult; use super::utils::error::MyResult;
use crate::{ use crate::{
backend::{config::IbisConfig, database::IbisData}, backend::{config::IbisConfig, database::IbisContext},
common::{instance::DbInstance, user::DbPerson}, common::{instance::DbInstance, user::DbPerson},
}; };
use activities::announce::AnnounceActivity; use activities::announce::AnnounceActivity;
@ -25,14 +25,14 @@ pub async fn send_activity<Activity, ActorType: Actor>(
actor: &ActorType, actor: &ActorType,
activity: Activity, activity: Activity,
recipients: Vec<Url>, recipients: Vec<Url>,
data: &Data<IbisData>, context: &Data<IbisContext>,
) -> Result<(), <Activity as ActivityHandler>::Error> ) -> Result<(), <Activity as ActivityHandler>::Error>
where where
Activity: ActivityHandler + Serialize + Debug + Send + Sync, Activity: ActivityHandler + Serialize + Debug + Send + Sync,
<Activity as ActivityHandler>::Error: From<activitypub_federation::error::Error>, <Activity as ActivityHandler>::Error: From<activitypub_federation::error::Error>,
{ {
let activity = WithContext::new_default(activity); let activity = WithContext::new_default(activity);
queue_activity(&activity, actor, recipients, data).await?; queue_activity(&activity, actor, recipients, context).await?;
Ok(()) Ok(())
} }
@ -40,13 +40,13 @@ pub async fn send_activity_to_instance(
actor: &DbPerson, actor: &DbPerson,
activity: AnnouncableActivities, activity: AnnouncableActivities,
instance: &DbInstance, instance: &DbInstance,
data: &Data<IbisData>, context: &Data<IbisContext>,
) -> MyResult<()> { ) -> MyResult<()> {
if instance.local { if instance.local {
AnnounceActivity::send(activity, data).await?; AnnounceActivity::send(activity, context).await?;
} else { } else {
let inbox_url = instance.inbox_url.parse()?; let inbox_url = instance.inbox_url.parse()?;
send_activity(actor, activity, vec![inbox_url], data).await?; send_activity(actor, activity, vec![inbox_url], context).await?;
} }
Ok(()) Ok(())
} }

View file

@ -1,6 +1,6 @@
use crate::{ use crate::{
backend::{ backend::{
database::{article::DbArticleForm, IbisData}, database::{article::DbArticleForm, IbisContext},
federation::objects::edits_collection::DbEditCollection, federation::objects::edits_collection::DbEditCollection,
utils::{error::Error, validate::validate_article_title}, utils::{error::Error, validate::validate_article_title},
}, },
@ -40,27 +40,27 @@ pub struct ApubArticle {
#[async_trait::async_trait] #[async_trait::async_trait]
impl Object for DbArticle { impl Object for DbArticle {
type DataType = IbisData; type DataType = IbisContext;
type Kind = ApubArticle; type Kind = ApubArticle;
type Error = Error; type Error = Error;
async fn read_from_id( async fn read_from_id(
object_id: Url, object_id: Url,
data: &Data<Self::DataType>, context: &Data<Self::DataType>,
) -> Result<Option<Self>, Self::Error> { ) -> Result<Option<Self>, Self::Error> {
let article = DbArticle::read_from_ap_id(&object_id.into(), data).ok(); let article = DbArticle::read_from_ap_id(&object_id.into(), context).ok();
Ok(article) Ok(article)
} }
async fn into_json(self, data: &Data<Self::DataType>) -> Result<Self::Kind, Self::Error> { async fn into_json(self, context: &Data<Self::DataType>) -> Result<Self::Kind, Self::Error> {
let local_instance = DbInstance::read_local(data)?; let local_instance = DbInstance::read_local(context)?;
Ok(ApubArticle { Ok(ApubArticle {
kind: Default::default(), kind: Default::default(),
id: self.ap_id.clone(), id: self.ap_id.clone(),
attributed_to: local_instance.ap_id.clone(), attributed_to: local_instance.ap_id.clone(),
to: vec![public(), local_instance.followers_url()?], to: vec![public(), local_instance.followers_url()?],
edits: self.edits_id()?, edits: self.edits_id()?,
latest_version: self.latest_edit_version(data)?, latest_version: self.latest_edit_version(context)?,
content: self.text, content: self.text,
name: self.title, name: self.title,
protected: self.protected, protected: self.protected,
@ -70,15 +70,18 @@ impl Object for DbArticle {
async fn verify( async fn verify(
json: &Self::Kind, json: &Self::Kind,
expected_domain: &Url, expected_domain: &Url,
data: &Data<Self::DataType>, context: &Data<Self::DataType>,
) -> Result<(), Self::Error> { ) -> Result<(), Self::Error> {
verify_domains_match(json.id.inner(), expected_domain)?; verify_domains_match(json.id.inner(), expected_domain)?;
verify_is_remote_object(&json.id, data)?; verify_is_remote_object(&json.id, context)?;
Ok(()) Ok(())
} }
async fn from_json(json: Self::Kind, data: &Data<Self::DataType>) -> Result<Self, Self::Error> { async fn from_json(
let instance = json.attributed_to.dereference(data).await?; json: Self::Kind,
context: &Data<Self::DataType>,
) -> Result<Self, Self::Error> {
let instance = json.attributed_to.dereference(context).await?;
let mut form = DbArticleForm { let mut form = DbArticleForm {
title: json.name, title: json.name,
text: json.content, text: json.content,
@ -89,9 +92,9 @@ impl Object for DbArticle {
approved: true, approved: true,
}; };
form.title = validate_article_title(&form.title)?; form.title = validate_article_title(&form.title)?;
let article = DbArticle::create_or_update(form, data)?; let article = DbArticle::create_or_update(form, context)?;
json.edits.dereference(&article, data).await?; json.edits.dereference(&article, context).await?;
Ok(article) Ok(article)
} }

View file

@ -1,7 +1,7 @@
use super::{article::ApubArticle, comment::ApubComment}; use super::{article::ApubArticle, comment::ApubComment};
use crate::{ use crate::{
backend::{ backend::{
database::IbisData, database::IbisContext,
utils::error::{Error, MyResult}, utils::error::{Error, MyResult},
}, },
common::{article::DbArticle, comment::DbComment}, common::{article::DbArticle, comment::DbComment},
@ -26,7 +26,7 @@ pub enum ApubArticleOrComment {
#[async_trait::async_trait] #[async_trait::async_trait]
impl Object for DbArticleOrComment { impl Object for DbArticleOrComment {
type DataType = IbisData; type DataType = IbisContext;
type Kind = ApubArticleOrComment; type Kind = ApubArticleOrComment;
type Error = Error; type Error = Error;
@ -34,38 +34,41 @@ impl Object for DbArticleOrComment {
None None
} }
async fn read_from_id(object_id: Url, data: &Data<Self::DataType>) -> MyResult<Option<Self>> { async fn read_from_id(
let post = DbArticle::read_from_id(object_id.clone(), data).await?; object_id: Url,
context: &Data<Self::DataType>,
) -> MyResult<Option<Self>> {
let post = DbArticle::read_from_id(object_id.clone(), context).await?;
Ok(match post { Ok(match post {
Some(o) => Some(Self::Article(o)), Some(o) => Some(Self::Article(o)),
None => DbComment::read_from_id(object_id, data) None => DbComment::read_from_id(object_id, context)
.await? .await?
.map(Self::Comment), .map(Self::Comment),
}) })
} }
async fn delete(self, data: &Data<Self::DataType>) -> MyResult<()> { async fn delete(self, context: &Data<Self::DataType>) -> MyResult<()> {
match self { match self {
Self::Article(p) => p.delete(data).await, Self::Article(p) => p.delete(context).await,
Self::Comment(c) => c.delete(data).await, Self::Comment(c) => c.delete(context).await,
} }
} }
async fn into_json(self, data: &Data<Self::DataType>) -> MyResult<Self::Kind> { async fn into_json(self, context: &Data<Self::DataType>) -> MyResult<Self::Kind> {
Ok(match self { Ok(match self {
Self::Article(p) => Self::Kind::Article(Box::new(p.into_json(data).await?)), Self::Article(p) => Self::Kind::Article(Box::new(p.into_json(context).await?)),
Self::Comment(c) => Self::Kind::Comment(Box::new(c.into_json(data).await?)), Self::Comment(c) => Self::Kind::Comment(Box::new(c.into_json(context).await?)),
}) })
} }
async fn verify( async fn verify(
apub: &Self::Kind, apub: &Self::Kind,
expected_domain: &Url, expected_domain: &Url,
data: &Data<Self::DataType>, context: &Data<Self::DataType>,
) -> MyResult<()> { ) -> MyResult<()> {
match apub { match apub {
Self::Kind::Article(a) => DbArticle::verify(a, expected_domain, data).await, Self::Kind::Article(a) => DbArticle::verify(a, expected_domain, context).await,
Self::Kind::Comment(a) => DbComment::verify(a, expected_domain, data).await, Self::Kind::Comment(a) => DbComment::verify(a, expected_domain, context).await,
} }
} }

View file

@ -1,6 +1,6 @@
use crate::{ use crate::{
backend::{ backend::{
database::IbisData, database::IbisContext,
federation::objects::article::ApubArticle, federation::objects::article::ApubArticle,
utils::error::{Error, MyResult}, utils::error::{Error, MyResult},
}, },
@ -40,25 +40,25 @@ pub fn local_articles_url(domain: &str) -> MyResult<CollectionId<DbArticleCollec
#[async_trait::async_trait] #[async_trait::async_trait]
impl Collection for DbArticleCollection { impl Collection for DbArticleCollection {
type Owner = (); type Owner = ();
type DataType = IbisData; type DataType = IbisContext;
type Kind = ArticleCollection; type Kind = ArticleCollection;
type Error = Error; type Error = Error;
async fn read_local( async fn read_local(
_owner: &Self::Owner, _owner: &Self::Owner,
data: &Data<Self::DataType>, context: &Data<Self::DataType>,
) -> Result<Self::Kind, Self::Error> { ) -> Result<Self::Kind, Self::Error> {
let local_articles = DbArticle::read_all(Some(true), None, data)?; let local_articles = DbArticle::read_all(Some(true), None, context)?;
let articles = try_join_all( let articles = try_join_all(
local_articles local_articles
.into_iter() .into_iter()
.map(|a| a.into_json(data)) .map(|a| a.into_json(context))
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
) )
.await?; .await?;
let collection = ArticleCollection { let collection = ArticleCollection {
r#type: Default::default(), r#type: Default::default(),
id: local_articles_url(&data.config.federation.domain)?.into(), id: local_articles_url(&context.config.federation.domain)?.into(),
total_items: articles.len() as i32, total_items: articles.len() as i32,
items: articles, items: articles,
}; };
@ -68,7 +68,7 @@ impl Collection for DbArticleCollection {
async fn verify( async fn verify(
json: &Self::Kind, json: &Self::Kind,
expected_domain: &Url, expected_domain: &Url,
_data: &Data<Self::DataType>, _context: &Data<Self::DataType>,
) -> Result<(), Self::Error> { ) -> Result<(), Self::Error> {
verify_domains_match(&json.id, expected_domain)?; verify_domains_match(&json.id, expected_domain)?;
Ok(()) Ok(())
@ -77,20 +77,20 @@ impl Collection for DbArticleCollection {
async fn from_json( async fn from_json(
apub: Self::Kind, apub: Self::Kind,
_owner: &Self::Owner, _owner: &Self::Owner,
data: &Data<Self::DataType>, context: &Data<Self::DataType>,
) -> Result<Self, Self::Error> { ) -> Result<Self, Self::Error> {
let articles = let articles = apub
apub.items .items
.into_iter() .into_iter()
.filter(|i| !i.id.is_local(data)) .filter(|i| !i.id.is_local(context))
.map(|article| async { .map(|article| async {
let id = article.id.clone(); let id = article.id.clone();
let res = DbArticle::from_json(article, data).await; let res = DbArticle::from_json(article, context).await;
if let Err(e) = &res { if let Err(e) = &res {
warn!("Failed to synchronize article {id}: {e}"); warn!("Failed to synchronize article {id}: {e}");
} }
res res
}); });
join_all(articles).await; join_all(articles).await;
Ok(DbArticleCollection(())) Ok(DbArticleCollection(()))

View file

@ -1,7 +1,7 @@
use super::article_or_comment::DbArticleOrComment; use super::article_or_comment::DbArticleOrComment;
use crate::{ use crate::{
backend::{ backend::{
database::{comment::DbCommentInsertForm, IbisData}, database::{comment::DbCommentInsertForm, IbisContext},
utils::{error::Error, validate::validate_comment_max_depth}, utils::{error::Error, validate::validate_comment_max_depth},
}, },
common::{article::DbArticle, comment::DbComment, user::DbPerson}, common::{article::DbArticle, comment::DbComment, user::DbPerson},
@ -37,24 +37,24 @@ pub struct ApubComment {
#[async_trait::async_trait] #[async_trait::async_trait]
impl Object for DbComment { impl Object for DbComment {
type DataType = IbisData; type DataType = IbisContext;
type Kind = ApubComment; type Kind = ApubComment;
type Error = Error; type Error = Error;
async fn read_from_id( async fn read_from_id(
object_id: Url, object_id: Url,
data: &Data<Self::DataType>, context: &Data<Self::DataType>,
) -> Result<Option<Self>, Self::Error> { ) -> Result<Option<Self>, Self::Error> {
Ok(DbComment::read_from_ap_id(&object_id.into(), data).ok()) Ok(DbComment::read_from_ap_id(&object_id.into(), context).ok())
} }
async fn into_json(self, data: &Data<Self::DataType>) -> Result<Self::Kind, Self::Error> { async fn into_json(self, context: &Data<Self::DataType>) -> Result<Self::Kind, Self::Error> {
let creator = DbPerson::read(self.creator_id, data)?; let creator = DbPerson::read(self.creator_id, context)?;
let in_reply_to = if let Some(parent_comment_id) = self.parent_id { let in_reply_to = if let Some(parent_comment_id) = self.parent_id {
let comment = DbComment::read(parent_comment_id, data)?; let comment = DbComment::read(parent_comment_id, context)?;
comment.ap_id.into_inner().into() comment.ap_id.into_inner().into()
} else { } else {
let article = DbArticle::read(self.article_id, data)?; let article = DbArticle::read(self.article_id, context)?;
article.ap_id.into_inner().into() article.ap_id.into_inner().into()
}; };
Ok(ApubComment { Ok(ApubComment {
@ -72,15 +72,18 @@ impl Object for DbComment {
async fn verify( async fn verify(
json: &Self::Kind, json: &Self::Kind,
expected_domain: &Url, expected_domain: &Url,
data: &Data<Self::DataType>, context: &Data<Self::DataType>,
) -> Result<(), Self::Error> { ) -> Result<(), Self::Error> {
verify_domains_match(json.id.inner(), expected_domain)?; verify_domains_match(json.id.inner(), expected_domain)?;
verify_is_remote_object(&json.id, data)?; verify_is_remote_object(&json.id, context)?;
Ok(()) Ok(())
} }
async fn from_json(json: Self::Kind, data: &Data<Self::DataType>) -> Result<Self, Self::Error> { async fn from_json(
let parent = json.in_reply_to.dereference(data).await?; json: Self::Kind,
context: &Data<Self::DataType>,
) -> Result<Self, Self::Error> {
let parent = json.in_reply_to.dereference(context).await?;
let (article_id, parent_id, depth) = match parent { let (article_id, parent_id, depth) = match parent {
DbArticleOrComment::Article(db_article) => (db_article.id, None, 0), DbArticleOrComment::Article(db_article) => (db_article.id, None, 0),
DbArticleOrComment::Comment(db_comment) => ( DbArticleOrComment::Comment(db_comment) => (
@ -89,7 +92,7 @@ impl Object for DbComment {
db_comment.depth + 1, db_comment.depth + 1,
), ),
}; };
let creator = json.attributed_to.dereference(data).await?; let creator = json.attributed_to.dereference(context).await?;
validate_comment_max_depth(depth)?; validate_comment_max_depth(depth)?;
let form = DbCommentInsertForm { let form = DbCommentInsertForm {
@ -105,6 +108,6 @@ impl Object for DbComment {
depth, depth,
}; };
Ok(DbComment::create_or_update(form, data)?) Ok(DbComment::create_or_update(form, context)?)
} }
} }

View file

@ -1,6 +1,6 @@
use crate::{ use crate::{
backend::{ backend::{
database::{edit::DbEditForm, IbisData}, database::{edit::DbEditForm, IbisContext},
utils::error::Error, utils::error::Error,
}, },
common::{ common::{
@ -43,20 +43,20 @@ pub struct ApubEdit {
#[async_trait::async_trait] #[async_trait::async_trait]
impl Object for DbEdit { impl Object for DbEdit {
type DataType = IbisData; type DataType = IbisContext;
type Kind = ApubEdit; type Kind = ApubEdit;
type Error = Error; type Error = Error;
async fn read_from_id( async fn read_from_id(
object_id: Url, object_id: Url,
data: &Data<Self::DataType>, context: &Data<Self::DataType>,
) -> Result<Option<Self>, Self::Error> { ) -> Result<Option<Self>, Self::Error> {
Ok(DbEdit::read_from_ap_id(&object_id.into(), data).ok()) Ok(DbEdit::read_from_ap_id(&object_id.into(), context).ok())
} }
async fn into_json(self, data: &Data<Self::DataType>) -> Result<Self::Kind, Self::Error> { async fn into_json(self, context: &Data<Self::DataType>) -> Result<Self::Kind, Self::Error> {
let article = DbArticle::read_view(self.article_id, data)?; let article = DbArticle::read_view(self.article_id, context)?;
let creator = DbPerson::read(self.creator_id, data)?; let creator = DbPerson::read(self.creator_id, context)?;
Ok(ApubEdit { Ok(ApubEdit {
kind: PatchType::Patch, kind: PatchType::Patch,
id: self.ap_id, id: self.ap_id,
@ -73,21 +73,24 @@ impl Object for DbEdit {
async fn verify( async fn verify(
json: &Self::Kind, json: &Self::Kind,
expected_domain: &Url, expected_domain: &Url,
data: &Data<Self::DataType>, context: &Data<Self::DataType>,
) -> Result<(), Self::Error> { ) -> Result<(), Self::Error> {
verify_domains_match(json.id.inner(), expected_domain)?; verify_domains_match(json.id.inner(), expected_domain)?;
verify_is_remote_object(&json.id, data)?; verify_is_remote_object(&json.id, context)?;
Ok(()) Ok(())
} }
async fn from_json(json: Self::Kind, data: &Data<Self::DataType>) -> Result<Self, Self::Error> { async fn from_json(
let article = json.object.dereference(data).await?; json: Self::Kind,
let creator = match json.attributed_to.dereference(data).await { context: &Data<Self::DataType>,
) -> Result<Self, Self::Error> {
let article = json.object.dereference(context).await?;
let creator = match json.attributed_to.dereference(context).await {
Ok(c) => c, Ok(c) => c,
Err(e) => { Err(e) => {
// If actor couldnt be fetched, use ghost as placeholder // If actor couldnt be fetched, use ghost as placeholder
warn!("Failed to fetch user {}: {e}", json.attributed_to); warn!("Failed to fetch user {}: {e}", json.attributed_to);
DbPerson::ghost(data)? DbPerson::ghost(context)?
} }
}; };
let form = DbEditForm { let form = DbEditForm {
@ -101,7 +104,7 @@ impl Object for DbEdit {
published: json.published, published: json.published,
pending: false, pending: false,
}; };
let edit = DbEdit::create(&form, data)?; let edit = DbEdit::create(&form, context)?;
Ok(edit) Ok(edit)
} }
} }

View file

@ -1,5 +1,5 @@
use crate::{ use crate::{
backend::{database::IbisData, federation::objects::edit::ApubEdit, utils::error::Error}, backend::{database::IbisContext, federation::objects::edit::ApubEdit, utils::error::Error},
common::article::{DbArticle, DbEdit}, common::article::{DbArticle, DbEdit},
}; };
use activitypub_federation::{ use activitypub_federation::{
@ -28,20 +28,20 @@ pub struct DbEditCollection();
#[async_trait::async_trait] #[async_trait::async_trait]
impl Collection for DbEditCollection { impl Collection for DbEditCollection {
type Owner = DbArticle; type Owner = DbArticle;
type DataType = IbisData; type DataType = IbisContext;
type Kind = ApubEditCollection; type Kind = ApubEditCollection;
type Error = Error; type Error = Error;
async fn read_local( async fn read_local(
article: &Self::Owner, article: &Self::Owner,
data: &Data<Self::DataType>, context: &Data<Self::DataType>,
) -> Result<Self::Kind, Self::Error> { ) -> Result<Self::Kind, Self::Error> {
let article = DbArticle::read(article.id, data)?; let article = DbArticle::read(article.id, context)?;
let edits = DbEdit::list_for_article(article.id, data)?; let edits = DbEdit::list_for_article(article.id, context)?;
let edits = future::try_join_all( let edits = future::try_join_all(
edits edits
.into_iter() .into_iter()
.map(|e| e.into_json(data)) .map(|e| e.into_json(context))
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
) )
.await?; .await?;
@ -57,7 +57,7 @@ impl Collection for DbEditCollection {
async fn verify( async fn verify(
json: &Self::Kind, json: &Self::Kind,
expected_domain: &Url, expected_domain: &Url,
_data: &Data<Self::DataType>, _context: &Data<Self::DataType>,
) -> Result<(), Self::Error> { ) -> Result<(), Self::Error> {
verify_domains_match(&json.id, expected_domain)?; verify_domains_match(&json.id, expected_domain)?;
Ok(()) Ok(())
@ -66,12 +66,16 @@ impl Collection for DbEditCollection {
async fn from_json( async fn from_json(
apub: Self::Kind, apub: Self::Kind,
owner: &Self::Owner, owner: &Self::Owner,
data: &Data<Self::DataType>, context: &Data<Self::DataType>,
) -> Result<Self, Self::Error> { ) -> Result<Self, Self::Error> {
try_join_all(apub.items.into_iter().map(|i| DbEdit::from_json(i, data))) try_join_all(
.await apub.items
.map_err(|e| warn!("Failed to synchronize edits for {}: {e}", owner.ap_id)) .into_iter()
.ok(); .map(|i| DbEdit::from_json(i, context)),
)
.await
.map_err(|e| warn!("Failed to synchronize edits for {}: {e}", owner.ap_id))
.ok();
Ok(DbEditCollection()) Ok(DbEditCollection())
} }
} }

View file

@ -1,7 +1,7 @@
use super::instance_collection::DbInstanceCollection; use super::instance_collection::DbInstanceCollection;
use crate::{ use crate::{
backend::{ backend::{
database::{instance::DbInstanceForm, IbisData}, database::{instance::DbInstanceForm, IbisContext},
federation::{objects::articles_collection::DbArticleCollection, send_activity}, federation::{objects::articles_collection::DbArticleCollection, send_activity},
utils::error::{Error, MyResult}, utils::error::{Error, MyResult},
}, },
@ -40,8 +40,8 @@ impl DbInstance {
Ok(Url::parse(&format!("{}/followers", self.ap_id.inner()))?) Ok(Url::parse(&format!("{}/followers", self.ap_id.inner()))?)
} }
pub fn follower_ids(&self, data: &Data<IbisData>) -> MyResult<Vec<Url>> { pub fn follower_ids(&self, context: &Data<IbisContext>) -> MyResult<Vec<Url>> {
Ok(DbInstance::read_followers(self.id, data)? Ok(DbInstance::read_followers(self.id, context)?
.into_iter() .into_iter()
.map(|f| f.ap_id.into()) .map(|f| f.ap_id.into())
.collect()) .collect())
@ -51,26 +51,26 @@ impl DbInstance {
&self, &self,
activity: Activity, activity: Activity,
extra_recipients: Vec<DbInstance>, extra_recipients: Vec<DbInstance>,
data: &Data<IbisData>, context: &Data<IbisContext>,
) -> Result<(), <Activity as ActivityHandler>::Error> ) -> Result<(), <Activity as ActivityHandler>::Error>
where where
Activity: ActivityHandler + Serialize + Debug + Send + Sync, Activity: ActivityHandler + Serialize + Debug + Send + Sync,
<Activity as ActivityHandler>::Error: From<activitypub_federation::error::Error>, <Activity as ActivityHandler>::Error: From<activitypub_federation::error::Error>,
<Activity as ActivityHandler>::Error: From<Error>, <Activity as ActivityHandler>::Error: From<Error>,
{ {
let mut inboxes: Vec<_> = DbInstance::read_followers(self.id, data)? let mut inboxes: Vec<_> = DbInstance::read_followers(self.id, context)?
.iter() .iter()
.map(|f| f.inbox_url()) .map(|f| f.inbox_url())
.collect(); .collect();
inboxes.extend(extra_recipients.into_iter().map(|i| i.inbox_url())); inboxes.extend(extra_recipients.into_iter().map(|i| i.inbox_url()));
send_activity(self, activity, inboxes, data).await?; send_activity(self, activity, inboxes, context).await?;
Ok(()) Ok(())
} }
} }
#[async_trait::async_trait] #[async_trait::async_trait]
impl Object for DbInstance { impl Object for DbInstance {
type DataType = IbisData; type DataType = IbisContext;
type Kind = ApubInstance; type Kind = ApubInstance;
type Error = Error; type Error = Error;
@ -80,12 +80,12 @@ impl Object for DbInstance {
async fn read_from_id( async fn read_from_id(
object_id: Url, object_id: Url,
data: &Data<Self::DataType>, context: &Data<Self::DataType>,
) -> Result<Option<Self>, Self::Error> { ) -> Result<Option<Self>, Self::Error> {
Ok(DbInstance::read_from_ap_id(&object_id.into(), data).ok()) Ok(DbInstance::read_from_ap_id(&object_id.into(), context).ok())
} }
async fn into_json(self, _data: &Data<Self::DataType>) -> Result<Self::Kind, Self::Error> { async fn into_json(self, _context: &Data<Self::DataType>) -> Result<Self::Kind, Self::Error> {
Ok(ApubInstance { Ok(ApubInstance {
kind: Default::default(), kind: Default::default(),
id: self.ap_id.clone(), id: self.ap_id.clone(),
@ -100,14 +100,17 @@ impl Object for DbInstance {
async fn verify( async fn verify(
json: &Self::Kind, json: &Self::Kind,
expected_domain: &Url, expected_domain: &Url,
data: &Data<Self::DataType>, context: &Data<Self::DataType>,
) -> Result<(), Self::Error> { ) -> Result<(), Self::Error> {
verify_domains_match(json.id.inner(), expected_domain)?; verify_domains_match(json.id.inner(), expected_domain)?;
verify_is_remote_object(&json.id, data)?; verify_is_remote_object(&json.id, context)?;
Ok(()) Ok(())
} }
async fn from_json(json: Self::Kind, data: &Data<Self::DataType>) -> Result<Self, Self::Error> { async fn from_json(
json: Self::Kind,
context: &Data<Self::DataType>,
) -> Result<Self, Self::Error> {
let domain = extract_domain(&json.id); let domain = extract_domain(&json.id);
let form = DbInstanceForm { let form = DbInstanceForm {
domain, domain,
@ -121,20 +124,20 @@ impl Object for DbInstance {
last_refreshed_at: Utc::now(), last_refreshed_at: Utc::now(),
local: false, local: false,
}; };
let instance = DbInstance::create(&form, data)?; let instance = DbInstance::create(&form, context)?;
// TODO: very inefficient to sync all articles every time // TODO: very inefficient to sync all articles every time
let instance_ = instance.clone(); let instance_ = instance.clone();
let data_ = data.reset_request_count(); let context_ = context.reset_request_count();
tokio::spawn(async move { tokio::spawn(async move {
if let Some(articles_url) = &instance_.articles_url { if let Some(articles_url) = &instance_.articles_url {
let res = articles_url.dereference(&(), &data_).await; let res = articles_url.dereference(&(), &context_).await;
if let Err(e) = res { if let Err(e) = res {
tracing::warn!("error in spawn: {e}"); tracing::warn!("error in spawn: {e}");
} }
} }
if let Some(instances_url) = &instance_.instances_url { if let Some(instances_url) = &instance_.instances_url {
let res = instances_url.dereference(&(), &data_).await; let res = instances_url.dereference(&(), &context_).await;
if let Err(e) = res { if let Err(e) = res {
tracing::warn!("error in spawn: {e}"); tracing::warn!("error in spawn: {e}");
} }

View file

@ -1,7 +1,7 @@
use super::instance::ApubInstance; use super::instance::ApubInstance;
use crate::{ use crate::{
backend::{ backend::{
database::IbisData, database::IbisContext,
utils::error::{Error, MyResult}, utils::error::{Error, MyResult},
}, },
common::{instance::DbInstance, utils::http_protocol_str}, common::{instance::DbInstance, utils::http_protocol_str},
@ -40,25 +40,25 @@ pub fn linked_instances_url(domain: &str) -> MyResult<CollectionId<DbInstanceCol
#[async_trait::async_trait] #[async_trait::async_trait]
impl Collection for DbInstanceCollection { impl Collection for DbInstanceCollection {
type Owner = (); type Owner = ();
type DataType = IbisData; type DataType = IbisContext;
type Kind = InstanceCollection; type Kind = InstanceCollection;
type Error = Error; type Error = Error;
async fn read_local( async fn read_local(
_owner: &Self::Owner, _owner: &Self::Owner,
data: &Data<Self::DataType>, context: &Data<Self::DataType>,
) -> Result<Self::Kind, Self::Error> { ) -> Result<Self::Kind, Self::Error> {
let instances = DbInstance::read_remote(data)?; let instances = DbInstance::read_remote(context)?;
let instances = future::try_join_all( let instances = future::try_join_all(
instances instances
.into_iter() .into_iter()
.map(|i| i.into_json(data)) .map(|i| i.into_json(context))
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
) )
.await?; .await?;
let collection = InstanceCollection { let collection = InstanceCollection {
r#type: Default::default(), r#type: Default::default(),
id: linked_instances_url(&data.config.federation.domain)?.into(), id: linked_instances_url(&context.config.federation.domain)?.into(),
total_items: instances.len() as i32, total_items: instances.len() as i32,
items: instances, items: instances,
}; };
@ -68,7 +68,7 @@ impl Collection for DbInstanceCollection {
async fn verify( async fn verify(
json: &Self::Kind, json: &Self::Kind,
expected_domain: &Url, expected_domain: &Url,
_data: &Data<Self::DataType>, _context: &Data<Self::DataType>,
) -> Result<(), Self::Error> { ) -> Result<(), Self::Error> {
verify_domains_match(&json.id, expected_domain)?; verify_domains_match(&json.id, expected_domain)?;
Ok(()) Ok(())
@ -77,20 +77,20 @@ impl Collection for DbInstanceCollection {
async fn from_json( async fn from_json(
apub: Self::Kind, apub: Self::Kind,
_owner: &Self::Owner, _owner: &Self::Owner,
data: &Data<Self::DataType>, context: &Data<Self::DataType>,
) -> Result<Self, Self::Error> { ) -> Result<Self, Self::Error> {
let instances = let instances = apub
apub.items .items
.into_iter() .into_iter()
.filter(|i| !i.id.is_local(data)) .filter(|i| !i.id.is_local(context))
.map(|instance| async { .map(|instance| async {
let id = instance.id.clone(); let id = instance.id.clone();
let res = DbInstance::from_json(instance, data).await; let res = DbInstance::from_json(instance, context).await;
if let Err(e) = &res { if let Err(e) = &res {
warn!("Failed to synchronize article {id}: {e}"); warn!("Failed to synchronize article {id}: {e}");
} }
res res
}); });
join_all(instances).await; join_all(instances).await;
Ok(DbInstanceCollection(())) Ok(DbInstanceCollection(()))

View file

@ -1,6 +1,6 @@
use crate::{ use crate::{
backend::{ backend::{
database::{user::DbPersonForm, IbisData}, database::{user::DbPersonForm, IbisContext},
utils::error::Error, utils::error::Error,
}, },
common::user::DbPerson, common::user::DbPerson,
@ -33,7 +33,7 @@ pub struct ApubUser {
#[async_trait::async_trait] #[async_trait::async_trait]
impl Object for DbPerson { impl Object for DbPerson {
type DataType = IbisData; type DataType = IbisContext;
type Kind = ApubUser; type Kind = ApubUser;
type Error = Error; type Error = Error;
@ -43,12 +43,12 @@ impl Object for DbPerson {
async fn read_from_id( async fn read_from_id(
object_id: Url, object_id: Url,
data: &Data<Self::DataType>, context: &Data<Self::DataType>,
) -> Result<Option<Self>, Self::Error> { ) -> Result<Option<Self>, Self::Error> {
Ok(DbPerson::read_from_ap_id(&object_id.into(), data).ok()) Ok(DbPerson::read_from_ap_id(&object_id.into(), context).ok())
} }
async fn into_json(self, _data: &Data<Self::DataType>) -> Result<Self::Kind, Self::Error> { async fn into_json(self, _context: &Data<Self::DataType>) -> Result<Self::Kind, Self::Error> {
Ok(ApubUser { Ok(ApubUser {
kind: Default::default(), kind: Default::default(),
id: __self.ap_id.clone(), id: __self.ap_id.clone(),
@ -63,13 +63,16 @@ impl Object for DbPerson {
async fn verify( async fn verify(
json: &Self::Kind, json: &Self::Kind,
expected_domain: &Url, expected_domain: &Url,
_data: &Data<Self::DataType>, _context: &Data<Self::DataType>,
) -> Result<(), Self::Error> { ) -> Result<(), Self::Error> {
verify_domains_match(json.id.inner(), expected_domain)?; verify_domains_match(json.id.inner(), expected_domain)?;
Ok(()) Ok(())
} }
async fn from_json(json: Self::Kind, data: &Data<Self::DataType>) -> Result<Self, Self::Error> { async fn from_json(
json: Self::Kind,
context: &Data<Self::DataType>,
) -> Result<Self, Self::Error> {
let form = DbPersonForm { let form = DbPersonForm {
username: json.preferred_username, username: json.preferred_username,
ap_id: json.id, ap_id: json.id,
@ -81,7 +84,7 @@ impl Object for DbPerson {
display_name: json.name, display_name: json.name,
bio: json.summary, bio: json.summary,
}; };
DbPerson::create(&form, data) DbPerson::create(&form, context)
} }
} }

View file

@ -11,7 +11,7 @@ use super::{
}; };
use crate::{ use crate::{
backend::{ backend::{
database::IbisData, database::IbisContext,
federation::{ federation::{
activities::{ activities::{
accept::Accept, accept::Accept,
@ -74,66 +74,66 @@ pub fn federation_routes() -> Router<()> {
#[debug_handler] #[debug_handler]
async fn http_get_instance( async fn http_get_instance(
data: Data<IbisData>, context: Data<IbisContext>,
) -> MyResult<FederationJson<WithContext<ApubInstance>>> { ) -> MyResult<FederationJson<WithContext<ApubInstance>>> {
let local_instance = DbInstance::read_local(&data)?; let local_instance = DbInstance::read_local(&context)?;
let json_instance = local_instance.into_json(&data).await?; let json_instance = local_instance.into_json(&context).await?;
Ok(FederationJson(WithContext::new_default(json_instance))) Ok(FederationJson(WithContext::new_default(json_instance)))
} }
#[debug_handler] #[debug_handler]
async fn http_get_person( async fn http_get_person(
Path(name): Path<String>, Path(name): Path<String>,
data: Data<IbisData>, context: Data<IbisContext>,
) -> MyResult<FederationJson<WithContext<ApubUser>>> { ) -> MyResult<FederationJson<WithContext<ApubUser>>> {
let person = DbPerson::read_local_from_name(&name, &data)?.person; let person = DbPerson::read_local_from_name(&name, &context)?.person;
let json_person = person.into_json(&data).await?; let json_person = person.into_json(&context).await?;
Ok(FederationJson(WithContext::new_default(json_person))) Ok(FederationJson(WithContext::new_default(json_person)))
} }
#[debug_handler] #[debug_handler]
async fn http_get_all_articles( async fn http_get_all_articles(
data: Data<IbisData>, context: Data<IbisContext>,
) -> MyResult<FederationJson<WithContext<ArticleCollection>>> { ) -> MyResult<FederationJson<WithContext<ArticleCollection>>> {
let collection = DbArticleCollection::read_local(&(), &data).await?; let collection = DbArticleCollection::read_local(&(), &context).await?;
Ok(FederationJson(WithContext::new_default(collection))) Ok(FederationJson(WithContext::new_default(collection)))
} }
#[debug_handler] #[debug_handler]
async fn http_get_linked_instances( async fn http_get_linked_instances(
data: Data<IbisData>, context: Data<IbisContext>,
) -> MyResult<FederationJson<WithContext<InstanceCollection>>> { ) -> MyResult<FederationJson<WithContext<InstanceCollection>>> {
let collection = DbInstanceCollection::read_local(&(), &data).await?; let collection = DbInstanceCollection::read_local(&(), &context).await?;
Ok(FederationJson(WithContext::new_default(collection))) Ok(FederationJson(WithContext::new_default(collection)))
} }
#[debug_handler] #[debug_handler]
async fn http_get_article( async fn http_get_article(
Path(title): Path<String>, Path(title): Path<String>,
data: Data<IbisData>, context: Data<IbisContext>,
) -> MyResult<FederationJson<WithContext<ApubArticle>>> { ) -> MyResult<FederationJson<WithContext<ApubArticle>>> {
let article = DbArticle::read_view_title(&title, None, &data)?; let article = DbArticle::read_view_title(&title, None, &context)?;
let json = article.article.into_json(&data).await?; let json = article.article.into_json(&context).await?;
Ok(FederationJson(WithContext::new_default(json))) Ok(FederationJson(WithContext::new_default(json)))
} }
#[debug_handler] #[debug_handler]
async fn http_get_article_edits( async fn http_get_article_edits(
Path(title): Path<String>, Path(title): Path<String>,
data: Data<IbisData>, context: Data<IbisContext>,
) -> MyResult<FederationJson<WithContext<ApubEditCollection>>> { ) -> MyResult<FederationJson<WithContext<ApubEditCollection>>> {
let article = DbArticle::read_view_title(&title, None, &data)?; let article = DbArticle::read_view_title(&title, None, &context)?;
let json = DbEditCollection::read_local(&article.article, &data).await?; let json = DbEditCollection::read_local(&article.article, &context).await?;
Ok(FederationJson(WithContext::new_default(json))) Ok(FederationJson(WithContext::new_default(json)))
} }
#[debug_handler] #[debug_handler]
async fn http_get_comment( async fn http_get_comment(
Path(id): Path<i32>, Path(id): Path<i32>,
data: Data<IbisData>, context: Data<IbisContext>,
) -> MyResult<FederationJson<WithContext<ApubComment>>> { ) -> MyResult<FederationJson<WithContext<ApubComment>>> {
let comment = DbComment::read(CommentId(id), &data)?; let comment = DbComment::read(CommentId(id), &context)?;
let json = comment.into_json(&data).await?; let json = comment.into_json(&context).await?;
Ok(FederationJson(WithContext::new_default(json))) Ok(FederationJson(WithContext::new_default(json)))
} }
@ -163,10 +163,10 @@ pub enum AnnouncableActivities {
#[debug_handler] #[debug_handler]
pub async fn http_post_inbox( pub async fn http_post_inbox(
data: Data<IbisData>, context: Data<IbisContext>,
activity_data: ActivityData, activity_data: ActivityData,
) -> impl IntoResponse { ) -> impl IntoResponse {
receive_activity::<WithContext<InboxActivities>, UserOrInstance, IbisData>(activity_data, &data) receive_activity::<WithContext<InboxActivities>, UserOrInstance, _>(activity_data, &context)
.await .await
} }
@ -191,7 +191,7 @@ pub enum PersonOrInstanceType {
#[async_trait::async_trait] #[async_trait::async_trait]
impl Object for UserOrInstance { impl Object for UserOrInstance {
type DataType = IbisData; type DataType = IbisContext;
type Kind = PersonOrInstance; type Kind = PersonOrInstance;
type Error = Error; type Error = Error;

View file

@ -1,7 +1,7 @@
use crate::{ use crate::{
backend::{ backend::{
config::IbisConfig, config::IbisConfig,
database::{article::DbArticleForm, instance::DbInstanceForm, IbisData}, database::{article::DbArticleForm, instance::DbInstanceForm, IbisContext},
federation::{activities::submit_article_update, VerifyUrlData}, federation::{activities::submit_article_update, VerifyUrlData},
utils::{ utils::{
error::{Error, MyResult}, error::{Error, MyResult},
@ -59,11 +59,11 @@ pub async fn start(
.get()? .get()?
.run_pending_migrations(MIGRATIONS) .run_pending_migrations(MIGRATIONS)
.expect("run migrations"); .expect("run migrations");
let ibis_data = IbisData { db_pool, config }; let context = IbisContext { db_pool, config };
let data = FederationConfig::builder() let data = FederationConfig::builder()
.domain(ibis_data.config.federation.domain.clone()) .domain(context.config.federation.domain.clone())
.url_verifier(Box::new(VerifyUrlData(ibis_data.config.clone()))) .url_verifier(Box::new(VerifyUrlData(context.config.clone())))
.app_data(ibis_data) .app_data(context)
.http_fetch_limit(1000) .http_fetch_limit(1000)
.debug(cfg!(debug_assertions)) .debug(cfg!(debug_assertions))
.build() .build()
@ -89,8 +89,8 @@ const MAIN_PAGE_DEFAULT_TEXT: &str = "Welcome to Ibis, the federated Wikipedia a
This main page can only be edited by the admin. Use it as an introduction for new users, \ This main page can only be edited by the admin. Use it as an introduction for new users, \
and to list interesting articles."; and to list interesting articles.";
async fn setup(data: &Data<IbisData>) -> Result<(), Error> { async fn setup(context: &Data<IbisContext>) -> Result<(), Error> {
let domain = &data.config.federation.domain; let domain = &context.config.federation.domain;
let ap_id = ObjectId::parse(&format!("{}://{domain}", http_protocol_str()))?; let ap_id = ObjectId::parse(&format!("{}://{domain}", http_protocol_str()))?;
let inbox_url = format!("{}://{domain}/inbox", http_protocol_str()); let inbox_url = format!("{}://{domain}/inbox", http_protocol_str());
let keypair = generate_keypair()?; let keypair = generate_keypair()?;
@ -106,13 +106,13 @@ async fn setup(data: &Data<IbisData>) -> Result<(), Error> {
last_refreshed_at: Utc::now(), last_refreshed_at: Utc::now(),
local: true, local: true,
}; };
let instance = DbInstance::create(&form, data)?; let instance = DbInstance::create(&form, context)?;
let person = DbPerson::create_local( let person = DbPerson::create_local(
data.config.setup.admin_username.clone(), context.config.setup.admin_username.clone(),
data.config.setup.admin_password.clone(), context.config.setup.admin_password.clone(),
true, true,
data, context,
)?; )?;
// Create the main page which is shown by default // Create the main page which is shown by default
@ -128,7 +128,7 @@ async fn setup(data: &Data<IbisData>) -> Result<(), Error> {
protected: true, protected: true,
approved: true, approved: true,
}; };
let article = DbArticle::create(form, data)?; let article = DbArticle::create(form, context)?;
// also create an article so its included in most recently edited list // also create an article so its included in most recently edited list
submit_article_update( submit_article_update(
MAIN_PAGE_DEFAULT_TEXT.to_string(), MAIN_PAGE_DEFAULT_TEXT.to_string(),
@ -136,12 +136,12 @@ async fn setup(data: &Data<IbisData>) -> Result<(), Error> {
EditVersion::default(), EditVersion::default(),
&article, &article,
person.person.id, person.person.id,
data, context,
) )
.await?; .await?;
// create ghost user // create ghost user
DbPerson::ghost(data)?; DbPerson::ghost(context)?;
Ok(()) Ok(())
} }

View file

@ -1,5 +1,5 @@
use crate::{ use crate::{
backend::{api::user::validate, database::IbisData}, backend::{api::user::validate, database::IbisContext},
common::{Auth, AUTH_COOKIE}, common::{Auth, AUTH_COOKIE},
}; };
use axum::{body::Body, extract::State, http::Request, middleware::Next, response::Response}; use axum::{body::Body, extract::State, http::Request, middleware::Next, response::Response};
@ -14,7 +14,7 @@ pub(super) const FEDERATION_ROUTES_PREFIX: &str = "/federation_routes";
/// If user is authenticated sets extensions `Auth` and `LocalUserView`. /// If user is authenticated sets extensions `Auth` and `LocalUserView`.
#[debug_middleware] #[debug_middleware]
pub(super) async fn auth_middleware( pub(super) async fn auth_middleware(
State(data): State<Arc<IbisData>>, State(context): State<Arc<IbisContext>>,
mut request: Request<Body>, mut request: Request<Body>,
next: Next, next: Next,
) -> Response { ) -> Response {
@ -34,7 +34,7 @@ pub(super) async fn auth_middleware(
let auth: HashSet<_> = headers.chain(cookies).map(|s| s.to_string()).collect(); let auth: HashSet<_> = headers.chain(cookies).map(|s| s.to_string()).collect();
for auth in auth { for auth in auth {
if let Ok(local_user) = validate(&auth, &data).await { if let Ok(local_user) = validate(&auth, &context).await {
request.extensions_mut().insert(Auth(Some(auth))); request.extensions_mut().insert(Auth(Some(auth)));
request.extensions_mut().insert(local_user); request.extensions_mut().insert(local_user);
} }

View file

@ -1,4 +1,4 @@
use super::{database::IbisData, utils::error::MyResult}; use super::{database::IbisContext, utils::error::MyResult};
use crate::{ use crate::{
backend::{api::api_routes, federation::routes::federation_routes}, backend::{api::api_routes, federation::routes::federation_routes},
common::Auth, common::Auth,
@ -31,7 +31,7 @@ mod middleware;
mod nodeinfo; mod nodeinfo;
pub(super) async fn start_server( pub(super) async fn start_server(
data: FederationConfig<IbisData>, context: FederationConfig<IbisContext>,
override_hostname: Option<SocketAddr>, override_hostname: Option<SocketAddr>,
notify_start: Option<oneshot::Sender<()>>, notify_start: Option<oneshot::Sender<()>>,
) -> MyResult<()> { ) -> MyResult<()> {
@ -42,7 +42,7 @@ pub(super) async fn start_server(
} }
let routes = generate_route_list(App); let routes = generate_route_list(App);
let arc_data = Arc::new(data.deref().clone()); let arc_data = Arc::new(context.deref().clone());
let app = Router::new() let app = Router::new()
.leptos_routes_with_handler(routes, get(leptos_routes_handler)) .leptos_routes_with_handler(routes, get(leptos_routes_handler))
.fallback(file_and_error_handler) .fallback(file_and_error_handler)
@ -50,7 +50,7 @@ pub(super) async fn start_server(
.nest(FEDERATION_ROUTES_PREFIX, federation_routes()) .nest(FEDERATION_ROUTES_PREFIX, federation_routes())
.nest("/api/v1", api_routes()) .nest("/api/v1", api_routes())
.nest("", nodeinfo::config()) .nest("", nodeinfo::config())
.layer(FederationMiddleware::new(data)) .layer(FederationMiddleware::new(context))
.layer(CorsLayer::permissive()) .layer(CorsLayer::permissive())
.layer(CompressionLayer::new()) .layer(CompressionLayer::new())
.route_layer(from_fn_with_state(arc_data, auth_middleware)); .route_layer(from_fn_with_state(arc_data, auth_middleware));

View file

@ -1,6 +1,6 @@
use crate::{ use crate::{
backend::{ backend::{
database::{instance_stats::InstanceStats, IbisData}, database::{instance_stats::InstanceStats, IbisContext},
utils::error::MyResult, utils::error::MyResult,
}, },
common::utils::http_protocol_str, common::utils::http_protocol_str,
@ -16,21 +16,21 @@ pub fn config() -> Router<()> {
.route("/.well-known/nodeinfo", get(node_info_well_known)) .route("/.well-known/nodeinfo", get(node_info_well_known))
} }
async fn node_info_well_known(data: Data<IbisData>) -> MyResult<Json<NodeInfoWellKnown>> { async fn node_info_well_known(context: Data<IbisContext>) -> MyResult<Json<NodeInfoWellKnown>> {
Ok(Json(NodeInfoWellKnown { Ok(Json(NodeInfoWellKnown {
links: vec![NodeInfoWellKnownLinks { links: vec![NodeInfoWellKnownLinks {
rel: Url::parse("http://nodeinfo.diaspora.software/ns/schema/2.1")?, rel: Url::parse("http://nodeinfo.diaspora.software/ns/schema/2.1")?,
href: Url::parse(&format!( href: Url::parse(&format!(
"{}://{}/nodeinfo/2.1.json", "{}://{}/nodeinfo/2.1.json",
http_protocol_str(), http_protocol_str(),
data.domain() context.domain()
))?, ))?,
}], }],
})) }))
} }
async fn node_info(data: Data<IbisData>) -> MyResult<Json<NodeInfo>> { async fn node_info(context: Data<IbisContext>) -> MyResult<Json<NodeInfo>> {
let stats = InstanceStats::read(&data)?; let stats = InstanceStats::read(&context)?;
Ok(Json(NodeInfo { Ok(Json(NodeInfo {
version: "2.1".to_string(), version: "2.1".to_string(),
software: NodeInfoSoftware { software: NodeInfoSoftware {
@ -49,7 +49,7 @@ async fn node_info(data: Data<IbisData>) -> MyResult<Json<NodeInfo>> {
local_posts: stats.articles, local_posts: stats.articles,
local_comments: stats.comments, local_comments: stats.comments,
}, },
open_registrations: data.config.options.registration_open, open_registrations: context.config.options.registration_open,
services: Default::default(), services: Default::default(),
metadata: vec![], metadata: vec![],
})) }))

View file

@ -1,5 +1,5 @@
use crate::{ use crate::{
backend::{database::IbisData, utils::error::MyResult}, backend::{database::IbisContext, utils::error::MyResult},
common::{ common::{
article::{DbEdit, EditVersion}, article::{DbEdit, EditVersion},
utils, utils,
@ -19,8 +19,8 @@ pub mod error;
pub(super) mod scheduled_tasks; pub(super) mod scheduled_tasks;
pub(super) mod validate; pub(super) mod validate;
pub(super) fn generate_activity_id(data: &Data<IbisData>) -> Result<Url, ParseError> { pub(super) fn generate_activity_id(context: &Data<IbisContext>) -> Result<Url, ParseError> {
let domain = &data.config.federation.domain; let domain = &context.config.federation.domain;
let id: String = thread_rng() let id: String = thread_rng()
.sample_iter(&Alphanumeric) .sample_iter(&Alphanumeric)
.take(7) .take(7)