1
0
Fork 0
mirror of https://github.com/Nutomic/ibis.git synced 2024-11-22 12:01:08 +00:00

Simplify code so that unapproved articles can be viewed directly (but not included in listings)

This commit is contained in:
Felix Ableitner 2024-11-13 11:07:28 +01:00
parent 733abdef96
commit 18d46d22bf
8 changed files with 20 additions and 48 deletions

View file

@ -1,4 +1,4 @@
use super::{check_is_admin, is_admin_opt}; use super::check_is_admin;
use crate::{ use crate::{
backend::{ backend::{
database::{ database::{
@ -42,7 +42,7 @@ use diffy::create_patch;
/// Create a new article with empty text, and federate it to followers. /// Create a new article with empty text, and federate it to followers.
#[debug_handler] #[debug_handler]
pub(in crate::backend::api) async fn create_article( pub(in crate::backend::api) async fn create_article(
Extension(mut user): Extension<LocalUserView>, user: Extension<LocalUserView>,
data: Data<IbisData>, data: Data<IbisData>,
Form(create_article): Form<CreateArticleForm>, Form(create_article): Form<CreateArticleForm>,
) -> MyResult<Json<ArticleView>> { ) -> MyResult<Json<ArticleView>> {
@ -80,12 +80,10 @@ pub(in crate::backend::api) async fn create_article(
resolve_conflict_id: None, resolve_conflict_id: None,
}; };
// workaround so the edit goes through let _ = edit_article(user, data.reset_request_count(), Form(edit_data)).await?;
user.local_user.admin = true;
let _ = edit_article(Extension(user), data.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, true, &data)?; let article_view = DbArticle::read_view(article.id, &data)?;
CreateArticle::send_to_followers(article_view.article.clone(), &data).await?; CreateArticle::send_to_followers(article_view.article.clone(), &data).await?;
Ok(Json(article_view)) Ok(Json(article_view))
@ -106,12 +104,11 @@ pub(in crate::backend::api) async fn edit_article(
data: Data<IbisData>, data: Data<IbisData>,
Form(mut edit_form): Form<EditArticleForm>, Form(mut edit_form): Form<EditArticleForm>,
) -> MyResult<Json<Option<ApiConflict>>> { ) -> MyResult<Json<Option<ApiConflict>>> {
let is_admin = check_is_admin(&user).is_ok();
// resolve conflict if any // resolve conflict if any
if let Some(resolve_conflict_id) = edit_form.resolve_conflict_id { if let Some(resolve_conflict_id) = edit_form.resolve_conflict_id {
DbConflict::delete(resolve_conflict_id, &data)?; DbConflict::delete(resolve_conflict_id, &data)?;
} }
let original_article = DbArticle::read_view(edit_form.article_id, is_admin, &data)?; let original_article = DbArticle::read_view(edit_form.article_id, &data)?;
if edit_form.new_text == original_article.article.text { if edit_form.new_text == original_article.article.text {
return Err(anyhow!("Edit contains no changes").into()); return Err(anyhow!("Edit contains no changes").into());
} }
@ -153,7 +150,7 @@ pub(in crate::backend::api) async fn edit_article(
previous_version_id: previous_version.hash, previous_version_id: previous_version.hash,
}; };
let conflict = DbConflict::create(&form, &data)?; let conflict = DbConflict::create(&form, &data)?;
Ok(Json(conflict.to_api_conflict(is_admin, &data).await?)) Ok(Json(conflict.to_api_conflict(&data).await?))
} }
} }
@ -161,22 +158,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<GetArticleForm>, Query(query): Query<GetArticleForm>,
user: Option<Extension<LocalUserView>>,
data: Data<IbisData>, data: Data<IbisData>,
) -> MyResult<Json<ArticleView>> { ) -> MyResult<Json<ArticleView>> {
let is_admin = is_admin_opt(&user);
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,
is_admin,
&data, &data,
)?)), )?)),
(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, is_admin, &data)?; let article = DbArticle::read_view(id, &data)?;
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()),
@ -199,13 +193,12 @@ pub(in crate::backend::api) async fn list_articles(
/// how an article should be edited. /// how an article should be edited.
#[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>, data: Data<IbisData>,
Form(fork_form): Form<ForkArticleForm>, Form(fork_form): Form<ForkArticleForm>,
) -> MyResult<Json<ArticleView>> { ) -> MyResult<Json<ArticleView>> {
let is_admin = check_is_admin(&user).is_ok();
// 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(fork_form.article_id, is_admin, &data)?; let original_article = DbArticle::read_view(fork_form.article_id, &data)?;
let local_instance = DbInstance::read_local_instance(&data)?; let local_instance = DbInstance::read_local_instance(&data)?;
let ap_id = ObjectId::parse(&format!( let ap_id = ObjectId::parse(&format!(
@ -249,7 +242,7 @@ pub(in crate::backend::api) async fn fork_article(
CreateArticle::send_to_followers(article.clone(), &data).await?; CreateArticle::send_to_followers(article.clone(), &data).await?;
Ok(Json(DbArticle::read_view(article.id, is_admin, &data)?)) Ok(Json(DbArticle::read_view(article.id, &data)?))
} }
/// 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

View file

@ -36,7 +36,6 @@ use axum::{
middleware::{self, Next}, middleware::{self, Next},
response::Response, response::Response,
routing::{get, post}, routing::{get, post},
Extension,
Router, Router,
}; };
use axum_extra::extract::CookieJar; use axum_extra::extract::CookieJar;
@ -94,11 +93,3 @@ fn check_is_admin(user: &LocalUserView) -> MyResult<()> {
} }
Ok(()) Ok(())
} }
fn is_admin_opt(user: &Option<Extension<LocalUserView>>) -> bool {
if let Some(user) = user {
user.local_user.admin
} else {
false
}
}

View file

@ -161,11 +161,10 @@ pub(crate) async fn list_notifications(
Extension(user): Extension<LocalUserView>, Extension(user): Extension<LocalUserView>,
data: Data<IbisData>, data: Data<IbisData>,
) -> MyResult<Json<Vec<Notification>>> { ) -> MyResult<Json<Vec<Notification>>> {
let is_admin = check_is_admin(&user).is_ok();
let conflicts = DbConflict::list(&user.person, &data)?; let conflicts = DbConflict::list(&user.person, &data)?;
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 = data.reset_request_count();
async move { c.to_api_conflict(is_admin, &data).await } async move { c.to_api_conflict(&data).await }
})) }))
.await?; .await?;
let mut notifications: Vec<_> = conflicts let mut notifications: Vec<_> = conflicts

View file

@ -87,12 +87,9 @@ impl DbArticle {
.get_result::<Self>(conn.deref_mut())?) .get_result::<Self>(conn.deref_mut())?)
} }
pub fn read_view(id: ArticleId, is_admin: bool, data: &IbisData) -> MyResult<ArticleView> { pub fn read_view(id: ArticleId, data: &IbisData) -> MyResult<ArticleView> {
let mut conn = data.db_pool.get()?; let mut conn = data.db_pool.get()?;
let mut query = article::table.find(id).into_boxed(); let query = article::table.find(id).into_boxed();
if !is_admin {
query = query.filter(article::dsl::approved.eq(true));
}
let article: DbArticle = query.get_result(conn.deref_mut())?; let article: DbArticle = query.get_result(conn.deref_mut())?;
let latest_version = article.latest_edit_version(data)?; let latest_version = article.latest_edit_version(data)?;
let edits = DbEdit::read_for_article(&article, data)?; let edits = DbEdit::read_for_article(&article, data)?;
@ -106,7 +103,6 @@ impl DbArticle {
pub fn read_view_title( pub fn read_view_title(
title: &str, title: &str,
domain: Option<String>, domain: Option<String>,
admin: bool,
data: &IbisData, data: &IbisData,
) -> MyResult<ArticleView> { ) -> MyResult<ArticleView> {
let mut conn = data.db_pool.get()?; let mut conn = data.db_pool.get()?;
@ -115,14 +111,11 @@ impl DbArticle {
.inner_join(instance::table) .inner_join(instance::table)
.filter(article::dsl::title.eq(title)) .filter(article::dsl::title.eq(title))
.into_boxed(); .into_boxed();
let mut query = if let Some(domain) = domain { let query = if let Some(domain) = domain {
query.filter(instance::dsl::domain.eq(domain)) query.filter(instance::dsl::domain.eq(domain))
} else { } else {
query.filter(article::dsl::local.eq(true)) query.filter(article::dsl::local.eq(true))
}; };
if !admin {
query = query.filter(article::dsl::approved.eq(true));
}
query query
.select(article::all_columns) .select(article::all_columns)
.get_result(conn.deref_mut())? .get_result(conn.deref_mut())?

View file

@ -78,12 +78,8 @@ impl DbConflict {
Ok(delete(conflict::table.find(id)).get_result(conn.deref_mut())?) Ok(delete(conflict::table.find(id)).get_result(conn.deref_mut())?)
} }
pub async fn to_api_conflict( pub async fn to_api_conflict(&self, data: &Data<IbisData>) -> MyResult<Option<ApiConflict>> {
&self, let article = DbArticle::read_view(self.article_id, data)?;
is_admin: bool,
data: &Data<IbisData>,
) -> MyResult<Option<ApiConflict>> {
let article = DbArticle::read_view(self.article_id, is_admin, data)?;
// 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(data).await?;

View file

@ -52,7 +52,7 @@ impl Object for DbEdit {
} }
async fn into_json(self, data: &Data<Self::DataType>) -> Result<Self::Kind, Self::Error> { async fn into_json(self, data: &Data<Self::DataType>) -> Result<Self::Kind, Self::Error> {
let article = DbArticle::read_view(self.article_id, false, data)?; let article = DbArticle::read_view(self.article_id, data)?;
let creator = DbPerson::read(self.creator_id, data)?; let creator = DbPerson::read(self.creator_id, data)?;
Ok(ApubEdit { Ok(ApubEdit {
kind: PatchType::Patch, kind: PatchType::Patch,

View file

@ -35,7 +35,7 @@ impl Collection for DbEditCollection {
owner: &Self::Owner, owner: &Self::Owner,
data: &Data<Self::DataType>, data: &Data<Self::DataType>,
) -> Result<Self::Kind, Self::Error> { ) -> Result<Self::Kind, Self::Error> {
let article = DbArticle::read_view(owner.id, false, data)?; let article = DbArticle::read_view(owner.id, data)?;
let edits = future::try_join_all( let edits = future::try_join_all(
article article

View file

@ -94,7 +94,7 @@ async fn http_get_article(
Path(title): Path<String>, Path(title): Path<String>,
data: Data<IbisData>, data: Data<IbisData>,
) -> MyResult<FederationJson<WithContext<ApubArticle>>> { ) -> MyResult<FederationJson<WithContext<ApubArticle>>> {
let article = DbArticle::read_view_title(&title, None, false, &data)?; let article = DbArticle::read_view_title(&title, None, &data)?;
let json = article.article.into_json(&data).await?; let json = article.article.into_json(&data).await?;
Ok(FederationJson(WithContext::new_default(json))) Ok(FederationJson(WithContext::new_default(json)))
} }
@ -104,7 +104,7 @@ async fn http_get_article_edits(
Path(title): Path<String>, Path(title): Path<String>,
data: Data<IbisData>, data: Data<IbisData>,
) -> MyResult<FederationJson<WithContext<ApubEditCollection>>> { ) -> MyResult<FederationJson<WithContext<ApubEditCollection>>> {
let article = DbArticle::read_view_title(&title, None, false, &data)?; let article = DbArticle::read_view_title(&title, None, &data)?;
let json = DbEditCollection::read_local(&article.article, &data).await?; let json = DbEditCollection::read_local(&article.article, &data).await?;
Ok(FederationJson(WithContext::new_default(json))) Ok(FederationJson(WithContext::new_default(json)))
} }