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:
parent
0c45fe3eba
commit
0f0f83bc3a
15 changed files with 57 additions and 32 deletions
|
@ -1,3 +1,3 @@
|
|||
[setup]
|
||||
admin_username = "ibis"
|
||||
admin_password = "ibis"
|
||||
[federation]
|
||||
# necessary for auth cookie to work
|
||||
domain = "127.0.0.1:8080"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
@ -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(())
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
10
src/common/validation.rs
Normal 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(())
|
||||
}
|
|
@ -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>
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
#[cfg(feature = "ssr")]
|
||||
pub mod backend;
|
||||
pub mod common;
|
||||
pub mod config;
|
||||
pub mod frontend;
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue