Merge branch 'master' into setup-script

This commit is contained in:
Bat 2018-06-19 22:26:31 +01:00
commit 635ac6cf42
10 changed files with 109 additions and 91 deletions

View File

@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: plume\n" "Project-Id-Version: plume\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-06-15 16:33-0700\n" "POT-Creation-Date: 2018-06-15 16:33-0700\n"
"PO-Revision-Date: 2018-06-17 20:57+0200\n" "PO-Revision-Date: 2018-06-19 21:15+0200\n"
"Last-Translator: Marcin Mikołajczak <me@m4sk.in>\n" "Last-Translator: Marcin Mikołajczak <me@m4sk.in>\n"
"Language-Team: none\n" "Language-Team: none\n"
"Language: pl\n" "Language: pl\n"
@ -12,6 +12,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " "Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
"|| n%100>=20) ? 1 : 2);\n" "|| n%100>=20) ? 1 : 2);\n"
"X-Generator: Poedit 2.0.8\n"
msgid "Latest articles" msgid "Latest articles"
msgstr "Najnowsze artykuły" msgstr "Najnowsze artykuły"
@ -117,7 +118,7 @@ msgid "Publish"
msgstr "Opublikuj" msgstr "Opublikuj"
msgid "Login" msgid "Login"
msgstr "" msgstr "Logowanie"
msgid "Username or email" msgid "Username or email"
msgstr "Nazwa użytkownika lub adres e-mail" msgstr "Nazwa użytkownika lub adres e-mail"
@ -261,22 +262,22 @@ msgid "By {{ link_1 }}{{ link_2 }}{{ link_3 }}{{ name }}{{ link_4 }}"
msgstr "Napisano przez {{ link_1 }}{{ url }}{{ link_2 }}{{ name }}{{ link_3 }}" msgstr "Napisano przez {{ link_1 }}{{ url }}{{ link_2 }}{{ name }}{{ link_3 }}"
msgid "{{ data }} reshared your article" msgid "{{ data }} reshared your article"
msgstr "" msgstr "{{ data }} udostępnił Twój artykuł"
msgid "{{ data }} started following you" msgid "{{ data }} started following you"
msgstr "" msgstr "{{ data }} zaczął Cię obserwować"
msgid "{{ data }} liked your article" msgid "{{ data }} liked your article"
msgstr "" msgstr "{{ data }} polubił Twój artykuł"
msgid "{{ data }} commented your article" msgid "{{ data }} commented your article"
msgstr "" msgstr "{{ data }} skomentował Twój artykuł"
msgid "We couldn't find this page." msgid "We couldn't find this page."
msgstr "" msgstr "Nie udało się odnaleźć tej strony."
msgid "The link that led you here may be broken." msgid "The link that led you here may be broken."
msgstr "" msgstr "Odnośnik który Cię tu zaprowadził może być uszkodzony."
#~ msgid "Logowanie" #~ msgid "Logowanie"
#~ msgstr "Zaloguj się" #~ msgstr "Zaloguj się"

View File

@ -52,7 +52,7 @@ pub struct NewPost {
impl Post { impl Post {
insert!(posts, NewPost); insert!(posts, NewPost);
get!(posts); get!(posts);
find_by!(posts, find_by_slug, slug as String); find_by!(posts, find_by_slug, slug as String, blog_id as i32);
find_by!(posts, find_by_ap_url, ap_url as String); find_by!(posts, find_by_ap_url, ap_url as String);
pub fn count_local(conn: &PgConnection) -> usize { pub fn count_local(conn: &PgConnection) -> usize {

View File

@ -46,7 +46,7 @@ fn new(user: User) -> Template {
#[get("/blogs/new", rank = 2)] #[get("/blogs/new", rank = 2)]
fn new_auth() -> Flash<Redirect>{ fn new_auth() -> Flash<Redirect>{
utils::requires_login("You need to be logged in order to create a new blog", "/blogs/new") utils::requires_login("You need to be logged in order to create a new blog", uri!(new))
} }
#[derive(FromForm)] #[derive(FromForm)]
@ -59,21 +59,25 @@ fn create(conn: DbConn, data: Form<NewBlogForm>, user: User) -> Redirect {
let form = data.get(); let form = data.get();
let slug = utils::make_actor_id(form.title.to_string()); let slug = utils::make_actor_id(form.title.to_string());
let blog = Blog::insert(&*conn, NewBlog::new_local( if Blog::find_local(&*conn, slug.clone()).is_some() || slug.len() == 0 {
slug.to_string(), Redirect::to(uri!(new))
form.title.to_string(), } else {
String::from(""), let blog = Blog::insert(&*conn, NewBlog::new_local(
Instance::local_id(&*conn) slug.to_string(),
)); form.title.to_string(),
blog.update_boxes(&*conn); String::from(""),
Instance::local_id(&*conn)
));
blog.update_boxes(&*conn);
BlogAuthor::insert(&*conn, NewBlogAuthor { BlogAuthor::insert(&*conn, NewBlogAuthor {
blog_id: blog.id, blog_id: blog.id,
author_id: user.id, author_id: user.id,
is_owner: true is_owner: true
}); });
Redirect::to(format!("/~/{}/", slug)) Redirect::to(uri!(details: name = slug))
}
} }
#[get("/~/<name>/outbox")] #[get("/~/<name>/outbox")]

View File

@ -7,6 +7,7 @@ use rocket_contrib::Template;
use activity_pub::{broadcast, IntoId, inbox::Notify}; use activity_pub::{broadcast, IntoId, inbox::Notify};
use db_conn::DbConn; use db_conn::DbConn;
use models::{ use models::{
blogs::Blog,
comments::*, comments::*,
posts::Post, posts::Post,
users::User users::User
@ -15,19 +16,21 @@ use models::{
use utils; use utils;
use safe_string::SafeString; use safe_string::SafeString;
#[get("/~/<_blog>/<slug>/comment")] #[get("/~/<blog>/<slug>/comment")]
fn new(_blog: String, slug: String, user: User, conn: DbConn) -> Template { fn new(blog: String, slug: String, user: User, conn: DbConn) -> Template {
may_fail!(Post::find_by_slug(&*conn, slug), "Couldn't find this post", |post| { may_fail!(Blog::find_by_fqn(&*conn, blog), "Couldn't find this blog", |blog| {
Template::render("comments/new", json!({ may_fail!(Post::find_by_slug(&*conn, slug, blog.id), "Couldn't find this post", |post| {
"post": post, Template::render("comments/new", json!({
"account": user "post": post,
})) "account": user
}))
})
}) })
} }
#[get("/~/<blog>/<slug>/comment", rank=2)] #[get("/~/<blog>/<slug>/comment", rank=2)]
fn new_auth(blog: String, slug: String) -> Flash<Redirect>{ fn new_auth(blog: String, slug: String) -> Flash<Redirect>{
utils::requires_login("You need to be logged in order to post a comment", &format!("~/{}/{}/comment", blog, slug)) utils::requires_login("You need to be logged in order to post a comment", uri!(new: blog = blog, slug = slug))
} }
#[derive(FromForm)] #[derive(FromForm)]
@ -40,9 +43,10 @@ struct NewCommentForm {
pub content: String pub content: String
} }
#[post("/~/<blog>/<slug>/comment?<query>", data = "<data>")] #[post("/~/<blog_name>/<slug>/comment?<query>", data = "<data>")]
fn create(blog: String, slug: String, query: CommentQuery, data: Form<NewCommentForm>, user: User, conn: DbConn) -> Redirect { fn create(blog_name: String, slug: String, query: CommentQuery, data: Form<NewCommentForm>, user: User, conn: DbConn) -> Redirect {
let post = Post::find_by_slug(&*conn, slug.clone()).unwrap(); let blog = Blog::find_by_fqn(&*conn, blog_name.clone()).unwrap();
let post = Post::find_by_slug(&*conn, slug.clone(), blog.id).unwrap();
let form = data.get(); let form = data.get();
let comment = Comment::insert(&*conn, NewComment { let comment = Comment::insert(&*conn, NewComment {
content: SafeString::new(&form.content.clone()), content: SafeString::new(&form.content.clone()),
@ -57,5 +61,5 @@ fn create(blog: String, slug: String, query: CommentQuery, data: Form<NewComment
Comment::notify(&*conn, comment.into_activity(&*conn), user.clone().into_id()); Comment::notify(&*conn, comment.into_activity(&*conn), user.clone().into_id());
broadcast(&*conn, &user, comment.create_activity(&*conn), user.get_followers(&*conn)); broadcast(&*conn, &user, comment.create_activity(&*conn), user.get_followers(&*conn));
Redirect::to(format!("/~/{}/{}/#comment-{}", blog, slug, comment.id)) Redirect::to(format!("/~/{}/{}/#comment-{}", blog_name, slug, comment.id))
} }

View File

@ -3,6 +3,7 @@ use rocket::response::{Redirect, Flash};
use activity_pub::{broadcast, IntoId, inbox::Notify}; use activity_pub::{broadcast, IntoId, inbox::Notify};
use db_conn::DbConn; use db_conn::DbConn;
use models::{ use models::{
blogs::Blog,
likes, likes,
posts::Post, posts::Post,
users::User users::User
@ -12,7 +13,8 @@ use utils;
#[get("/~/<blog>/<slug>/like")] #[get("/~/<blog>/<slug>/like")]
fn create(blog: String, slug: String, user: User, conn: DbConn) -> Redirect { fn create(blog: String, slug: String, user: User, conn: DbConn) -> Redirect {
let post = Post::find_by_slug(&*conn, slug.clone()).unwrap(); let b = Blog::find_by_fqn(&*conn, blog.clone()).unwrap();
let post = Post::find_by_slug(&*conn, slug.clone(), b.id).unwrap();
if !user.has_liked(&*conn, &post) { if !user.has_liked(&*conn, &post) {
let like = likes::Like::insert(&*conn, likes::NewLike { let like = likes::Like::insert(&*conn, likes::NewLike {
@ -30,10 +32,10 @@ fn create(blog: String, slug: String, user: User, conn: DbConn) -> Redirect {
broadcast(&*conn, &user, delete_act, user.get_followers(&*conn)); broadcast(&*conn, &user, delete_act, user.get_followers(&*conn));
} }
Redirect::to(format!("/~/{}/{}/", blog, slug)) Redirect::to(uri!(super::posts::details: blog = blog, slug = slug))
} }
#[get("/~/<blog>/<slug>/like", rank = 2)] #[get("/~/<blog>/<slug>/like", rank = 2)]
fn create_auth(blog: String, slug: String) -> Flash<Redirect>{ fn create_auth(blog: String, slug: String) -> Flash<Redirect>{
utils::requires_login("You need to be logged in order to like a post", &format!("/~/{}/{}/like", blog, slug)) utils::requires_login("You need to be logged in order to like a post", uri!(create: blog = blog, slug = slug))
} }

View File

@ -16,5 +16,5 @@ fn notifications(conn: DbConn, user: User) -> Template {
#[get("/notifications", rank = 2)] #[get("/notifications", rank = 2)]
fn notifications_auth() -> Flash<Redirect>{ fn notifications_auth() -> Flash<Redirect>{
utils::requires_login("You need to be logged in order to see your notifications", "/notifications") utils::requires_login("You need to be logged in order to see your notifications", uri!(notifications))
} }

View File

@ -20,7 +20,7 @@ use safe_string::SafeString;
#[get("/~/<blog>/<slug>", rank = 4)] #[get("/~/<blog>/<slug>", rank = 4)]
fn details(blog: String, slug: String, conn: DbConn, user: Option<User>) -> Template { fn details(blog: String, slug: String, conn: DbConn, user: Option<User>) -> Template {
may_fail!(Blog::find_by_fqn(&*conn, blog), "Couldn't find this blog", |blog| { may_fail!(Blog::find_by_fqn(&*conn, blog), "Couldn't find this blog", |blog| {
may_fail!(Post::find_by_slug(&*conn, slug), "Couldn't find this post", |post| { may_fail!(Post::find_by_slug(&*conn, slug, blog.id), "Couldn't find this post", |post| {
let comments = Comment::find_by_post(&*conn, post.id); let comments = Comment::find_by_post(&*conn, post.id);
Template::render("posts/details", json!({ Template::render("posts/details", json!({
@ -39,10 +39,10 @@ fn details(blog: String, slug: String, conn: DbConn, user: Option<User>) -> Temp
}) })
} }
#[get("/~/<_blog>/<slug>", rank = 3, format = "application/activity+json")] #[get("/~/<blog>/<slug>", rank = 3, format = "application/activity+json")]
fn activity_details(_blog: String, slug: String, conn: DbConn) -> ActivityPub { fn activity_details(blog: String, slug: String, conn: DbConn) -> ActivityPub {
// FIXME: posts in different blogs may have the same slug let blog = Blog::find_by_fqn(&*conn, blog).unwrap();
let post = Post::find_by_slug(&*conn, slug).unwrap(); let post = Post::find_by_slug(&*conn, slug, blog.id).unwrap();
let mut act = post.serialize(&*conn); let mut act = post.serialize(&*conn);
act["@context"] = context(); act["@context"] = context();
@ -51,11 +51,12 @@ fn activity_details(_blog: String, slug: String, conn: DbConn) -> ActivityPub {
#[get("/~/<blog>/new", rank = 2)] #[get("/~/<blog>/new", rank = 2)]
fn new_auth(blog: String) -> Flash<Redirect> { fn new_auth(blog: String) -> Flash<Redirect> {
utils::requires_login("You need to be logged in order to write a new post", &format!("/~/{}/new",blog)) utils::requires_login("You need to be logged in order to write a new post", uri!(new: blog = blog))
} }
#[get("/~/<_blog>/new", rank = 1)] #[get("/~/<blog>/new", rank = 1)]
fn new(_blog: String, user: User) -> Template { #[allow(unused_variables)]
fn new(blog: String, user: User) -> Template {
Template::render("posts/new", json!({ Template::render("posts/new", json!({
"account": user "account": user
})) }))
@ -74,37 +75,41 @@ fn create(blog_name: String, data: Form<NewPostForm>, user: User, conn: DbConn)
let form = data.get(); let form = data.get();
let slug = form.title.to_string().to_kebab_case(); let slug = form.title.to_string().to_kebab_case();
let content = markdown_to_html(form.content.to_string().as_ref(), &ComrakOptions{ if slug == "new" || Post::find_by_slug(&*conn, slug.clone(), blog.id).is_some() {
smart: true, Redirect::to(uri!(new: blog = blog_name))
safe: true, } else {
ext_strikethrough: true, let content = markdown_to_html(form.content.to_string().as_ref(), &ComrakOptions{
ext_tagfilter: true, smart: true,
ext_table: true, safe: true,
ext_autolink: true, ext_strikethrough: true,
ext_tasklist: true, ext_tagfilter: true,
ext_superscript: true, ext_table: true,
ext_header_ids: Some("title".to_string()), ext_autolink: true,
ext_footnotes: true, ext_tasklist: true,
..ComrakOptions::default() ext_superscript: true,
}); ext_header_ids: Some("title".to_string()),
ext_footnotes: true,
..ComrakOptions::default()
});
let post = Post::insert(&*conn, NewPost { let post = Post::insert(&*conn, NewPost {
blog_id: blog.id, blog_id: blog.id,
slug: slug.to_string(), slug: slug.to_string(),
title: form.title.to_string(), title: form.title.to_string(),
content: SafeString::new(&content), content: SafeString::new(&content),
published: true, published: true,
license: form.license.to_string(), license: form.license.to_string(),
ap_url: "".to_string() ap_url: "".to_string()
}); });
post.update_ap_url(&*conn); post.update_ap_url(&*conn);
PostAuthor::insert(&*conn, NewPostAuthor { PostAuthor::insert(&*conn, NewPostAuthor {
post_id: post.id, post_id: post.id,
author_id: user.id author_id: user.id
}); });
let act = post.create_activity(&*conn); let act = post.create_activity(&*conn);
broadcast(&*conn, &user, act, user.get_followers(&*conn)); broadcast(&*conn, &user, act, user.get_followers(&*conn));
Redirect::to(format!("/~/{}/{}/", blog_name, slug)) Redirect::to(uri!(details: blog = blog_name, slug = slug))
}
} }

View File

@ -3,6 +3,7 @@ use rocket::response::{Redirect, Flash};
use activity_pub::{broadcast, IntoId, inbox::Notify}; use activity_pub::{broadcast, IntoId, inbox::Notify};
use db_conn::DbConn; use db_conn::DbConn;
use models::{ use models::{
blogs::Blog,
posts::Post, posts::Post,
reshares::*, reshares::*,
users::User users::User
@ -12,7 +13,8 @@ use utils;
#[get("/~/<blog>/<slug>/reshare")] #[get("/~/<blog>/<slug>/reshare")]
fn create(blog: String, slug: String, user: User, conn: DbConn) -> Redirect { fn create(blog: String, slug: String, user: User, conn: DbConn) -> Redirect {
let post = Post::find_by_slug(&*conn, slug.clone()).unwrap(); let b = Blog::find_by_fqn(&*conn, blog.clone()).unwrap();
let post = Post::find_by_slug(&*conn, slug.clone(), b.id).unwrap();
if !user.has_reshared(&*conn, &post) { if !user.has_reshared(&*conn, &post) {
let reshare = Reshare::insert(&*conn, NewReshare { let reshare = Reshare::insert(&*conn, NewReshare {
@ -30,10 +32,10 @@ fn create(blog: String, slug: String, user: User, conn: DbConn) -> Redirect {
broadcast(&*conn, &user, delete_act, user.get_followers(&*conn)); broadcast(&*conn, &user, delete_act, user.get_followers(&*conn));
} }
Redirect::to(format!("/~/{}/{}/", blog, slug)) Redirect::to(uri!(super::posts::details: blog = blog, slug = slug))
} }
#[get("/~/<blog>/<slug>/reshare", rank=1)] #[get("/~/<blog>/<slug>/reshare", rank=1)]
fn create_auth(blog: String, slug: String) -> Flash<Redirect> { fn create_auth(blog: String, slug: String) -> Flash<Redirect> {
utils::requires_login("You need to be logged in order to reshare a post", &format!("/~/{}/{}/reshare",blog, slug)) utils::requires_login("You need to be logged in order to reshare a post", uri!(create: blog = blog, slug = slug))
} }

View File

@ -27,8 +27,8 @@ use utils;
#[get("/me")] #[get("/me")]
fn me(user: Option<User>) -> Result<Redirect, Flash<Redirect>> { fn me(user: Option<User>) -> Result<Redirect, Flash<Redirect>> {
match user { match user {
Some(user) => Ok(Redirect::to(format!("/@/{}/", user.username))), Some(user) => Ok(Redirect::to(uri!(details: name = user.username))),
None => Err(utils::requires_login("", "/me")) None => Err(utils::requires_login("", uri!(me)))
} }
} }
@ -65,7 +65,7 @@ fn dashboard(user: User, conn: DbConn) -> Template {
#[get("/dashboard", rank = 2)] #[get("/dashboard", rank = 2)]
fn dashboard_auth() -> Flash<Redirect> { fn dashboard_auth() -> Flash<Redirect> {
utils::requires_login("You need to be logged in order to access your dashboard", "/dashboard") utils::requires_login("You need to be logged in order to access your dashboard", uri!(dashboard))
} }
#[get("/@/<name>/follow")] #[get("/@/<name>/follow")]
@ -82,12 +82,12 @@ fn follow(name: String, conn: DbConn, user: User) -> Redirect {
follows::Follow::notify(&*conn, act.clone(), user.clone().into_id()); follows::Follow::notify(&*conn, act.clone(), user.clone().into_id());
broadcast(&*conn, &user, act, vec![target]); broadcast(&*conn, &user, act, vec![target]);
Redirect::to(format!("/@/{}/", name)) Redirect::to(uri!(details: name = name))
} }
#[get("/@/<name>/follow", rank = 2)] #[get("/@/<name>/follow", rank = 2)]
fn follow_auth(name: String) -> Flash<Redirect> { fn follow_auth(name: String) -> Flash<Redirect> {
utils::requires_login("You need to be logged in order to follow someone", &format!("/@/{}/follow", name)) utils::requires_login("You need to be logged in order to follow someone", uri!(follow: name = name))
} }
#[get("/@/<name>/followers", rank = 2)] #[get("/@/<name>/followers", rank = 2)]
@ -134,7 +134,7 @@ fn edit(name: String, user: User) -> Option<Template> {
#[get("/@/<name>/edit", rank = 2)] #[get("/@/<name>/edit", rank = 2)]
fn edit_auth(name: String) -> Flash<Redirect> { fn edit_auth(name: String) -> Flash<Redirect> {
utils::requires_login("You need to be logged in order to edit your profile", &format!("/@/{}/edit", name)) utils::requires_login("You need to be logged in order to edit your profile", uri!(edit: name = name))
} }
#[derive(FromForm)] #[derive(FromForm)]
@ -151,7 +151,7 @@ fn update(_name: String, conn: DbConn, user: User, data: Form<UpdateUserForm>) -
data.get().email.clone().unwrap_or(user.email.clone().unwrap()).to_string(), data.get().email.clone().unwrap_or(user.email.clone().unwrap()).to_string(),
data.get().summary.clone().unwrap_or(user.summary.to_string()) data.get().summary.clone().unwrap_or(user.summary.to_string())
); );
Redirect::to("/me") Redirect::to(uri!(me))
} }
#[derive(FromForm)] #[derive(FromForm)]
@ -182,7 +182,7 @@ fn create(conn: DbConn, data: Form<NewUserForm>) -> Result<Redirect, String> {
form.email.to_string(), form.email.to_string(),
User::hash_pass(form.password.to_string()) User::hash_pass(form.password.to_string())
).update_boxes(&*conn); ).update_boxes(&*conn);
Ok(Redirect::to(format!("/@/{}/", data.get().username))) Ok(Redirect::to(uri!(super::session::new)))
} else { } else {
Err(String::from("Passwords don't match")) Err(String::from("Passwords don't match"))
} }

View File

@ -15,6 +15,6 @@ pub fn make_actor_id(name: String) -> String {
.collect() .collect()
} }
pub fn requires_login(message: &str, url: &str) -> Flash<Redirect> { pub fn requires_login(message: &str, url: Uri) -> Flash<Redirect> {
Flash::new(Redirect::to(Uri::new(format!("/login?m={}", gettext(message.to_string())))), "callback", url) Flash::new(Redirect::to(Uri::new(format!("/login?m={}", gettext(message.to_string())))), "callback", url.as_str())
} }