2018-06-17 18:06:47 +02:00
|
|
|
use gettextrs::gettext;
|
2018-07-27 19:05:36 +02:00
|
|
|
use rocket::{request::LenientForm, response::Redirect};
|
2018-06-10 21:33:42 +02:00
|
|
|
use rocket_contrib::{Json, Template};
|
2018-05-12 14:56:38 +02:00
|
|
|
use serde_json;
|
2018-07-27 19:05:36 +02:00
|
|
|
use validator::{Validate};
|
2018-04-22 15:35:37 +02:00
|
|
|
|
2018-06-23 18:36:11 +02:00
|
|
|
use plume_models::{
|
2018-07-27 19:05:36 +02:00
|
|
|
admin::Admin,
|
2018-06-10 21:33:42 +02:00
|
|
|
comments::Comment,
|
2018-06-23 18:36:11 +02:00
|
|
|
db_conn::DbConn,
|
2018-05-19 09:39:59 +02:00
|
|
|
posts::Post,
|
|
|
|
users::User,
|
2018-09-14 20:25:16 +02:00
|
|
|
safe_string::SafeString,
|
2018-05-19 09:39:59 +02:00
|
|
|
instance::*
|
2018-09-14 20:25:16 +02:00
|
|
|
|
2018-05-19 09:39:59 +02:00
|
|
|
};
|
2018-06-23 18:36:11 +02:00
|
|
|
use inbox::Inbox;
|
2018-07-25 15:20:09 +02:00
|
|
|
use routes::Page;
|
2018-04-22 15:35:37 +02:00
|
|
|
|
2018-09-05 19:03:02 +02:00
|
|
|
#[get("/")]
|
|
|
|
fn index(conn: DbConn, user: Option<User>) -> Template {
|
2018-04-29 19:50:46 +02:00
|
|
|
match Instance::get_local(&*conn) {
|
|
|
|
Some(inst) => {
|
2018-09-05 19:03:02 +02:00
|
|
|
let federated = Post::get_recents_page(&*conn, Page::first().limits());
|
|
|
|
let local = Post::get_instance_page(&*conn, inst.id, Page::first().limits());
|
|
|
|
let user_feed = user.clone().map(|user| {
|
|
|
|
let followed = user.get_following(&*conn);
|
|
|
|
Post::user_feed_page(&*conn, followed.into_iter().map(|u| u.id).collect(), Page::first().limits())
|
|
|
|
});
|
2018-05-12 14:56:38 +02:00
|
|
|
|
2018-05-09 21:09:52 +02:00
|
|
|
Template::render("instance/index", json!({
|
2018-05-10 22:31:52 +02:00
|
|
|
"instance": inst,
|
2018-09-03 15:59:02 +02:00
|
|
|
"account": user.map(|u| u.to_json(&*conn)),
|
2018-09-05 19:03:02 +02:00
|
|
|
"federated": federated.into_iter().map(|p| p.to_json(&*conn)).collect::<Vec<serde_json::Value>>(),
|
|
|
|
"local": local.into_iter().map(|p| p.to_json(&*conn)).collect::<Vec<serde_json::Value>>(),
|
|
|
|
"user_feed": user_feed.map(|f| f.into_iter().map(|p| p.to_json(&*conn)).collect::<Vec<serde_json::Value>>()),
|
2018-07-27 22:16:17 +02:00
|
|
|
"n_users": User::count_local(&*conn),
|
|
|
|
"n_articles": Post::count_local(&*conn)
|
2018-05-09 21:09:52 +02:00
|
|
|
}))
|
2018-04-29 19:50:46 +02:00
|
|
|
}
|
|
|
|
None => {
|
2018-05-09 21:09:52 +02:00
|
|
|
Template::render("errors/500", json!({
|
2018-06-17 18:06:47 +02:00
|
|
|
"error_message": gettext("You need to configure your instance before using it.".to_string())
|
2018-05-09 21:09:52 +02:00
|
|
|
}))
|
2018-04-29 19:50:46 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-04 21:56:27 +02:00
|
|
|
#[get("/local?<page>")]
|
|
|
|
fn paginated_local(conn: DbConn, user: Option<User>, page: Page) -> Template {
|
|
|
|
let instance = Instance::get_local(&*conn).unwrap();
|
|
|
|
let articles = Post::get_instance_page(&*conn, instance.id, page.limits());
|
|
|
|
Template::render("instance/local", json!({
|
|
|
|
"account": user.map(|u| u.to_json(&*conn)),
|
|
|
|
"instance": instance,
|
|
|
|
"page": page.page,
|
|
|
|
"n_pages": Page::total(Post::count_local(&*conn) as i32),
|
|
|
|
"articles": articles.into_iter().map(|p| p.to_json(&*conn)).collect::<Vec<serde_json::Value>>()
|
|
|
|
}))
|
|
|
|
}
|
|
|
|
|
|
|
|
#[get("/local")]
|
|
|
|
fn local(conn: DbConn, user: Option<User>) -> Template {
|
|
|
|
paginated_local(conn, user, Page::first())
|
|
|
|
}
|
|
|
|
|
2018-09-05 16:21:50 +02:00
|
|
|
#[get("/feed")]
|
|
|
|
fn feed(conn: DbConn, user: User) -> Template {
|
|
|
|
paginated_feed(conn, user, Page::first())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[get("/feed?<page>")]
|
|
|
|
fn paginated_feed(conn: DbConn, user: User, page: Page) -> Template {
|
|
|
|
let followed = user.get_following(&*conn);
|
|
|
|
let articles = Post::user_feed_page(&*conn, followed.into_iter().map(|u| u.id).collect(), page.limits());
|
|
|
|
Template::render("instance/feed", json!({
|
|
|
|
"account": user.to_json(&*conn),
|
|
|
|
"page": page.page,
|
|
|
|
"n_pages": Page::total(Post::count_local(&*conn) as i32),
|
2018-09-05 16:37:49 +02:00
|
|
|
"articles": articles.into_iter().map(|p| p.to_json(&*conn)).collect::<Vec<serde_json::Value>>()
|
|
|
|
}))
|
|
|
|
}
|
|
|
|
|
|
|
|
#[get("/federated")]
|
|
|
|
fn federated(conn: DbConn, user: Option<User>) -> Template {
|
|
|
|
paginated_federated(conn, user, Page::first())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[get("/federated?<page>")]
|
|
|
|
fn paginated_federated(conn: DbConn, user: Option<User>, page: Page) -> Template {
|
|
|
|
let articles = Post::get_recents_page(&*conn, page.limits());
|
|
|
|
Template::render("instance/federated", json!({
|
|
|
|
"account": user.map(|u| u.to_json(&*conn)),
|
|
|
|
"page": page.page,
|
|
|
|
"n_pages": Page::total(Post::count_local(&*conn) as i32),
|
2018-09-05 16:21:50 +02:00
|
|
|
"articles": articles.into_iter().map(|p| p.to_json(&*conn)).collect::<Vec<serde_json::Value>>()
|
|
|
|
}))
|
|
|
|
}
|
|
|
|
|
2018-07-27 19:05:36 +02:00
|
|
|
#[get("/admin")]
|
|
|
|
fn admin(conn: DbConn, admin: Admin) -> Template {
|
|
|
|
Template::render("instance/admin", json!({
|
2018-09-03 15:59:02 +02:00
|
|
|
"account": admin.0.to_json(&*conn),
|
2018-07-27 19:05:36 +02:00
|
|
|
"instance": Instance::get_local(&*conn),
|
|
|
|
"errors": null,
|
|
|
|
"form": null
|
|
|
|
}))
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(FromForm, Validate, Serialize)]
|
|
|
|
struct InstanceSettingsForm {
|
|
|
|
#[validate(length(min = "1"))]
|
|
|
|
name: String,
|
|
|
|
open_registrations: bool,
|
2018-09-14 20:25:16 +02:00
|
|
|
short_description: SafeString,
|
|
|
|
long_description: SafeString,
|
2018-07-27 19:05:36 +02:00
|
|
|
#[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,
|
2018-09-14 18:24:27 +02:00
|
|
|
form.short_description.clone(),
|
|
|
|
form.long_description.clone());
|
2018-07-27 19:05:36 +02:00
|
|
|
Redirect::to(uri!(admin))
|
|
|
|
})
|
|
|
|
.map_err(|e| Template::render("instance/admin", json!({
|
2018-09-03 15:59:02 +02:00
|
|
|
"account": admin.0.to_json(&*conn),
|
2018-07-27 19:05:36 +02:00
|
|
|
"instance": Instance::get_local(&*conn),
|
|
|
|
"errors": e.inner(),
|
|
|
|
"form": form
|
|
|
|
})))
|
|
|
|
}
|
|
|
|
|
2018-09-08 20:54:09 +02:00
|
|
|
#[get("/admin/instances")]
|
|
|
|
fn admin_instances(admin: Admin, conn: DbConn) -> Template {
|
|
|
|
admin_instances_paginated(admin, conn, Page::first())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[get("/admin/instances?<page>")]
|
|
|
|
fn admin_instances_paginated(admin: Admin, conn: DbConn, page: Page) -> Template {
|
|
|
|
let instances = Instance::page(&*conn, page.limits());
|
|
|
|
Template::render("instance/list", json!({
|
|
|
|
"account": admin.0.to_json(&*conn),
|
|
|
|
"instances": instances,
|
|
|
|
"instance": Instance::get_local(&*conn),
|
|
|
|
"page": page.page,
|
|
|
|
"n_pages": Page::total(Instance::count(&*conn) as i32),
|
|
|
|
}))
|
|
|
|
}
|
|
|
|
|
2018-09-08 21:07:55 +02:00
|
|
|
#[get("/admin/instances/<id>/block")]
|
2018-09-08 23:05:48 +02:00
|
|
|
fn toggle_block(_admin: Admin, conn: DbConn, id: i32) -> Redirect {
|
2018-09-08 21:07:55 +02:00
|
|
|
if let Some(inst) = Instance::get(&*conn, id) {
|
|
|
|
inst.toggle_block(&*conn);
|
|
|
|
}
|
|
|
|
|
|
|
|
Redirect::to(uri!(admin_instances))
|
|
|
|
}
|
|
|
|
|
2018-09-09 12:25:55 +02:00
|
|
|
#[get("/admin/users")]
|
|
|
|
fn admin_users(admin: Admin, conn: DbConn) -> Template {
|
|
|
|
admin_users_paginated(admin, conn, Page::first())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[get("/admin/users?<page>")]
|
|
|
|
fn admin_users_paginated(admin: Admin, conn: DbConn, page: Page) -> Template {
|
|
|
|
let users = User::get_local_page(&*conn, page.limits()).into_iter()
|
|
|
|
.map(|u| u.to_json(&*conn)).collect::<Vec<serde_json::Value>>();
|
|
|
|
|
|
|
|
Template::render("instance/users", json!({
|
|
|
|
"account": admin.0.to_json(&*conn),
|
|
|
|
"users": users,
|
|
|
|
"page": page.page,
|
|
|
|
"n_pages": Page::total(User::count_local(&*conn) as i32)
|
|
|
|
}))
|
|
|
|
}
|
|
|
|
|
|
|
|
#[get("/admin/users/<id>/ban")]
|
|
|
|
fn ban(_admin: Admin, conn: DbConn, id: i32) -> Redirect {
|
|
|
|
User::get(&*conn, id).map(|u| u.delete(&*conn));
|
|
|
|
Redirect::to(uri!(admin_users))
|
|
|
|
}
|
|
|
|
|
2018-05-13 19:39:18 +02:00
|
|
|
#[post("/inbox", data = "<data>")]
|
|
|
|
fn shared_inbox(conn: DbConn, data: String) -> String {
|
|
|
|
let act: serde_json::Value = serde_json::from_str(&data[..]).unwrap();
|
2018-09-08 23:05:48 +02:00
|
|
|
|
|
|
|
let activity = act.clone();
|
|
|
|
let actor_id = activity["actor"].as_str()
|
|
|
|
.unwrap_or_else(|| activity["actor"]["id"].as_str().expect("No actor ID for incoming activity, blocks by panicking"));
|
|
|
|
if Instance::is_blocked(&*conn, actor_id.to_string()) {
|
|
|
|
return String::new();
|
|
|
|
}
|
2018-05-13 19:39:18 +02:00
|
|
|
let instance = Instance::get_local(&*conn).unwrap();
|
2018-06-21 18:00:37 +02:00
|
|
|
match instance.received(&*conn, act) {
|
|
|
|
Ok(_) => String::new(),
|
|
|
|
Err(e) => {
|
2018-09-08 01:11:27 +02:00
|
|
|
println!("Shared inbox error: {}\n{}", e.as_fail(), e.backtrace());
|
|
|
|
format!("Error: {}", e.as_fail())
|
2018-06-21 18:00:37 +02:00
|
|
|
}
|
|
|
|
}
|
2018-05-13 19:39:18 +02:00
|
|
|
}
|
2018-06-10 21:33:42 +02:00
|
|
|
|
|
|
|
#[get("/nodeinfo")]
|
2018-06-16 19:39:22 +02:00
|
|
|
fn nodeinfo(conn: DbConn) -> Json<serde_json::Value> {
|
2018-06-10 21:33:42 +02:00
|
|
|
Json(json!({
|
|
|
|
"version": "2.0",
|
|
|
|
"software": {
|
|
|
|
"name": "Plume",
|
2018-09-11 20:53:14 +02:00
|
|
|
"version": "0.2.0"
|
2018-06-10 21:33:42 +02:00
|
|
|
},
|
|
|
|
"protocols": ["activitypub"],
|
|
|
|
"services": {
|
|
|
|
"inbound": [],
|
|
|
|
"outbound": []
|
|
|
|
},
|
|
|
|
"openRegistrations": true,
|
|
|
|
"usage": {
|
|
|
|
"users": {
|
|
|
|
"total": User::count_local(&*conn)
|
|
|
|
},
|
|
|
|
"localPosts": Post::count_local(&*conn),
|
|
|
|
"localComments": Comment::count_local(&*conn)
|
|
|
|
},
|
|
|
|
"metadata": {}
|
|
|
|
}))
|
|
|
|
}
|
2018-09-01 18:39:40 +02:00
|
|
|
|
|
|
|
#[get("/about")]
|
2018-09-03 23:48:35 +02:00
|
|
|
fn about(user: Option<User>, conn: DbConn) -> Template {
|
2018-09-01 18:39:40 +02:00
|
|
|
Template::render("instance/about", json!({
|
2018-09-03 23:48:35 +02:00
|
|
|
"account": user.map(|u| u.to_json(&*conn)),
|
2018-09-01 18:39:40 +02:00
|
|
|
"instance": Instance::get_local(&*conn),
|
|
|
|
"admin": Instance::get_local(&*conn).map(|i| i.main_admin(&*conn).to_json(&*conn)),
|
2018-09-11 20:53:14 +02:00
|
|
|
"version": "0.2.0",
|
2018-09-01 18:39:40 +02:00
|
|
|
"n_users": User::count_local(&*conn),
|
|
|
|
"n_articles": Post::count_local(&*conn),
|
|
|
|
"n_instances": Instance::count(&*conn) - 1
|
|
|
|
}))
|
|
|
|
}
|
2018-09-10 16:08:22 +02:00
|
|
|
|
|
|
|
#[get("/manifest.json")]
|
|
|
|
fn web_manifest(conn: DbConn) -> Json<serde_json::Value> {
|
2018-09-10 20:54:18 +02:00
|
|
|
let instance = Instance::get_local(&*conn).unwrap();
|
2018-09-10 16:08:22 +02:00
|
|
|
Json(json!({
|
|
|
|
"name": &instance.name,
|
|
|
|
"description": &instance.short_description,
|
|
|
|
"start_url": String::from("/"),
|
|
|
|
"scope": String::from("/"),
|
|
|
|
"display": String::from("standalone"),
|
|
|
|
"background_color": String::from("#f4f4f4"),
|
|
|
|
"theme_color": String::from("#7765e3")
|
|
|
|
}))
|
|
|
|
}
|