Refactor notifications
This commit is contained in:
		
							parent
							
								
									44172b67d5
								
							
						
					
					
						commit
						c87d490664
					
				| @ -0,0 +1,8 @@ | |||||||
|  | -- This file should undo anything in `up.sql` | ||||||
|  | ALTER TABLE notifications ADD COLUMN title VARCHAR NOT NULL; | ||||||
|  | ALTER TABLE notifications ADD COLUMN content TEXT; | ||||||
|  | ALTER TABLE notifications ADD COLUMN link VARCHAR; | ||||||
|  | ALTER TABLE notifications ADD COLUMN data VARCHAR; | ||||||
|  | 
 | ||||||
|  | ALTER TABLE notifications DROP COLUMN kind; | ||||||
|  | ALTER TABLE notifications DROP COLUMN object_id; | ||||||
| @ -0,0 +1,8 @@ | |||||||
|  | -- Your SQL goes here | ||||||
|  | ALTER TABLE notifications DROP COLUMN title; | ||||||
|  | ALTER TABLE notifications DROP COLUMN content; | ||||||
|  | ALTER TABLE notifications DROP COLUMN link; | ||||||
|  | ALTER TABLE notifications DROP COLUMN data; | ||||||
|  | 
 | ||||||
|  | ALTER TABLE notifications ADD COLUMN kind VARCHAR NOT NULL DEFAULT 'unknown'; | ||||||
|  | ALTER TABLE notifications ADD COLUMN object_id INTEGER NOT NULL DEFAULT 0; | ||||||
| @ -123,10 +123,8 @@ impl Notify<PgConnection> for Comment { | |||||||
|     fn notify(&self, conn: &PgConnection) { |     fn notify(&self, conn: &PgConnection) { | ||||||
|         for author in self.get_post(conn).get_authors(conn) { |         for author in self.get_post(conn).get_authors(conn) { | ||||||
|             Notification::insert(conn, NewNotification { |             Notification::insert(conn, NewNotification { | ||||||
|                 title: "{{ data }} commented your article".to_string(), |                 kind: notification_kind::COMMENT.to_string(), | ||||||
|                 data: Some(self.get_author(conn).display_name.clone()), |                 object_id: self.id, | ||||||
|                 content: Some(self.get_post(conn).title), |  | ||||||
|                 link: self.ap_url.clone(), |  | ||||||
|                 user_id: author.id |                 user_id: author.id | ||||||
|             }); |             }); | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -70,12 +70,9 @@ impl FromActivity<FollowAct, PgConnection> for Follow { | |||||||
| 
 | 
 | ||||||
| impl Notify<PgConnection> for Follow { | impl Notify<PgConnection> for Follow { | ||||||
|     fn notify(&self, conn: &PgConnection) { |     fn notify(&self, conn: &PgConnection) { | ||||||
|         let follower = User::get(conn, self.follower_id).unwrap(); |  | ||||||
|         Notification::insert(conn, NewNotification { |         Notification::insert(conn, NewNotification { | ||||||
|             title: "{{ data }} started following you".to_string(), |             kind: notification_kind::FOLLOW.to_string(), | ||||||
|             data: Some(follower.display_name.clone()), |             object_id: self.id, | ||||||
|             content: None, |  | ||||||
|             link: Some(follower.ap_url), |  | ||||||
|             user_id: self.following_id |             user_id: self.following_id | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -89,15 +89,11 @@ impl FromActivity<activity::Like, PgConnection> for Like { | |||||||
| 
 | 
 | ||||||
| impl Notify<PgConnection> for Like { | impl Notify<PgConnection> for Like { | ||||||
|     fn notify(&self, conn: &PgConnection) { |     fn notify(&self, conn: &PgConnection) { | ||||||
|         let liker = User::get(conn, self.user_id).unwrap(); |  | ||||||
|         let post = Post::get(conn, self.post_id).unwrap(); |         let post = Post::get(conn, self.post_id).unwrap(); | ||||||
|         for author in post.get_authors(conn) { |         for author in post.get_authors(conn) { | ||||||
|             let post = post.clone(); |  | ||||||
|             Notification::insert(conn, NewNotification { |             Notification::insert(conn, NewNotification { | ||||||
|                 title: "{{ data }} liked your article".to_string(), |                 kind: notification_kind::LIKE.to_string(), | ||||||
|                 data: Some(liker.display_name.clone()), |                 object_id: self.id, | ||||||
|                 content: Some(post.title), |  | ||||||
|                 link: Some(post.ap_url), |  | ||||||
|                 user_id: author.id |                 user_id: author.id | ||||||
|             }); |             }); | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -46,6 +46,13 @@ impl Mention { | |||||||
|         self.comment_id.and_then(|id| Comment::get(conn, id)) |         self.comment_id.and_then(|id| Comment::get(conn, id)) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     pub fn get_user(&self, conn: &PgConnection) -> Option<User> { | ||||||
|  |         match self.get_post(conn) { | ||||||
|  |             Some(p) => p.get_authors(conn).into_iter().next(), | ||||||
|  |             None => self.get_comment(conn).map(|c| c.get_author(conn)) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     pub fn build_activity(conn: &PgConnection, ment: String) -> link::Mention { |     pub fn build_activity(conn: &PgConnection, ment: String) -> link::Mention { | ||||||
|         let user = User::find_by_fqn(conn, ment.clone()); |         let user = User::find_by_fqn(conn, ment.clone()); | ||||||
|         let mut mention = link::Mention::default(); |         let mut mention = link::Mention::default(); | ||||||
| @ -94,16 +101,10 @@ impl Mention { | |||||||
| 
 | 
 | ||||||
| impl Notify<PgConnection> for Mention { | impl Notify<PgConnection> for Mention { | ||||||
|     fn notify(&self, conn: &PgConnection) { |     fn notify(&self, conn: &PgConnection) { | ||||||
|         let author = self.get_comment(conn) |  | ||||||
|             .map(|c| c.get_author(conn).display_name.clone()) |  | ||||||
|             .unwrap_or_else(|| self.get_post(conn).unwrap().get_authors(conn)[0].display_name.clone()); |  | ||||||
| 
 |  | ||||||
|         self.get_mentioned(conn).map(|m| { |         self.get_mentioned(conn).map(|m| { | ||||||
|             Notification::insert(conn, NewNotification { |             Notification::insert(conn, NewNotification { | ||||||
|                 title: "{{ data }} mentioned you.".to_string(), |                 kind: notification_kind::MENTION.to_string(), | ||||||
|                 data: Some(author), |                 object_id: self.id, | ||||||
|                 content: None, |  | ||||||
|                 link: Some(self.get_post(conn).map(|p| p.ap_url).unwrap_or_else(|| self.get_comment(conn).unwrap().ap_url.unwrap_or(String::new()))), |  | ||||||
|                 user_id: m.id |                 user_id: m.id | ||||||
|             }); |             }); | ||||||
|         }); |         }); | ||||||
|  | |||||||
| @ -1,28 +1,39 @@ | |||||||
| use chrono::NaiveDateTime; | use chrono::NaiveDateTime; | ||||||
| use diesel::{self, PgConnection, RunQueryDsl, QueryDsl, ExpressionMethods}; | use diesel::{self, PgConnection, RunQueryDsl, QueryDsl, ExpressionMethods}; | ||||||
|  | use serde_json; | ||||||
| 
 | 
 | ||||||
|  | use comments::Comment; | ||||||
|  | use follows::Follow; | ||||||
|  | use likes::Like; | ||||||
|  | use mentions::Mention; | ||||||
|  | use posts::Post; | ||||||
|  | use reshares::Reshare; | ||||||
| use users::User; | use users::User; | ||||||
| use schema::notifications; | use schema::notifications; | ||||||
| 
 | 
 | ||||||
|  | pub mod notification_kind { | ||||||
|  |     pub const COMMENT: &'static str = "COMMENT"; | ||||||
|  |     pub const FOLLOW: &'static str = "FOLLOW"; | ||||||
|  |     pub const LIKE: &'static str = "LIKE"; | ||||||
|  |     pub const MENTION: &'static str = "MENTION"; | ||||||
|  |     pub const RESHARE: &'static str = "RESHARE"; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| #[derive(Queryable, Identifiable, Serialize)] | #[derive(Queryable, Identifiable, Serialize)] | ||||||
| pub struct Notification { | pub struct Notification { | ||||||
|     pub id: i32, |     pub id: i32, | ||||||
|     pub title: String, |  | ||||||
|     pub content: Option<String>, |  | ||||||
|     pub link: Option<String>, |  | ||||||
|     pub user_id: i32, |     pub user_id: i32, | ||||||
|     pub creation_date: NaiveDateTime, |     pub creation_date: NaiveDateTime, | ||||||
|     pub data: Option<String> |     pub kind: String, | ||||||
|  |     pub object_id: i32 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[derive(Insertable)] | #[derive(Insertable)] | ||||||
| #[table_name = "notifications"] | #[table_name = "notifications"] | ||||||
| pub struct NewNotification { | pub struct NewNotification { | ||||||
|     pub title: String, |  | ||||||
|     pub content: Option<String>, |  | ||||||
|     pub link: Option<String>, |  | ||||||
|     pub user_id: i32, |     pub user_id: i32, | ||||||
|     pub data: Option<String> |     pub kind: String, | ||||||
|  |     pub object_id: i32 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl Notification { | impl Notification { | ||||||
| @ -44,4 +55,47 @@ impl Notification { | |||||||
|             .load::<Notification>(conn) |             .load::<Notification>(conn) | ||||||
|             .expect("Couldn't load user notifications page") |             .expect("Couldn't load user notifications page") | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     pub fn to_json(&self, conn: &PgConnection) -> serde_json::Value { | ||||||
|  |         let mut json = json!(self); | ||||||
|  |         json["object"] = json!(match self.kind.as_ref() { | ||||||
|  |             notification_kind::COMMENT => Comment::get(conn, self.object_id).map(|comment| | ||||||
|  |                 json!({ | ||||||
|  |                     "post": comment.get_post(conn).to_json(conn), | ||||||
|  |                     "user": comment.get_author(conn).to_json(conn), | ||||||
|  |                     "id": comment.id | ||||||
|  |                 }) | ||||||
|  |             ), | ||||||
|  |             notification_kind::FOLLOW => Follow::get(conn, self.object_id).map(|follow| | ||||||
|  |                 json!({ | ||||||
|  |                     "follower": User::get(conn, follow.follower_id).map(|u| u.to_json(conn)) | ||||||
|  |                 }) | ||||||
|  |             ), | ||||||
|  |             notification_kind::LIKE => Like::get(conn, self.object_id).map(|like| | ||||||
|  |                 json!({ | ||||||
|  |                     "post": Post::get(conn, like.post_id).map(|p| p.to_json(conn)), | ||||||
|  |                     "user": User::get(conn, like.user_id).map(|u| u.to_json(conn)) | ||||||
|  |                 }) | ||||||
|  |             ), | ||||||
|  |             notification_kind::MENTION => Mention::get(conn, self.object_id).map(|mention| | ||||||
|  |                 json!({ | ||||||
|  |                     "user": mention.get_user(conn).map(|u| u.to_json(conn)), | ||||||
|  |                     "url": mention.get_post(conn).map(|p| p.to_json(conn)["url"].clone()) | ||||||
|  |                         .unwrap_or_else(|| { | ||||||
|  |                             let comment = mention.get_comment(conn).expect("No comment nor post for mention"); | ||||||
|  |                             let post = comment.get_post(conn).to_json(conn); | ||||||
|  |                             json!(format!("{}#comment-{}", post["url"].as_str().unwrap(), comment.id)) | ||||||
|  |                         }) | ||||||
|  |                 }) | ||||||
|  |             ), | ||||||
|  |             notification_kind::RESHARE => Reshare::get(conn, self.object_id).map(|reshare| | ||||||
|  |                 json!({ | ||||||
|  |                     "post": reshare.get_post(conn).map(|p| p.to_json(conn)), | ||||||
|  |                     "user": reshare.get_user(conn).map(|u| u.to_json(conn)) | ||||||
|  |                 }) | ||||||
|  |             ), | ||||||
|  |             _ => Some(json!({})) | ||||||
|  |         }); | ||||||
|  |         json | ||||||
|  |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -5,7 +5,7 @@ use diesel::{self, PgConnection, QueryDsl, RunQueryDsl, ExpressionMethods}; | |||||||
| use plume_common::activity_pub::{Id, IntoId, inbox::{FromActivity, Notify, Deletable}, PUBLIC_VISIBILTY}; | use plume_common::activity_pub::{Id, IntoId, inbox::{FromActivity, Notify, Deletable}, PUBLIC_VISIBILTY}; | ||||||
| use notifications::*; | use notifications::*; | ||||||
| use posts::Post; | use posts::Post; | ||||||
| use  users::User; | use users::User; | ||||||
| use schema::reshares; | use schema::reshares; | ||||||
| 
 | 
 | ||||||
| #[derive(Serialize, Deserialize, Queryable, Identifiable)] | #[derive(Serialize, Deserialize, Queryable, Identifiable)] | ||||||
| @ -55,6 +55,10 @@ impl Reshare { | |||||||
|         Post::get(conn, self.post_id) |         Post::get(conn, self.post_id) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     pub fn get_user(&self, conn: &PgConnection) -> Option<User> { | ||||||
|  |         User::get(conn, self.user_id) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     pub fn delete(&self, conn: &PgConnection) -> Undo { |     pub fn delete(&self, conn: &PgConnection) -> Undo { | ||||||
|         diesel::delete(self).execute(conn).unwrap(); |         diesel::delete(self).execute(conn).unwrap(); | ||||||
| 
 | 
 | ||||||
| @ -96,15 +100,11 @@ impl FromActivity<Announce, PgConnection> for Reshare { | |||||||
| 
 | 
 | ||||||
| impl Notify<PgConnection> for Reshare { | impl Notify<PgConnection> for Reshare { | ||||||
|     fn notify(&self, conn: &PgConnection) { |     fn notify(&self, conn: &PgConnection) { | ||||||
|         let actor = User::get(conn, self.user_id).unwrap(); |  | ||||||
|         let post = self.get_post(conn).unwrap(); |         let post = self.get_post(conn).unwrap(); | ||||||
|         for author in post.get_authors(conn) { |         for author in post.get_authors(conn) { | ||||||
|             let post = post.clone(); |  | ||||||
|             Notification::insert(conn, NewNotification { |             Notification::insert(conn, NewNotification { | ||||||
|                 title: "{{ data }} reshared your article".to_string(), |                 kind: notification_kind::RESHARE.to_string(), | ||||||
|                 data: Some(actor.display_name.clone()), |                 object_id: self.id, | ||||||
|                 content: Some(post.title), |  | ||||||
|                 link: Some(post.ap_url), |  | ||||||
|                 user_id: author.id |                 user_id: author.id | ||||||
|             }); |             }); | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -79,12 +79,10 @@ table! { | |||||||
| table! { | table! { | ||||||
|     notifications (id) { |     notifications (id) { | ||||||
|         id -> Int4, |         id -> Int4, | ||||||
|         title -> Varchar, |  | ||||||
|         content -> Nullable<Text>, |  | ||||||
|         link -> Nullable<Varchar>, |  | ||||||
|         user_id -> Int4, |         user_id -> Int4, | ||||||
|         creation_date -> Timestamp, |         creation_date -> Timestamp, | ||||||
|         data -> Nullable<Varchar>, |         kind -> Varchar, | ||||||
|  |         object_id -> Int4, | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										15
									
								
								po/plume.pot
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								po/plume.pot
									
									
									
									
									
								
							| @ -336,3 +336,18 @@ msgstr "" | |||||||
| 
 | 
 | ||||||
| msgid "Next page" | msgid "Next page" | ||||||
| msgstr "" | msgstr "" | ||||||
|  | 
 | ||||||
|  | msgid "{{ user }} mentioned you." | ||||||
|  | msgstr "" | ||||||
|  | 
 | ||||||
|  | msgid "{{ user }} commented your article." | ||||||
|  | msgstr "" | ||||||
|  | 
 | ||||||
|  | msgid "{{ user }} is now following you." | ||||||
|  | msgstr "" | ||||||
|  | 
 | ||||||
|  | msgid "{{ user }} liked your article." | ||||||
|  | msgstr "" | ||||||
|  | 
 | ||||||
|  | msgstr "{{ user }} reshare your article." | ||||||
|  | msgid "" | ||||||
|  | |||||||
| @ -9,7 +9,7 @@ use routes::Page; | |||||||
| fn paginated_notifications(conn: DbConn, user: User, page: Page) -> Template { | fn paginated_notifications(conn: DbConn, user: User, page: Page) -> Template { | ||||||
|     Template::render("notifications/index", json!({ |     Template::render("notifications/index", json!({ | ||||||
|         "account": user, |         "account": user, | ||||||
|         "notifications": Notification::page_for_user(&*conn, &user, page.limits()), |         "notifications": Notification::page_for_user(&*conn, &user, page.limits()).into_iter().map(|n| n.to_json(&*conn)).collect::<Vec<_>>(), | ||||||
|         "page": page.page, |         "page": page.page, | ||||||
|         "n_pages": Page::total(Notification::find_for_user(&*conn, &user).len() as i32) |         "n_pages": Page::total(Notification::find_for_user(&*conn, &user).len() as i32) | ||||||
|     })) |     })) | ||||||
|  | |||||||
| @ -10,9 +10,34 @@ | |||||||
|     <div class="list"> |     <div class="list"> | ||||||
|         {% for notification in notifications %} |         {% for notification in notifications %} | ||||||
|             <div class="card"> |             <div class="card"> | ||||||
|                 <h3><a href="{% if notification.link %}{{ notification.link }}/{% else %}#{% endif %}">{{ notification.title | _(data=notification.data) }}</a></h3> |                 {% if notification.kind == "COMMENT" %} | ||||||
|                 {% if notification.content %} |                     <h3><a href="{{ notification.object.post.url }}#comment-{{ notification.object.id }}"> | ||||||
|                     <p>{{ notification.content }}</p> |                         {{ "{{ user }} commented your article." | _(user=notification.object.user.display_name) }} | ||||||
|  |                     </a></h3> | ||||||
|  |                     <p><a href="{{ notification.object.post.url }}">{{ notification.object.post.title }}</a></p> | ||||||
|  | 
 | ||||||
|  |                 {% elif notification.kind == "FOLLOW" %} | ||||||
|  |                     <h3><a href="/@/{{ notification.object.follower.fqn }}/"> | ||||||
|  |                         {{ "{{ user }} is now following you." | _(user=notification.object.follower.display_name) }} | ||||||
|  |                     </a></h3> | ||||||
|  | 
 | ||||||
|  |                 {% elif notification.kind == "LIKE" %} | ||||||
|  |                     <h3> | ||||||
|  |                         {{ "{{ user }} liked your article." | _(user=notification.object.user.display_name) }} | ||||||
|  |                     </h3> | ||||||
|  |                     <p><a href="{{ notification.object.post.url }}">{{ notification.object.post.title }}</a></p> | ||||||
|  | 
 | ||||||
|  |                 {% elif notification.kind == "MENTION" %} | ||||||
|  |                     <h3><a href="{{ notification.object.url }}"> | ||||||
|  |                         {{ "{{ user }} mentioned you." | _(user=notification.object.user.display_name) }} | ||||||
|  |                     </a></h3> | ||||||
|  | 
 | ||||||
|  |                 {% elif notification.kind == "RESHARE" %} | ||||||
|  |                     <h3> | ||||||
|  |                         {{ "{{ user }} reshare your article." | _(user=notification.object.user.display_name) }} | ||||||
|  |                     </h3> | ||||||
|  |                     <p><a href="{{ notification.object.post.url }}">{{ notification.object.post.title }}</a></p> | ||||||
|  | 
 | ||||||
|                 {% endif %} |                 {% endif %} | ||||||
|             </div> |             </div> | ||||||
|         {% endfor %} |         {% endfor %} | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user