Add some configuration options for instance admins

This commit is contained in:
Bat 2018-07-27 19:05:36 +02:00
parent 826772ca20
commit 74ec59e77c
21 changed files with 200 additions and 9 deletions

View file

@ -0,0 +1,5 @@
-- This file should undo anything in `up.sql`
ALTER TABLE instances DROP COLUMN open_registrations;
ALTER TABLE instances DROP COLUMN short_description;
ALTER TABLE instances DROP COLUMN long_description;
ALTER TABLE instances DROP COLUMN default_license;

View file

@ -0,0 +1,5 @@
-- Your SQL goes here
ALTER TABLE instances ADD COLUMN open_registrations BOOLEAN NOT NULL DEFAULT 't';
ALTER TABLE instances ADD COLUMN short_description TEXT NOT NULL DEFAULT '';
ALTER TABLE instances ADD COLUMN long_description TEXT NOT NULL DEFAULT '';
ALTER TABLE instances ADD COLUMN default_license TEXT NOT NULL DEFAULT 'CC-0';

19
plume-models/src/admin.rs Normal file
View file

@ -0,0 +1,19 @@
use rocket::{Outcome, http::Status, request::{self, FromRequest, Request}};
use users::User;
/// Wrapper around User to use as a request guard on pages reserved to admins.
pub struct Admin(pub User);
impl<'a, 'r> FromRequest<'a, 'r> for Admin {
type Error = ();
fn from_request(request: &'a Request<'r>) -> request::Outcome<Admin, ()> {
let user = request.guard::<User>()?;
if user.is_admin {
Outcome::Success(Admin(user))
} else {
Outcome::Failure((Status::Unauthorized, ()))
}
}
}

View file

@ -140,7 +140,12 @@ impl Blog {
Instance::insert(conn, NewInstance { Instance::insert(conn, NewInstance {
public_domain: inst.clone(), public_domain: inst.clone(),
name: inst.clone(), name: inst.clone(),
local: false local: false,
// We don't really care about all the following for remote instances
long_description: String::new(),
short_description: String::new(),
default_license: String::new(),
open_registrations: true
}) })
} }
}; };

View file

@ -13,7 +13,11 @@ pub struct Instance {
pub name: String, pub name: String,
pub local: bool, pub local: bool,
pub blocked: bool, pub blocked: bool,
pub creation_date: NaiveDateTime pub creation_date: NaiveDateTime,
pub open_registrations: bool,
pub short_description: String,
pub long_description: String,
pub default_license : String
} }
#[derive(Insertable)] #[derive(Insertable)]
@ -21,7 +25,11 @@ pub struct Instance {
pub struct NewInstance { pub struct NewInstance {
pub public_domain: String, pub public_domain: String,
pub name: String, pub name: String,
pub local: bool pub local: bool,
pub open_registrations: bool,
pub short_description: String,
pub long_description: String,
pub default_license : String
} }
impl Instance { impl Instance {
@ -68,4 +76,15 @@ impl Instance {
box_name = box_name box_name = box_name
)) ))
} }
pub fn update(&self, conn: &PgConnection, name: String, open_registrations: bool, short_description: String, long_description: String) -> Instance {
diesel::update(self)
.set((
instances::name.eq(name),
instances::open_registrations.eq(open_registrations),
instances::short_description.eq(short_description),
instances::long_description.eq(long_description),
)).get_result::<Instance>(conn)
.expect("Couldn't update instance")
}
} }

View file

@ -103,6 +103,7 @@ pub fn ap_url(url: String) -> String {
format!("{}://{}", scheme, url) format!("{}://{}", scheme, url)
} }
pub mod admin;
pub mod blog_authors; pub mod blog_authors;
pub mod blogs; pub mod blogs;
pub mod comments; pub mod comments;

View file

@ -53,6 +53,10 @@ table! {
local -> Bool, local -> Bool,
blocked -> Bool, blocked -> Bool,
creation_date -> Timestamp, creation_date -> Timestamp,
open_registrations -> Bool,
short_description -> Text,
long_description -> Text,
default_license -> Text,
} }
} }

View file

@ -184,7 +184,12 @@ impl User {
Instance::insert(conn, NewInstance { Instance::insert(conn, NewInstance {
name: inst.clone(), name: inst.clone(),
public_domain: inst.clone(), public_domain: inst.clone(),
local: false local: false,
// We don't really care about all the following for remote instances
long_description: String::new(),
short_description: String::new(),
default_license: String::new(),
open_registrations: true
}) })
} }
}; };

View file

@ -377,3 +377,9 @@ msgstr ""
msgid "Matrix room" msgid "Matrix room"
msgstr "" msgstr ""
msgid "Administration"
msgstr ""
msgid "Instance settings"
msgstr ""

View file

@ -364,3 +364,9 @@ msgstr ""
msgid "Matrix room" msgid "Matrix room"
msgstr "" msgstr ""
msgid "Administration"
msgstr ""
msgid "Instance settings"
msgstr ""

View file

@ -373,3 +373,9 @@ msgstr ""
msgid "Matrix room" msgid "Matrix room"
msgstr "" msgstr ""
msgid "Administration"
msgstr ""
msgid "Instance settings"
msgstr ""

View file

@ -382,5 +382,11 @@ msgstr ""
msgid "Matrix room" msgid "Matrix room"
msgstr "" msgstr ""
msgid "Administration"
msgstr ""
msgid "Instance settings"
msgstr ""
#~ msgid "Logowanie" #~ msgid "Logowanie"
#~ msgstr "Zaloguj się" #~ msgstr "Zaloguj się"

View file

@ -357,3 +357,9 @@ msgstr ""
msgid "Matrix room" msgid "Matrix room"
msgstr "" msgstr ""
msgid "Administration"
msgstr ""
msgid "Instance settings"
msgstr ""

View file

@ -50,6 +50,8 @@ fn main() {
routes::instance::paginated_index, routes::instance::paginated_index,
routes::instance::index, routes::instance::index,
routes::instance::admin,
routes::instance::update_settings,
routes::instance::shared_inbox, routes::instance::shared_inbox,
routes::instance::nodeinfo, routes::instance::nodeinfo,

View file

@ -1,8 +1,11 @@
use gettextrs::gettext; use gettextrs::gettext;
use rocket::{request::LenientForm, response::Redirect};
use rocket_contrib::{Json, Template}; use rocket_contrib::{Json, Template};
use serde_json; use serde_json;
use validator::{Validate};
use plume_models::{ use plume_models::{
admin::Admin,
comments::Comment, comments::Comment,
db_conn::DbConn, db_conn::DbConn,
posts::Post, posts::Post,
@ -39,6 +42,48 @@ fn index(conn: DbConn, user: Option<User>) -> Template {
paginated_index(conn, user, Page::first()) paginated_index(conn, user, Page::first())
} }
#[get("/admin")]
fn admin(conn: DbConn, admin: Admin) -> Template {
Template::render("instance/admin", json!({
"account": admin.0,
"instance": Instance::get_local(&*conn),
"errors": null,
"form": null
}))
}
#[derive(FromForm, Validate, Serialize)]
struct InstanceSettingsForm {
#[validate(length(min = "1"))]
name: String,
open_registrations: bool,
short_description: String,
long_description: String,
#[validate(length(min = "1"))]
default_license: String
}
#[post("/admin", data = "<form>")]
fn update_settings(conn: DbConn, admin: Admin, form: LenientForm<InstanceSettingsForm>) -> Result<Redirect, Template> {
let form = form.get();
form.validate()
.map(|_| {
let instance = Instance::get_local(&*conn).unwrap();
instance.update(&*conn,
form.name.clone(),
form.open_registrations,
form.short_description.clone(),
form.long_description.clone());
Redirect::to(uri!(admin))
})
.map_err(|e| Template::render("instance/admin", json!({
"account": admin.0,
"instance": Instance::get_local(&*conn),
"errors": e.inner(),
"form": form
})))
}
#[post("/inbox", data = "<data>")] #[post("/inbox", data = "<data>")]
fn shared_inbox(conn: DbConn, data: String) -> String { fn shared_inbox(conn: DbConn, data: String) -> String {
let act: serde_json::Value = serde_json::from_str(&data[..]).unwrap(); let act: serde_json::Value = serde_json::from_str(&data[..]).unwrap();

View file

@ -151,7 +151,11 @@ fn quick_setup(conn: DbConn) {
let instance = Instance::insert(&*conn, NewInstance { let instance = Instance::insert(&*conn, NewInstance {
public_domain: domain, public_domain: domain,
name: name, name: name,
local: true local: true,
long_description: String::new(),
short_description: String::new(),
default_license: String::from("CC-0"),
open_registrations: true
}); });
println!("{}\n", " ✔️ Your instance was succesfully created!".green()); println!("{}\n", " ✔️ Your instance was succesfully created!".green());

View file

@ -362,7 +362,14 @@ textarea {
font-size: 1.1em; font-size: 1.1em;
line-height: 1.5em; line-height: 1.5em;
} }
input[type="checkbox"] {
display: inline;
margin: initial;
min-width: initial;
width: initial;
}
/* Button & Submit */ /* Button & Submit */
.button, input[type="submit"], button { .button, input[type="submit"], button {

View file

@ -36,6 +36,11 @@
<span>Plume 0.1.0</span> <span>Plume 0.1.0</span>
<a href="https://github.com/Plume-org/Plume">{{ "Source code" | _ }}</a> <a href="https://github.com/Plume-org/Plume">{{ "Source code" | _ }}</a>
<a href="https://riot.im/app/#/room/#funkwhale-troubleshooting:matrix.org">{{ "Matrix room" | _ }}</a> <a href="https://riot.im/app/#/room/#funkwhale-troubleshooting:matrix.org">{{ "Matrix room" | _ }}</a>
{% if account %}
{% if account.is_admin %}
<a href="/admin">{{ "Administration" | _ }}</a>
{% endif %}
{% endif %}
</footer> </footer>
</body> </body>
</html> </html>

View file

@ -0,0 +1,34 @@
{% extends "base" %}
{% import "macros" as macros %}
{% block title %}
Administration of {{ instance.name }}
{% endblock title %}
{% block content %}
<h1>{{ "Administration" | _ }}</h1>
<h2>{{ "Instance settings" | _ }}</h2>
<form method="post">
{{ macros::input(name="name", label="Name", errors=errors, form=form, props='minlenght="1"', default=instance) }}
<label for="open_registrations">
{% if instance.open_registrations %}
<input type="checkbox" name="open_registrations" id="open_registrations" checked>
{% else %}
<input type="checkbox" name="open_registrations" id="open_registrations">
{% endif %}
{{ "Allow anyone to register" | _ }}
</label>
<label for="short_description">{{ "Short description" | _ }}<small>{{ "Markdown is supported" }}</small></label>
<textarea id="short_description" name="short_description">{{ form.short_description | default(value=instance.short_description) }}</textarea>
<label for="long_description">{{ "Long description" | _ }}<small>{{ "Markdown is supported" }}</small></label>
<textarea id="long_description" name="long_description">{{ form.long_description | default(value=instance.long_description) }}</textarea>
{{ macros::input(name="default_license", label="Default license", errors=errors, form=form, props='minlenght="1"', default=instance) }}
<input type="submit" value="{{ "Save settings" | _ }}"/>
</form>
{% endblock content %}

View file

@ -17,7 +17,7 @@
</p> </p>
</div> </div>
{% endmacro post_card %} {% endmacro post_card %}
{% macro input(name, label, errors, form, type="text", props="", optional=false) %} {% macro input(name, label, errors, form, type="text", props="", optional=false, default='') %}
<label for="{{ name }}"> <label for="{{ name }}">
{{ label | _ }} {{ label | _ }}
{% if optional %} {% if optional %}
@ -29,7 +29,8 @@
<p class="error">{{ err.message | default(value="Unknown error") | _ }}</p> <p class="error">{{ err.message | default(value="Unknown error") | _ }}</p>
{% endfor %} {% endfor %}
{% endif %} {% endif %}
<input type="{{ type }}" id="{{ name }}" name="{{ name }}" value="{{ form[name] | default(value="") }}" {{ props | safe }}/> {% set default = default[name] | default(value="") %}
<input type="{{ type }}" id="{{ name }}" name="{{ name }}" value="{{ form[name] | default(value=default) }}" {{ props | safe }}/>
{% endmacro input %} {% endmacro input %}
{% macro paginate(page, total, previous="Previous page", next="Next page") %} {% macro paginate(page, total, previous="Previous page", next="Next page") %}
<div class="pagination"> <div class="pagination">

View file

@ -19,6 +19,6 @@
<label for="summary">{{ "Summary" | _ }}</label> <label for="summary">{{ "Summary" | _ }}</label>
<input name="summary" value="{{ account.summary }}"> <input name="summary" value="{{ account.summary }}">
<input type="submit" value="{{ "Update account" | _ }}"/> <input type="submit" value="{{ "Update account" | _ }}"/>
</form> </form>
{% endblock content %} {% endblock content %}