Merge branch 'master' of https://github.com/Plume-org/Plume into icons
This commit is contained in:
		
						commit
						a30b99f93e
					
				
							
								
								
									
										22
									
								
								docs/ENV-VARS.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								docs/ENV-VARS.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | ||||
| # Useful Environment Variables | ||||
| 
 | ||||
| Plume relies on some environment variables for some configuration options. You can either set them before | ||||
| starting the app with `cargo run` or write them in a `.env` file to have automatically loaded. | ||||
| 
 | ||||
| Here are the variables that Plume uses: | ||||
| 
 | ||||
| - `BASE_URL`: the domain name, or IP and port on which Plume is listening. It is used in all federation-related code. | ||||
| - `DB_URL`: the URL of the PostgreSQL database, used by Plume (`postgres://plume:plume@localhost/plume` by default). | ||||
| - `POSTGRES_USER`: if you just want to use a different PostgreSQL user name, and keep the rest of the default URL. | ||||
| - `POSTGRES_PASSWORD`: same as `POSTGRES_USER`, but for the password. | ||||
| - `USE_HTTPS`: if it is `0`, federation and medias will be using HTTP by default (`1` by default). | ||||
| - `ROCKET_ADDRESS`: the adress on which Plume should listen (`0.0.0.0` by default). | ||||
| - `ROCKET_PORT`: the port on which Plume should listen ([`7878` by default](https://twitter.com/ag_dubs/status/852559264510070784)) | ||||
| - `ROCKET_SECRET_KEY`: key used to sign private cookies and for CSRF protection. If it is not set, it will be regenerated everytime you restart Plume, | ||||
| meaning that all your users will get disconnected. You can generate one with `openssl rand -base64 32`. | ||||
| 
 | ||||
| ## Diesel | ||||
| 
 | ||||
| Diesel, the tool we use to run migrations may be configured with the `DATABASE_URL` which should contain the URL of the | ||||
| PostgreSQL database. Otherwise, you can specify `--database-url YOUR-URL` everytime you run a `diesel` command. | ||||
| 
 | ||||
| @ -2,5 +2,6 @@ | ||||
| 
 | ||||
| - [Installing Plume (for development or production)](INSTALL.md) | ||||
| - [Updating your instance](UPDATE.md) | ||||
| - [Useful Environment Variables](ENV-VARS.md) | ||||
| - [Development Guide](DEVELOPMENT.md) | ||||
| - [Making Plume available in your language](INTERNATIONALIZATION.md) | ||||
|  | ||||
							
								
								
									
										2
									
								
								migrations/2018-09-04-103017_follows_add_ap_url/down.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								migrations/2018-09-04-103017_follows_add_ap_url/down.sql
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,2 @@ | ||||
| -- This file should undo anything in `up.sql` | ||||
| ALTER TABLE follows DROP COLUMN ap_url; | ||||
							
								
								
									
										2
									
								
								migrations/2018-09-04-103017_follows_add_ap_url/up.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								migrations/2018-09-04-103017_follows_add_ap_url/up.sql
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,2 @@ | ||||
| -- Your SQL goes here | ||||
| ALTER TABLE follows ADD COLUMN ap_url TEXT NOT NULL DEFAULT ''; | ||||
							
								
								
									
										2
									
								
								migrations/2018-09-04-104828_posts_add_subtitle/down.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								migrations/2018-09-04-104828_posts_add_subtitle/down.sql
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,2 @@ | ||||
| -- This file should undo anything in `up.sql` | ||||
| ALTER TABLE posts DROP COLUMN subtitle; | ||||
							
								
								
									
										2
									
								
								migrations/2018-09-04-104828_posts_add_subtitle/up.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								migrations/2018-09-04-104828_posts_add_subtitle/up.sql
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,2 @@ | ||||
| -- Your SQL goes here | ||||
| ALTER TABLE posts ADD COLUMN subtitle TEXT NOT NULL DEFAULT ''; | ||||
| @ -1,7 +1,7 @@ | ||||
| use activitypub::{Actor, activity::{Accept, Follow as FollowAct}, actor::Person}; | ||||
| use activitypub::{Actor, activity::{Accept, Follow as FollowAct, Undo}, actor::Person}; | ||||
| use diesel::{self, PgConnection, ExpressionMethods, QueryDsl, RunQueryDsl}; | ||||
| 
 | ||||
| use plume_common::activity_pub::{broadcast, Id, IntoId, inbox::{FromActivity, Notify, WithInbox}, sign::Signer}; | ||||
| use plume_common::activity_pub::{broadcast, Id, IntoId, inbox::{FromActivity, Notify, WithInbox, Deletable}, sign::Signer}; | ||||
| use blogs::Blog; | ||||
| use notifications::*; | ||||
| use users::User; | ||||
| @ -12,19 +12,42 @@ use schema::follows; | ||||
| pub struct Follow { | ||||
|     pub id: i32, | ||||
|     pub follower_id: i32, | ||||
|     pub following_id: i32 | ||||
|     pub following_id: i32, | ||||
|     pub ap_url: String, | ||||
| } | ||||
| 
 | ||||
| #[derive(Insertable)] | ||||
| #[table_name = "follows"] | ||||
| pub struct NewFollow { | ||||
|     pub follower_id: i32, | ||||
|     pub following_id: i32 | ||||
|     pub following_id: i32, | ||||
|     pub ap_url: String, | ||||
| } | ||||
| 
 | ||||
| impl Follow { | ||||
|     insert!(follows, NewFollow); | ||||
|     get!(follows); | ||||
|     find_by!(follows, find_by_ap_url, ap_url as String); | ||||
| 
 | ||||
|     pub fn find(conn: &PgConnection, from: i32, to: i32) -> Option<Follow> { | ||||
|         follows::table.filter(follows::follower_id.eq(from)) | ||||
|             .filter(follows::following_id.eq(to)) | ||||
|             .get_result(conn) | ||||
|             .ok() | ||||
|     } | ||||
| 
 | ||||
|     pub fn into_activity(&self, conn: &PgConnection) -> FollowAct { | ||||
|         let user = User::get(conn, self.follower_id).unwrap(); | ||||
|         let target = User::get(conn, self.following_id).unwrap(); | ||||
| 
 | ||||
|         let mut act = FollowAct::default(); | ||||
|         act.follow_props.set_actor_link::<Id>(user.clone().into_id()).expect("Follow::into_activity: actor error"); | ||||
|         act.follow_props.set_object_object(user.into_activity(&*conn)).unwrap(); | ||||
|         act.object_props.set_id_string(self.ap_url.clone()).unwrap(); | ||||
|         act.object_props.set_to_link(target.clone().into_id()).expect("New Follow error while setting 'to'"); | ||||
|         act.object_props.set_cc_link_vec::<Id>(vec![]).expect("New Follow error while setting 'cc'"); | ||||
|         act | ||||
|     } | ||||
| 
 | ||||
|     /// from -> The one sending the follow request
 | ||||
|     /// target -> The target of the request, responding with Accept
 | ||||
| @ -36,9 +59,12 @@ impl Follow { | ||||
|         from_id: i32, | ||||
|         target_id: i32 | ||||
|     ) -> Follow { | ||||
|         let from_url: String = from.clone().into_id().into(); | ||||
|         let target_url: String = target.clone().into_id().into(); | ||||
|         let res = Follow::insert(conn, NewFollow { | ||||
|             follower_id: from_id, | ||||
|             following_id: target_id | ||||
|             following_id: target_id, | ||||
|             ap_url: format!("{}/follow/{}", from_url, target_url), | ||||
|         }); | ||||
| 
 | ||||
|         let mut accept = Accept::default(); | ||||
| @ -77,3 +103,21 @@ impl Notify<PgConnection> for Follow { | ||||
|         }); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Deletable<PgConnection, Undo> for Follow { | ||||
|     fn delete(&self, conn: &PgConnection) -> Undo { | ||||
|         diesel::delete(self).execute(conn).expect("Coudn't delete follow"); | ||||
| 
 | ||||
|         let mut undo = Undo::default(); | ||||
|         undo.undo_props.set_actor_link(User::get(conn, self.follower_id).unwrap().into_id()).expect("Follow::delete: actor error"); | ||||
|         undo.object_props.set_id_string(format!("{}/undo", self.ap_url)).expect("Follow::delete: id error"); | ||||
|         undo.undo_props.set_object_object(self.into_activity(conn)).expect("Follow::delete: object error"); | ||||
|         undo | ||||
|     } | ||||
| 
 | ||||
|     fn delete_id(id: String, conn: &PgConnection) { | ||||
|         if let Some(follow) = Follow::find_by_ap_url(conn, id) { | ||||
|             follow.delete(conn); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -33,20 +33,22 @@ pub struct Post { | ||||
|     pub published: bool, | ||||
|     pub license: String, | ||||
|     pub creation_date: NaiveDateTime, | ||||
|     pub ap_url: String | ||||
|     pub ap_url: String, | ||||
|     pub subtitle: String, | ||||
| } | ||||
| 
 | ||||
| #[derive(Insertable)] | ||||
| #[table_name = "posts"] | ||||
| pub struct NewPost { | ||||
|     pub blog_id: i32,    
 | ||||
|     pub blog_id: i32, | ||||
|     pub slug: String, | ||||
|     pub title: String, | ||||
|     pub content: SafeString, | ||||
|     pub published: bool, | ||||
|     pub license: String, | ||||
|     pub creation_date: Option<NaiveDateTime>, | ||||
|     pub ap_url: String | ||||
|     pub ap_url: String, | ||||
|     pub subtitle: String, | ||||
| } | ||||
| 
 | ||||
| impl Post { | ||||
| @ -185,6 +187,7 @@ impl Post { | ||||
|         article.object_props.set_attributed_to_link_vec::<Id>(authors).expect("Article::into_activity: attributedTo error"); | ||||
|         article.object_props.set_content_string(self.content.get().clone()).expect("Article::into_activity: content error"); | ||||
|         article.object_props.set_published_utctime(Utc.from_utc_datetime(&self.creation_date)).expect("Article::into_activity: published error"); | ||||
|         article.object_props.set_summary_string(self.subtitle.clone()).expect("Article::into_activity: summary error"); | ||||
|         article.object_props.set_tag_link_vec(mentions).expect("Article::into_activity: tag error"); | ||||
|         article.object_props.set_url_string(self.ap_url.clone()).expect("Article::into_activity: url error"); | ||||
|         article.object_props.set_to_link_vec::<Id>(to.into_iter().map(Id::new).collect()).expect("Article::into_activity: to error"); | ||||
| @ -250,7 +253,8 @@ impl FromActivity<Article, PgConnection> for Post { | ||||
|                 license: String::from("CC-0"), // TODO
 | ||||
|                 // FIXME: This is wrong: with this logic, we may use the display URL as the AP ID. We need two different fields
 | ||||
|                 ap_url: article.object_props.url_string().unwrap_or(article.object_props.id_string().expect("Post::from_activity: url + id error")), | ||||
|                 creation_date: Some(article.object_props.published_utctime().expect("Post::from_activity: published error").naive_utc()) | ||||
|                 creation_date: Some(article.object_props.published_utctime().expect("Post::from_activity: published error").naive_utc()), | ||||
|                 subtitle: article.object_props.summary_string().expect("Post::from_activity: summary error") | ||||
|             }); | ||||
| 
 | ||||
|             for author in authors.into_iter() { | ||||
|  | ||||
| @ -42,6 +42,7 @@ table! { | ||||
|         id -> Int4, | ||||
|         follower_id -> Int4, | ||||
|         following_id -> Int4, | ||||
|         ap_url -> Text, | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -124,6 +125,7 @@ table! { | ||||
|         license -> Varchar, | ||||
|         creation_date -> Timestamp, | ||||
|         ap_url -> Varchar, | ||||
|         subtitle -> Text, | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -567,7 +567,7 @@ impl WithInbox for User { | ||||
|     } | ||||
| 
 | ||||
|     fn is_local(&self) -> bool { | ||||
|         self.instance_id == 0 | ||||
|         self.instance_id == 1 | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										10
									
								
								po/de.po
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								po/de.po
									
									
									
									
									
								
							| @ -508,5 +508,15 @@ msgid "" | ||||
| "Sorry, but registrations are closed on this instance. Try to find another one" | ||||
| msgstr "" | ||||
| 
 | ||||
| #, fuzzy | ||||
| msgid "Subtitle" | ||||
| msgstr "Titel" | ||||
| 
 | ||||
| msgid "Login to like" | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "Login to boost" | ||||
| msgstr "" | ||||
| 
 | ||||
| #~ msgid "Your password should be at least 8 characters long" | ||||
| #~ msgstr "Das Passwort sollte mindestens 8 Zeichen lang sein" | ||||
|  | ||||
							
								
								
									
										9
									
								
								po/en.po
									
									
									
									
									
								
							
							
						
						
									
										9
									
								
								po/en.po
									
									
									
									
									
								
							| @ -497,3 +497,12 @@ msgstr "" | ||||
| msgid "" | ||||
| "Sorry, but registrations are closed on this instance. Try to find another one" | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "Subtitle" | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "Login to like" | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "Login to boost" | ||||
| msgstr "" | ||||
|  | ||||
							
								
								
									
										14
									
								
								po/fr.po
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								po/fr.po
									
									
									
									
									
								
							| @ -503,4 +503,16 @@ msgstr "Envoyer" | ||||
| 
 | ||||
| msgid "" | ||||
| "Sorry, but registrations are closed on this instance. Try to find another one" | ||||
| msgstr "Désolé, mais les inscriptions sont fermées sur cette instance. Essayez d'en trouver une autre." | ||||
| msgstr "" | ||||
| "Désolé, mais les inscriptions sont fermées sur cette instance. Essayez d'en " | ||||
| "trouver une autre." | ||||
| 
 | ||||
| #, fuzzy | ||||
| msgid "Subtitle" | ||||
| msgstr "Titre" | ||||
| 
 | ||||
| msgid "Login to like" | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "Login to boost" | ||||
| msgstr "" | ||||
|  | ||||
							
								
								
									
										13
									
								
								po/gl.po
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								po/gl.po
									
									
									
									
									
								
							| @ -496,4 +496,15 @@ msgstr "Enviar" | ||||
| msgid "" | ||||
| "Sorry, but registrations are closed on this instance. Try to find another one" | ||||
| msgstr "" | ||||
| "Lamentámolo, pero o rexistro en esta instancia está pechado. Inténteo en outra instancia" | ||||
| "Lamentámolo, pero o rexistro en esta instancia está pechado. Inténteo en " | ||||
| "outra instancia" | ||||
| 
 | ||||
| #, fuzzy | ||||
| msgid "Subtitle" | ||||
| msgstr "Título" | ||||
| 
 | ||||
| msgid "Login to like" | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "Login to boost" | ||||
| msgstr "" | ||||
|  | ||||
							
								
								
									
										10
									
								
								po/nb.po
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								po/nb.po
									
									
									
									
									
								
							| @ -512,6 +512,16 @@ msgid "" | ||||
| "Sorry, but registrations are closed on this instance. Try to find another one" | ||||
| msgstr "" | ||||
| 
 | ||||
| #, fuzzy | ||||
| msgid "Subtitle" | ||||
| msgstr "Tittel" | ||||
| 
 | ||||
| msgid "Login to like" | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "Login to boost" | ||||
| msgstr "" | ||||
| 
 | ||||
| #~ msgid "One reshare" | ||||
| #~ msgid_plural "{{ count }} reshares" | ||||
| #~ msgstr[0] "Én deling" | ||||
|  | ||||
							
								
								
									
										108
									
								
								po/pl.po
									
									
									
									
									
								
							
							
						
						
									
										108
									
								
								po/pl.po
									
									
									
									
									
								
							| @ -3,7 +3,7 @@ msgstr "" | ||||
| "Project-Id-Version: plume\n" | ||||
| "Report-Msgid-Bugs-To: \n" | ||||
| "POT-Creation-Date: 2018-06-15 16:33-0700\n" | ||||
| "PO-Revision-Date: 2018-07-28 14:56+0200\n" | ||||
| "PO-Revision-Date: 2018-09-04 17:35+0200\n" | ||||
| "Last-Translator: Marcin Mikołajczak <me@m4sk.in>\n" | ||||
| "Language-Team: none\n" | ||||
| "Language: pl\n" | ||||
| @ -12,7 +12,7 @@ msgstr "" | ||||
| "Content-Transfer-Encoding: 8bit\n" | ||||
| "Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " | ||||
| "|| n%100>=20) ? 1 : 2);\n" | ||||
| "X-Generator: Poedit 2.0.9\n" | ||||
| "X-Generator: Poedit 2.1.1\n" | ||||
| 
 | ||||
| msgid "Latest articles" | ||||
| msgstr "Najnowsze artykuły" | ||||
| @ -92,16 +92,15 @@ msgstr "Dodaj swoje" | ||||
| 
 | ||||
| msgid "One Boost" | ||||
| msgid_plural "{{ count }} Boosts" | ||||
| msgstr[0] "" | ||||
| msgstr[1] "" | ||||
| msgstr[2] "" | ||||
| msgstr[0] "Jedno podbicie" | ||||
| msgstr[1] "{{ count }} podbicia" | ||||
| msgstr[2] "{{ count }} podbić" | ||||
| 
 | ||||
| #, fuzzy | ||||
| msgid "I don't want to boost this anymore" | ||||
| msgstr "Cofnij udostępnienie" | ||||
| msgstr "Cofnij podbicie" | ||||
| 
 | ||||
| msgid "Boost" | ||||
| msgstr "" | ||||
| msgstr "Podbij" | ||||
| 
 | ||||
| msgid "Comments" | ||||
| msgstr "Komentarze" | ||||
| @ -165,9 +164,8 @@ msgstr "Obserwuj" | ||||
| msgid "Unfollow" | ||||
| msgstr "Przestań obserwować" | ||||
| 
 | ||||
| #, fuzzy | ||||
| msgid "Recently boosted" | ||||
| msgstr "Ostatnio udostępniono" | ||||
| msgstr "Ostatnio podbite" | ||||
| 
 | ||||
| msgid "One follower" | ||||
| msgid_plural "{{ count }} followers" | ||||
| @ -247,9 +245,8 @@ msgstr "Musisz się zalogować, aby zobaczyć swoje powiadomienia" | ||||
| msgid "You need to be logged in order to write a new post" | ||||
| msgstr "Musisz się zalogować, aby utworzyć wpis" | ||||
| 
 | ||||
| #, fuzzy | ||||
| msgid "You need to be logged in order to boost a post" | ||||
| msgstr "Musisz się zalogować, aby polubić wpis" | ||||
| msgstr "Musisz się zalogować, aby podbić wpis" | ||||
| 
 | ||||
| msgid "Invalid username or password" | ||||
| msgstr "Nieprawidłowa nazwa użytkownika lub hasło" | ||||
| @ -268,18 +265,17 @@ msgstr "" | ||||
| "Napisano przez {{ link_1 }}{{ url }}{{ link_2 }}{{ name | escape }}" | ||||
| "{{ link_3 }}" | ||||
| 
 | ||||
| #, fuzzy | ||||
| msgid "{{ data }} boosted your article" | ||||
| msgstr "{{ data }} skomentował Twój artykuł" | ||||
| msgstr "{{ data }} podbił(a) Twój artykuł" | ||||
| 
 | ||||
| msgid "{{ data }} started following you" | ||||
| msgstr "{{ data }} zaczął Cię obserwować" | ||||
| msgstr "{{ data }} zaczął(-ęła) Cię obserwować" | ||||
| 
 | ||||
| msgid "{{ data }} liked your article" | ||||
| msgstr "{{ data }} polubił Twój artykuł" | ||||
| msgstr "{{ data }} polubił(a) Twój artykuł" | ||||
| 
 | ||||
| msgid "{{ data }} commented your article" | ||||
| msgstr "{{ data }} skomentował Twój artykuł" | ||||
| msgstr "{{ data }} skomentował(a) Twój artykuł" | ||||
| 
 | ||||
| msgid "We couldn't find this page." | ||||
| msgstr "Nie udało się odnaleźć tej strony." | ||||
| @ -294,7 +290,7 @@ msgid "You are not author in this blog." | ||||
| msgstr "Nie jesteś autorem tego bloga." | ||||
| 
 | ||||
| msgid "{{ data }} mentioned you." | ||||
| msgstr "{{ data }} wspomniał o Tobie." | ||||
| msgstr "{{ data }} wspomniał(a) o Tobie." | ||||
| 
 | ||||
| msgid "Your comment" | ||||
| msgstr "Twój komentarz" | ||||
| @ -318,9 +314,8 @@ msgid "We need an email or a username to identify you" | ||||
| msgstr "" | ||||
| "Potrzebujemy nazwy użytkownika lub adresu e-mail, aby Cię zidentyfikować" | ||||
| 
 | ||||
| #, fuzzy | ||||
| msgid "Your password can't be empty" | ||||
| msgstr "Twój komentarz nie może być pusty" | ||||
| msgstr "Twoje hasło nie może być puste" | ||||
| 
 | ||||
| msgid "Passwords are not matching" | ||||
| msgstr "Hasła nie pasują do siebie" | ||||
| @ -361,20 +356,19 @@ msgid "Next page" | ||||
| msgstr "Następna strona" | ||||
| 
 | ||||
| msgid "{{ user }} mentioned you." | ||||
| msgstr "{{ user }} wspomniał o Tobie." | ||||
| msgstr "{{ user }} wspomniał(a) o Tobie." | ||||
| 
 | ||||
| msgid "{{ user }} commented your article." | ||||
| msgstr "{{ user }} skomentował Twój artykuł." | ||||
| msgstr "{{ user }} skomentował(a) Twój artykuł." | ||||
| 
 | ||||
| msgid "{{ user }} is now following you." | ||||
| msgstr "{{ user }} zaczął Cię obserwować." | ||||
| msgstr "{{ user }} zaczął(-ęła) Cię obserwować." | ||||
| 
 | ||||
| msgid "{{ user }} liked your article." | ||||
| msgstr "{{ user }} polubił Twój artykuł." | ||||
| msgstr "{{ user }} polubił(a) Twój artykuł." | ||||
| 
 | ||||
| #, fuzzy | ||||
| msgid "{{ user }} boosted your article." | ||||
| msgstr "{{ user }} skomentował Twój artykuł." | ||||
| msgstr "{{ user }} podbił(a) Twój artykuł." | ||||
| 
 | ||||
| msgid "Source code" | ||||
| msgstr "Kod źródłowy" | ||||
| @ -441,7 +435,7 @@ msgid "people" | ||||
| msgstr "osób" | ||||
| 
 | ||||
| msgid "Who wrote" | ||||
| msgstr "Którzy napisali" | ||||
| msgstr "Które napisały" | ||||
| 
 | ||||
| msgid "articles" | ||||
| msgstr "artykuły" | ||||
| @ -449,79 +443,83 @@ msgstr "artykuły" | ||||
| msgid "Read the detailed rules" | ||||
| msgstr "Przeczytaj szczegółowe zasady" | ||||
| 
 | ||||
| #, fuzzy | ||||
| msgid "Delete this article" | ||||
| msgstr "Najnowsze artykuły" | ||||
| msgstr "Usuń ten artykuł" | ||||
| 
 | ||||
| msgid "And connected to" | ||||
| msgstr "" | ||||
| msgstr "Połączony z" | ||||
| 
 | ||||
| #, fuzzy | ||||
| msgid "other instances" | ||||
| msgstr "O tej instancji" | ||||
| msgstr "innych instancji" | ||||
| 
 | ||||
| #, fuzzy | ||||
| msgid "Administred by" | ||||
| msgstr "Administracja" | ||||
| msgstr "Administrowany przez" | ||||
| 
 | ||||
| msgid "Runs Plume {{ version }}" | ||||
| msgstr "" | ||||
| msgstr "Działa na Plume {{ version }}" | ||||
| 
 | ||||
| #, fuzzy | ||||
| msgid "Your media" | ||||
| msgstr "Twój komentarz" | ||||
| msgstr "Twoja zawartość multimedialna" | ||||
| 
 | ||||
| msgid "Go to your gallery" | ||||
| msgstr "" | ||||
| msgstr "Przejdź do swojej galerii" | ||||
| 
 | ||||
| msgid "{{ name}}'s avatar'" | ||||
| msgstr "" | ||||
| msgstr "Awatar {{name}}" | ||||
| 
 | ||||
| msgid "Media details" | ||||
| msgstr "" | ||||
| msgstr "Szczegóły zawartości multimedialnej" | ||||
| 
 | ||||
| msgid "Go back to the gallery" | ||||
| msgstr "" | ||||
| msgstr "Powróć do galerii" | ||||
| 
 | ||||
| #, fuzzy | ||||
| msgid "Markdown code" | ||||
| msgstr "Markdown jest obsługiwany" | ||||
| msgstr "Kod Markdown" | ||||
| 
 | ||||
| msgid "Copy it in your articles to insert this media." | ||||
| msgstr "" | ||||
| msgstr "Skopiuj do swoich artykułów, aby wstawić tę zawartość multimedialną." | ||||
| 
 | ||||
| msgid "Use as avatar" | ||||
| msgstr "" | ||||
| msgstr "Użyj jako awataru" | ||||
| 
 | ||||
| msgid "Delete" | ||||
| msgstr "" | ||||
| msgstr "Usuń" | ||||
| 
 | ||||
| msgid "Upload" | ||||
| msgstr "" | ||||
| msgstr "Wyślij" | ||||
| 
 | ||||
| msgid "You don't have any media yet." | ||||
| msgstr "" | ||||
| msgstr "Nie masz żadnej zawartości multimedialnej." | ||||
| 
 | ||||
| msgid "Media upload" | ||||
| msgstr "" | ||||
| msgstr "Wysyłanie zawartości multimedialnej" | ||||
| 
 | ||||
| #, fuzzy | ||||
| msgid "Description" | ||||
| msgstr "Szczegółowy opis" | ||||
| msgstr "Opis" | ||||
| 
 | ||||
| #, fuzzy | ||||
| msgid "Content warning" | ||||
| msgstr "Zawartość" | ||||
| msgstr "Ostrzeżenie o zawartości" | ||||
| 
 | ||||
| msgid "File" | ||||
| msgstr "" | ||||
| msgstr "Plik" | ||||
| 
 | ||||
| msgid "Send" | ||||
| msgstr "" | ||||
| msgstr "Wyślij" | ||||
| 
 | ||||
| msgid "" | ||||
| "Sorry, but registrations are closed on this instance. Try to find another one" | ||||
| msgstr "" | ||||
| "Przepraszamy, rejestracja jest zamknięta na tej instancji. Spróbuj znaleźć " | ||||
| "inną" | ||||
| 
 | ||||
| msgid "Subtitle" | ||||
| msgstr "Podtytuł" | ||||
| 
 | ||||
| msgid "Login to like" | ||||
| msgstr "Zaloguj się aby polubić" | ||||
| 
 | ||||
| msgid "Login to boost" | ||||
| msgstr "Zaloguj się aby podbić" | ||||
| 
 | ||||
| #~ msgid "One reshare" | ||||
| #~ msgid_plural "{{ count }} reshares" | ||||
|  | ||||
| @ -486,3 +486,12 @@ msgstr "" | ||||
| 
 | ||||
| msgid "Sorry, but registrations are closed on this instance. Try to find another one" | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "Subtitle" | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "Login to like" | ||||
| msgstr "" | ||||
| 
 | ||||
| msgid "Login to boost" | ||||
| msgstr "" | ||||
|  | ||||
| @ -55,6 +55,10 @@ pub trait Inbox { | ||||
|                             "Announce" => { | ||||
|                                 Reshare::delete_id(act.undo_props.object_object::<Announce>()?.object_props.id_string()?, conn); | ||||
|                                 Ok(()) | ||||
|                             }, | ||||
|                             "Follow" => { | ||||
|                                 Follow::delete_id(act.undo_props.object_object::<Like>()?.object_props.id_string()?, conn); | ||||
|                                 Ok(()) | ||||
|                             } | ||||
|                             _ => Err(InboxError::CantUndo)? | ||||
|                         } | ||||
|  | ||||
| @ -57,7 +57,8 @@ fn details_response(blog: String, slug: String, conn: DbConn, user: Option<User> | ||||
|                 "date": &post.creation_date.timestamp(), | ||||
|                 "previous": query.and_then(|q| q.responding_to.map(|r| Comment::get(&*conn, r).expect("Error retrieving previous comment").to_json(&*conn, &vec![]))), | ||||
|                 "user_fqn": user.clone().map(|u| u.get_fqn(&*conn)).unwrap_or(String::new()), | ||||
|                 "is_author": user.map(|u| post.get_authors(&*conn).into_iter().any(|a| u.id == a.id)).unwrap_or(false) | ||||
|                 "is_author": user.clone().map(|u| post.get_authors(&*conn).into_iter().any(|a| u.id == a.id)).unwrap_or(false), | ||||
|                 "is_following": user.map(|u| u.is_following(&*conn, post.get_authors(&*conn)[0].id)).unwrap_or(false) | ||||
|             })) | ||||
|         }) | ||||
|     }) | ||||
| @ -98,6 +99,7 @@ fn new(blog: String, user: User, conn: DbConn) -> Template { | ||||
| struct NewPostForm { | ||||
|     #[validate(custom(function = "valid_slug", message = "Invalid title"))] | ||||
|     pub title: String, | ||||
|     pub subtitle: String, | ||||
|     pub content: String, | ||||
|     pub license: String | ||||
| } | ||||
| @ -150,7 +152,8 @@ fn create(blog_name: String, data: LenientForm<NewPostForm>, user: User, conn: D | ||||
|                     Instance::get_local(&*conn).map(|i| i.default_license).unwrap_or(String::from("CC-0")) | ||||
|                 }, | ||||
|                 ap_url: "".to_string(), | ||||
|                 creation_date: None | ||||
|                 creation_date: None, | ||||
|                 subtitle: form.subtitle.clone() | ||||
|             }); | ||||
|             let post = post.update_ap_url(&*conn); | ||||
|             PostAuthor::insert(&*conn, NewPostAuthor { | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| use activitypub::{ | ||||
|     activity::{Create, Follow}, | ||||
|     activity::Create, | ||||
|     collection::OrderedCollection, | ||||
|     object::Article | ||||
| }; | ||||
| @ -16,7 +16,7 @@ use workerpool::thunk::*; | ||||
| 
 | ||||
| use plume_common::activity_pub::{ | ||||
|     ActivityStream, broadcast, Id, IntoId, ApRequest, | ||||
|     inbox::{FromActivity, Notify} | ||||
|     inbox::{FromActivity, Notify, Deletable} | ||||
| }; | ||||
| use plume_common::utils; | ||||
| use plume_models::{ | ||||
| @ -71,7 +71,8 @@ fn details(name: String, conn: DbConn, account: Option<User>, worker: Worker, fe | ||||
|                         .unwrap_or_else(|| User::fetch_from_url(&*fecth_followers_conn, user_id).expect("Couldn't fetch follower")); | ||||
|                     follows::Follow::insert(&*fecth_followers_conn, follows::NewFollow { | ||||
|                         follower_id: follower.id, | ||||
|                         following_id: user_clone.id | ||||
|                         following_id: user_clone.id, | ||||
|                         ap_url: format!("{}/follow/{}", follower.ap_url, user_clone.ap_url), | ||||
|                     }); | ||||
|                 } | ||||
|             })); | ||||
| @ -116,20 +117,20 @@ fn dashboard_auth() -> Flash<Redirect> { | ||||
| #[get("/@/<name>/follow")] | ||||
| fn follow(name: String, conn: DbConn, user: User, worker: Worker) -> Redirect { | ||||
|     let target = User::find_by_fqn(&*conn, name.clone()).unwrap(); | ||||
|     let f = follows::Follow::insert(&*conn, follows::NewFollow { | ||||
|         follower_id: user.id, | ||||
|         following_id: target.id | ||||
|     }); | ||||
|     f.notify(&*conn); | ||||
|     if let Some(follow) = follows::Follow::find(&*conn, user.id, target.id) { | ||||
|         let delete_act = follow.delete(&*conn); | ||||
|         worker.execute(Thunk::of(move || broadcast(&user, delete_act, vec![target]))); | ||||
|     } else { | ||||
|         let f = follows::Follow::insert(&*conn, follows::NewFollow { | ||||
|             follower_id: user.id, | ||||
|             following_id: target.id, | ||||
|             ap_url: format!("{}/follow/{}", user.ap_url, target.ap_url), | ||||
|         }); | ||||
|         f.notify(&*conn); | ||||
| 
 | ||||
|     let mut act = Follow::default(); | ||||
|     act.follow_props.set_actor_link::<Id>(user.clone().into_id()).unwrap(); | ||||
|     act.follow_props.set_object_object(user.into_activity(&*conn)).unwrap(); | ||||
|     act.object_props.set_id_string(format!("{}/follow/{}", user.ap_url, target.ap_url)).unwrap(); | ||||
|     act.object_props.set_to_link(target.clone().into_id()).expect("New Follow error while setting 'to'"); | ||||
|     act.object_props.set_cc_link_vec::<Id>(vec![]).expect("New Follow error while setting 'cc'"); | ||||
| 
 | ||||
|     worker.execute(Thunk::of(move || broadcast(&user, act, vec![target]))); | ||||
|         let act = f.into_activity(&*conn); | ||||
|         worker.execute(Thunk::of(move || broadcast(&user, act, vec![target]))); | ||||
|     } | ||||
|     Redirect::to(uri!(details: name = name)) | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -192,9 +192,18 @@ | ||||
|  } | ||||
| 
 | ||||
|  article img { | ||||
|  	display: block; | ||||
|  	margin: 3em auto; | ||||
|  	max-width: 100%; | ||||
|  } | ||||
| 
 | ||||
|  article pre { | ||||
|  	padding: 1em; | ||||
|  	background: #DADADA; | ||||
|  	overflow: auto; | ||||
|  	border-radius: 5px; | ||||
|  } | ||||
| 
 | ||||
|  /* Article.Meta */ | ||||
| 
 | ||||
|  main .article-meta, main .article-meta button { | ||||
| @ -235,8 +244,8 @@ | ||||
|  	font-size: 1.5em; | ||||
|  } | ||||
| 
 | ||||
|  main .article-meta .likes button, | ||||
|  main .article-meta .reshares button { | ||||
|  main .article-meta .likes .action, | ||||
|  main .article-meta .reshares .action { | ||||
|  	display: flex; | ||||
|  	flex-direction: column; | ||||
|  	align-items: center; | ||||
| @ -246,15 +255,16 @@ | ||||
|  	background: none; | ||||
|  	color: #242424; | ||||
|  	border: none; | ||||
|  	font-size: 1.1em; | ||||
|  } | ||||
| 
 | ||||
|  main .article-meta .likes > p, | ||||
|  main .article-meta .likes button:hover { color: #E92F2F; } | ||||
|  main .article-meta .likes .action:hover { color: #E92F2F; } | ||||
|  main .article-meta .reshares > p, | ||||
|  main .article-meta .reshares button:hover { color: #7765E3; } | ||||
|  main .article-meta .reshares .action:hover { color: #7765E3; } | ||||
| 
 | ||||
|  main .article-meta .likes button svg.feather, | ||||
|  main .article-meta .reshares button i { | ||||
|  main .article-meta .likes .action svg.feather, | ||||
|  main .article-meta .reshares .action i { | ||||
|  	transition: background 0.1s ease-in; | ||||
|  	display: flex; | ||||
|  	align-items: center; | ||||
| @ -267,39 +277,39 @@ | ||||
|  	border-radius: 50%; | ||||
|  } | ||||
| 
 | ||||
|  main .article-meta .likes button svg.feather { | ||||
|  main .article-meta .likes .action svg.feather { | ||||
|  	padding: 0.7em; | ||||
|  	box-sizing: border-box; | ||||
|  	color: #E92F2F; | ||||
|  	fill: none; | ||||
|  	border: solid #E92F2F thin; | ||||
|  } | ||||
|  main .article-meta .likes button:hover svg.feather { | ||||
|  main .article-meta .likes .action:hover svg.feather { | ||||
|  	background: rgba(233, 47, 47, 0.15); | ||||
|  } | ||||
| 
 | ||||
|  main .article-meta .reshares button i { | ||||
|  main .article-meta .reshares .action i { | ||||
|  	color: #7765E3; | ||||
|  	border: solid #7765E3 thin; | ||||
|  	font-weight: 600; | ||||
|  } | ||||
|  main .article-meta .reshares button:hover i { | ||||
|  main .article-meta .reshares .action:hover i { | ||||
|  	background: rgba(119, 101, 227, 0.15); | ||||
|  } | ||||
| 
 | ||||
|  main .article-meta .likes button.liked svg.feather { background: #E92F2F; fill: currentColor; } | ||||
|  main .article-meta .likes button.liked:hover svg.feather { | ||||
|  main .article-meta .likes .action.liked svg.feather { background: #E92F2F; fill: currentColor; } | ||||
|  main .article-meta .likes .action.liked:hover svg.feather { | ||||
|  	background: rgba(233, 47, 47, 0.25); | ||||
|  	color: #E92F2F; | ||||
|  } | ||||
|  main .article-meta .reshares button.reshared i { background: #7765E3; } | ||||
|  main .article-meta .reshares button.reshared:hover i { | ||||
|  main .article-meta .reshares .action.reshared i { background: #7765E3; } | ||||
|  main .article-meta .reshares .action.reshared:hover i { | ||||
|  	background: rgba(119, 101, 227, 0.25); | ||||
|  	color: #7765E3; | ||||
|  } | ||||
| 
 | ||||
|  main .article-meta .likes button.liked svg.feather, | ||||
|  main .article-meta .reshares button.reshared i { | ||||
|  main .article-meta .likes .action.liked svg.feather, | ||||
|  main .article-meta .reshares .action.reshared i { | ||||
|  	color: #F4F4F4; | ||||
|  	font-weight: 900; | ||||
|  } | ||||
| @ -796,5 +806,5 @@ | ||||
|  } | ||||
| 
 | ||||
|  .avatar.padded { | ||||
|  	margin-right: 1em; | ||||
|  	margin-right: 2rem; | ||||
|  } | ||||
|  | ||||
| @ -30,7 +30,7 @@ | ||||
|                             <span class="mobile-label">{{ "Notifications" | _ }}</span> | ||||
|                         </a> | ||||
|                         <a href="/logout"> | ||||
|                             <i class="icon icon-log-out aria-label="{{ "Log Out" | _ }}"></i> | ||||
|                             <i class="icon icon-log-out" aria-label="{{ "Log Out" | _ }}"></i> | ||||
|                             <span class="mobile-label">{{ "Log Out" | _ }}</span> | ||||
|                         </a> | ||||
|                         <a href="/me"> | ||||
|  | ||||
| @ -2,7 +2,13 @@ | ||||
|     <div class="card"> | ||||
|         <h3><a href="{{ article.url }}">{{ article.post.title }}</a></h3> | ||||
|         <main | ||||
|             <p>{{ article.post.content | safe | striptags | truncate(length=200) }}</p> | ||||
|             <p> | ||||
|                 {% if article.post.subtitle | length > 0 %} | ||||
|                     {{ article.post.subtitle }} | ||||
|                 {% else %} | ||||
|                     {{ article.post.content | safe | striptags | truncate(length=200) }} | ||||
|                 {% endif %} | ||||
|             </p> | ||||
|         </main> | ||||
|         <p class="author"> | ||||
|         	{{ "By {{ link_1 }}{{ link_2 }}{{ link_3 }}{{ name | escape }}{{ link_4 }}" | _( | ||||
|  | ||||
| @ -11,6 +11,7 @@ | ||||
| 
 | ||||
| {% block content %} | ||||
|     <h1 class="article">{{ article.post.title }}</h1> | ||||
|     <h2 class="article">{{ article.post.subtitle }}</h2> | ||||
|     <p class="article-info"> | ||||
|         <span class="author">{{ "Written by {{ link_1 }}{{ url }}{{ link_2 }}{{ name | escape }}{{ link_3 }}" | _( | ||||
|             link_1='<a href="/@/', | ||||
| @ -33,6 +34,20 @@ | ||||
| 
 | ||||
|     <div class="article-meta"> | ||||
|         <p>{{ "This article is under the {{ license }} license." | _(license=article.post.license) }}</p> | ||||
|         <div class="flex"> | ||||
|             <img src="{{ author.avatar }}" alt="{{ author.name }}" class="avatar medium padded"> | ||||
|             <div class="grow"> | ||||
|                 <h2><a href="/@/{{ author.fqn }}">{{ author.name }}</a></h2> | ||||
|                 <p>{{ author.summary | safe }}</h2> | ||||
|             </div> | ||||
|             <a href="/@/{{ author.fqn }}/follow" class="button"> | ||||
|                 {% if is_following %} | ||||
|                     {{ "Unfollow" | _ }} | ||||
|                 {% else %} | ||||
|                     {{ "Follow" | _ }} | ||||
|                 {% endif %} | ||||
|             </a> | ||||
|         </div> | ||||
| 
 | ||||
|         {% if account %} | ||||
|             <div class="actions"> | ||||
| @ -40,23 +55,34 @@ | ||||
|                     <p aria-label="{{ "{{ count }} likes" | _n(singular="One like", count=n_likes) }}" title="{{ "{{ count }} likes" | _n(singular="One like", count=n_likes) }}">{{ n_likes }}</p> | ||||
| 
 | ||||
|                     {% if has_liked %} | ||||
|                         <button type="submit" class="liked">{{ macros::feather(name="heart") }}{{ "I don't like this anymore" | _ }}</button> | ||||
|                         <button type="submit" class="action liked">{{ macros::feather(name="heart") }}{{ "I don't like this anymore" | _ }}</button> | ||||
|                     {% else %} | ||||
|                         <button type="submit">{{ macros::feather(name="heart") }}{{ "Add yours" | _ }}</button> | ||||
|                         <button type="submit" class="action">{{ macros::feather(name="heart") }}{{ "Add yours" | _ }}</button> | ||||
|                     {% endif %} | ||||
|                 </form> | ||||
|                 <form class="reshares" action="{{ article.url }}reshare" method="POST"> | ||||
|                     <p aria-label="{{ "{{ count }} Boosts" | _n(singular="One Boost", count=n_reshares) }}" title="{{ "{{ count }} Boosts" | _n(singular="One Boost", count=n_reshares) }}">{{ n_reshares }}</p> | ||||
| 
 | ||||
|                     {% if has_reshared %} | ||||
|                         <button type="submit" class="reshared"><i class="icon icon-repeat"></i>{{ "I don't want to boost this anymore" | _ }}</button> | ||||
|                         <button type="submit" class="action reshared"><i class="icon icon-repeat"></i>{{ "I don't want to boost this anymore" | _ }}</button> | ||||
|                     {% else %} | ||||
|                         <button type="submit"><i class="icon icon-repeat"></i>{{ "Boost" | _ }}</button> | ||||
|                         <button type="submit" class="action"><i class="icon icon-repeat"></i>{{ "Boost" | _ }}</button> | ||||
|                     {% endif %} | ||||
|                 </form> | ||||
|             </div> | ||||
|         {% else %} | ||||
|             <p class="center">{{ "Login or use your Fediverse account to interact with this article" | _ }}</p> | ||||
|             <div class="actions"> | ||||
|                 <div class="likes"> | ||||
|                     <p aria-label="{{ "{{ count }} likes" | _n(singular="One like", count=n_likes) }}" title="{{ "{{ count }} likes" | _n(singular="One like", count=n_likes) }}">{{ n_likes }}</p> | ||||
|                     <a href="/login?m=Login%20to%20like" class="action">{{ macros::feather(name="heart") }}{{ "Add yours" | _ }}</a> | ||||
|                 </div> | ||||
| 
 | ||||
|                 <div class="reshares"> | ||||
|                     <p aria-label="{{ "{{ count }} Boosts" | _n(singular="One Boost", count=n_reshares) }}" title="{{ "{{ count }} Boosts" | _n(singular="One Boost", count=n_reshares) }}">{{ n_reshares }}</p> | ||||
|                     <a href="/login?m=Login%20to%20boost" class="action"><i class="icon icon-repeat"></i>{{ "Boost" | _ }}</a> | ||||
|                 </div> | ||||
|             </div> | ||||
|         {% endif %} | ||||
| 
 | ||||
|         <div class="comments"> | ||||
|  | ||||
| @ -9,6 +9,7 @@ | ||||
| <h1>{{ "Create a post" | _ }}</h1> | ||||
| <form class="new-post" method="post"> | ||||
|     {{ macros::input(name="title", label="Title", errors=errors, form=form, props="required") }} | ||||
|     {{ macros::input(name="subtitle", label="Subtitle", errors=errors, form=form, optional=true) }} | ||||
| 
 | ||||
|     {% if errors is defined and errors.content %} | ||||
|         {% for err in errors.content %} | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user