1
0
Fork 0
mirror of https://github.com/Nutomic/ibis.git synced 2024-11-21 19:31:09 +00:00

various changes

- only admin can edit main page
- adjust config values
- better text for default page
This commit is contained in:
Felix Ableitner 2024-02-08 12:20:01 +01:00
parent 0c45fe3eba
commit 0f0f83bc3a
15 changed files with 57 additions and 32 deletions

View file

@ -1,3 +1,3 @@
[setup]
admin_username = "ibis"
admin_password = "ibis"
[federation]
# necessary for auth cookie to work
domain = "127.0.0.1:8080"

View file

@ -9,8 +9,8 @@ registration_open = true
# Details of the initial admin account
[setup]
admin_username = "admin"
admin_password = "hunter2"
admin_username = "ibis"
admin_password = "ibis"
[federation]
# Domain name of the instance, mandatory for federation

View file

@ -6,12 +6,13 @@ use crate::backend::error::MyResult;
use crate::backend::federation::activities::create_article::CreateArticle;
use crate::backend::federation::activities::submit_article_update;
use crate::backend::utils::generate_article_version;
use crate::common::validation::can_edit_article;
use crate::common::LocalUserView;
use crate::common::{ApiConflict, ResolveObject};
use crate::common::{ArticleView, DbArticle, DbEdit};
use crate::common::{CreateArticleData, EditArticleData, EditVersion, ForkArticleData};
use crate::common::{DbInstance, SearchArticleData};
use crate::common::{GetArticleData, ListArticlesData};
use crate::common::{LocalUserView, MAIN_PAGE_NAME};
use activitypub_federation::config::Data;
use activitypub_federation::fetch::object_id::ObjectId;
use anyhow::anyhow;
@ -91,12 +92,7 @@ pub(in crate::backend::api) async fn edit_article(
if edit_form.summary.is_empty() {
return Err(anyhow!("No summary given").into());
}
if original_article.article.local
&& original_article.article.title == MAIN_PAGE_NAME
&& !user.local_user.admin
{
return Err(anyhow!("Only admin can edit main page").into());
}
can_edit_article(&original_article.article, user.local_user.admin)?;
// ensure trailing newline for clean diffs
if !edit_form.new_text.ends_with('\n') {
edit_form.new_text.push('\n');

View file

@ -26,9 +26,11 @@ pub struct IbisConfig {
#[derive(Debug, Deserialize, PartialEq, Eq, Clone, Document, SmartDefault)]
#[serde(default)]
pub struct IbisConfigSetup {
#[doku(example = "admin")]
#[default("ibis")]
#[doku(example = "ibis")]
pub admin_username: String,
#[doku(example = "hunter2")]
#[default("ibis")]
#[doku(example = "ibis")]
pub admin_password: String,
}

View file

@ -1,6 +1,6 @@
use crate::backend::config::IbisConfig;
use crate::backend::database::schema::jwt_secret;
use crate::backend::error::MyResult;
use crate::config::IbisConfig;
use diesel::PgConnection;
use diesel::{QueryDsl, RunQueryDsl};
use std::ops::Deref;

View file

@ -12,6 +12,7 @@ use activitypub_federation::{
traits::{ActivityHandler, Object},
};
use crate::common::validation::can_edit_article;
use crate::common::DbArticle;
use serde::{Deserialize, Serialize};
use url::Url;
@ -67,7 +68,9 @@ impl ActivityHandler for UpdateLocalArticle {
self.actor.inner()
}
async fn verify(&self, _data: &Data<Self::DataType>) -> Result<(), Self::Error> {
async fn verify(&self, data: &Data<Self::DataType>) -> Result<(), Self::Error> {
let article = DbArticle::read_from_ap_id(&self.object.id, &data.db_connection)?;
can_edit_article(&article, false)?;
Ok(())
}

View file

@ -1,5 +1,5 @@
use crate::backend::config::IbisConfig;
use crate::backend::database::IbisData;
use crate::config::IbisConfig;
use activitypub_federation::activity_sending::SendActivityTask;
use activitypub_federation::config::{Data, UrlVerifier};
use activitypub_federation::error::Error as ActivityPubError;

View file

@ -1,3 +1,4 @@
use crate::backend::config::IbisConfig;
use crate::backend::database::article::DbArticleForm;
use crate::backend::database::instance::DbInstanceForm;
use crate::backend::database::IbisData;
@ -7,7 +8,6 @@ use crate::backend::federation::routes::federation_routes;
use crate::backend::federation::VerifyUrlData;
use crate::backend::utils::generate_activity_id;
use crate::common::{DbArticle, DbInstance, DbPerson, MAIN_PAGE_NAME};
use crate::config::IbisConfig;
use crate::frontend::app::App;
use activitypub_federation::config::{FederationConfig, FederationMiddleware};
use activitypub_federation::fetch::collection_id::CollectionId;
@ -33,6 +33,7 @@ use tower_http::cors::CorsLayer;
use tower_http::services::{ServeDir, ServeFile};
pub mod api;
pub mod config;
pub mod database;
pub mod error;
pub mod federation;
@ -103,6 +104,11 @@ pub async fn start(config: IbisConfig) -> MyResult<()> {
Ok(())
}
const MAIN_PAGE_DEFAULT_TEXT: &str = "Welcome to Ibis, the federated Wikipedia alternative!
This main page can only be edited by the admin. Use it as an introduction for new users, \
and to list interesting articles.";
fn setup(data: &IbisData) -> Result<(), Error> {
let domain = &data.config.federation.domain;
let ap_id = ObjectId::parse(&format!("http://{domain}"))?;
@ -124,7 +130,7 @@ fn setup(data: &IbisData) -> Result<(), Error> {
// Create the main page which is shown by default
let form = DbArticleForm {
title: MAIN_PAGE_NAME.to_string(),
text: "Hello world!".to_string(),
text: MAIN_PAGE_DEFAULT_TEXT.to_string(),
ap_id: ObjectId::parse(&format!("http://{domain}/article/{MAIN_PAGE_NAME}"))?,
instance_id: instance.id,
local: true,

View file

@ -8,14 +8,17 @@ use rand::{distributions::Alphanumeric, thread_rng, Rng};
use url::{ParseError, Url};
pub fn generate_activity_id(domain: &Url) -> Result<Url, ParseError> {
let port = domain.port().unwrap();
let port = match domain.port() {
Some(p) => format!(":{p}"),
None => String::new(),
};
let domain = domain.host_str().unwrap();
let id: String = thread_rng()
.sample_iter(&Alphanumeric)
.take(7)
.map(char::from)
.collect();
Url::parse(&format!("http://{}:{}/objects/{}", domain, port, id))
Url::parse(&format!("http://{}{}/objects/{}", domain, port, id))
}
/// Starting from empty string, apply edits until the specified version is reached. If no version is

View file

@ -1,3 +1,5 @@
pub mod validation;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};

10
src/common/validation.rs Normal file
View file

@ -0,0 +1,10 @@
use crate::common::{DbArticle, MAIN_PAGE_NAME};
use anyhow::anyhow;
use anyhow::Result;
pub fn can_edit_article(article: &DbArticle, is_admin: bool) -> Result<()> {
if article.local && article.title == MAIN_PAGE_NAME && !is_admin {
return Err(anyhow!("Only admin can edit main page"));
}
Ok(())
}

View file

@ -1,3 +1,4 @@
use crate::common::validation::can_edit_article;
use crate::common::ArticleView;
use crate::frontend::app::GlobalState;
use leptos::*;
@ -9,15 +10,18 @@ pub fn ArticleNav(article: Resource<Option<String>, ArticleView>) -> impl IntoVi
view! {
<Suspense>
{move || article.get().map(|article| {
let title = article.article.title;
let title = article.article.title.clone();
view!{
<nav class="inner">
<A href={format!("/article/{title}")}>"Read"</A>
<A href={format!("/article/{title}/history")}>"History"</A>
<Show when=move || global_state.with(|state| state.my_profile.is_some())>
<A href={format!("/article/{title}/edit")}>"Edit"</A>
</Show>
</nav>
<nav class="inner">
<A href={format!("/article/{title}")}>"Read"</A>
<A href={format!("/article/{title}/history")}>"History"</A>
<Show when=move || global_state.with(|state| {
let is_admin = state.my_profile.as_ref().map(|p| p.local_user.admin).unwrap_or(false);
state.my_profile.is_some() && can_edit_article(&article.article, is_admin).is_ok()
})>
<A href={format!("/article/{title}/edit")}>"Edit"</A>
</Show>
</nav>
}})}
</Suspense>
}

View file

@ -1,5 +1,4 @@
#[cfg(feature = "ssr")]
pub mod backend;
pub mod common;
pub mod config;
pub mod frontend;

View file

@ -2,7 +2,7 @@
#[tokio::main]
pub async fn main() -> ibis_lib::backend::error::MyResult<()> {
use config::Config;
use ibis_lib::config::IbisConfig;
use ibis_lib::backend::config::IbisConfig;
use log::LevelFilter;
if std::env::args().collect::<Vec<_>>().get(1) == Some(&"--print-config".to_string()) {

View file

@ -1,6 +1,6 @@
use ibis_lib::backend::config::{IbisConfig, IbisConfigFederation};
use ibis_lib::backend::start;
use ibis_lib::common::RegisterUserData;
use ibis_lib::config::{IbisConfig, IbisConfigFederation};
use ibis_lib::frontend::api::ApiClient;
use ibis_lib::frontend::error::MyResult;
use reqwest::ClientBuilder;