]> Untitled Git - lemmy.git/commitdiff
View where a URL has been cross-posted to in the past
authorDessalines <tyhou13@gmx.com>
Thu, 22 Aug 2019 05:17:15 +0000 (22:17 -0700)
committerDessalines <tyhou13@gmx.com>
Thu, 22 Aug 2019 05:17:15 +0000 (22:17 -0700)
- This shows when creating a post, or when viewing a post.
- Fixes #131

server/src/api/post.rs
server/src/api/site.rs
server/src/api/user.rs
server/src/db/mod.rs
server/src/db/post_view.rs
server/src/websocket/server.rs
ui/src/components/post-form.tsx
ui/src/components/post.tsx
ui/src/components/search.tsx
ui/src/interfaces.ts
ui/src/translations/en.ts

index 35363a171679b9cd9c01141e5b85ff309245d7c4..c5985f467e14fd4c5c2bba60b878175ecc5814d2 100644 (file)
@@ -254,6 +254,7 @@ impl Perform<GetPostsResponse> for Oper<GetPosts> {
       data.community_id, 
       None,
       None,
+      None,
       user_id, 
       show_nsfw,
       false, 
index 8f094aace850fe1425132f744f6f23c0d5e828b3..c98539bee8222a509194f428514f8f2beca6309c 100644 (file)
@@ -23,6 +23,7 @@ pub struct Search {
 #[derive(Serialize, Deserialize)]
 pub struct SearchResponse {
   op: String,
+  type_: String,
   comments: Vec<CommentView>,
   posts: Vec<PostView>,
   communities: Vec<CommunityView>,
@@ -288,6 +289,7 @@ impl Perform<SearchResponse> for Oper<Search> {
           data.community_id, 
           None,
           Some(data.q.to_owned()),
+          None,
           None, 
           true,
           false, 
@@ -333,6 +335,7 @@ impl Perform<SearchResponse> for Oper<Search> {
           data.community_id, 
           None,
           Some(data.q.to_owned()),
+          None,
           None, 
           true,
           false, 
@@ -363,6 +366,22 @@ impl Perform<SearchResponse> for Oper<Search> {
           Some(data.q.to_owned()), 
           data.page, 
           data.limit)?;
+      },
+      SearchType::Url => {
+        posts = PostView::list(
+          &conn, 
+          PostListingType::All, 
+          &sort, 
+          data.community_id, 
+          None,
+          None,
+          Some(data.q.to_owned()),
+          None, 
+          true,
+          false, 
+          false, 
+          data.page, 
+          data.limit)?;
       }
     };
 
@@ -371,6 +390,7 @@ impl Perform<SearchResponse> for Oper<Search> {
     Ok(
       SearchResponse {
         op: self.op.to_string(),
+        type_: data.type_.to_owned(),
         comments: comments,
         posts: posts,
         communities: communities,
index 672eca562a33522c4cfbf5e86f21c9253b76eb6f..425cc1cbddb2f775b74693ae68ac0f72b8c2132e 100644 (file)
@@ -318,6 +318,7 @@ impl Perform<GetUserDetailsResponse> for Oper<GetUserDetails> {
         data.community_id, 
         None, 
         None,
+        None,
         Some(user_details_id), 
         show_nsfw,
         data.saved_only, 
@@ -332,6 +333,7 @@ impl Perform<GetUserDetailsResponse> for Oper<GetUserDetails> {
         data.community_id, 
         Some(user_details_id), 
         None, 
+        None,
         user_id, 
         show_nsfw,
         data.saved_only, 
index 9f0c79b8fc47209b3e06f8c280a38bbd3995306c..3de0abb461c0fb2cd4106ec494224fd74d8c51cd 100644 (file)
@@ -67,7 +67,7 @@ pub enum SortType {
 
 #[derive(EnumString,ToString,Debug, Serialize, Deserialize)]
 pub enum SearchType {
-  All, Comments, Posts, Communities, Users
+  All, Comments, Posts, Communities, Users, Url
 }
 
 pub fn fuzzy_search(q: &str) -> String {
index c7e6eea3e56e4c5f1528db3bbf05c23f4d5d18ad..c9d8cff7b47fb1405b80cb68e56fd4fa8b82c58f 100644 (file)
@@ -79,6 +79,7 @@ impl PostView {
     for_community_id: Option<i32>, 
     for_creator_id: Option<i32>, 
     search_term: Option<String>,
+    url_search: Option<String>,
     my_user_id: Option<i32>, 
     show_nsfw: bool,
     saved_only: bool,
@@ -104,6 +105,10 @@ impl PostView {
       query = query.filter(name.ilike(fuzzy_search(&search_term)));
     };
 
+    if let Some(url_search) = url_search {
+      query = query.filter(url.eq(url_search));
+    };
+
     // TODO these are wrong, bc they'll only show saved for your logged in user, not theirs
     if saved_only {
       query = query.filter(saved.eq(true));
@@ -326,29 +331,34 @@ mod tests {
     };
 
 
-    let read_post_listings_with_user = PostView::list(&conn, 
-                                                      PostListingType::Community, 
-                                                      &SortType::New, Some(inserted_community.id), 
-                                                      None, 
-                                                      None,
-                                                      Some(inserted_user.id), 
-                                                      false,
-                                                      false, 
-                                                      false, 
-                                                      None, 
-                                                      None).unwrap();
-    let read_post_listings_no_user = PostView::list(&conn, 
-                                                    PostListingType::Community, 
-                                                    &SortType::New, 
-                                                    Some(inserted_community.id), 
-                                                    None, 
-                                                    None, 
-                                                    None,
-                                                    false,
-                                                    false, 
-                                                    false, 
-                                                    None, 
-                                                    None).unwrap();
+    let read_post_listings_with_user = PostView::list(
+      &conn, 
+      PostListingType::Community, 
+      &SortType::New, 
+      Some(inserted_community.id), 
+      None, 
+      None,
+      None,
+      Some(inserted_user.id), 
+      false,
+      false, 
+      false, 
+      None, 
+      None).unwrap();
+    let read_post_listings_no_user = PostView::list(
+      &conn, 
+      PostListingType::Community, 
+      &SortType::New, 
+      Some(inserted_community.id), 
+      None, 
+      None, 
+      None,
+      None,
+      false,
+      false, 
+      false, 
+      None, 
+      None).unwrap();
     let read_post_listing_no_user = PostView::read(&conn, inserted_post.id, None).unwrap();
     let read_post_listing_with_user = PostView::read(&conn, inserted_post.id, Some(inserted_user.id)).unwrap();
 
index 64f94f4cd4fc5242e167577be4bba060aa518b24..c0dee2679188c49badc1bfe8069658281e94de36 100644 (file)
@@ -142,6 +142,7 @@ impl ChatServer {
       None,
       None, 
       None,
+      None,
       false,
       false,
       false,
index 42620c9febfa59c17baa7d6e5b7d6a92881dc560..d21b2fb4c62983934af747eb27e59bedd0f76a5c 100644 (file)
@@ -23,6 +23,7 @@ interface PostFormState {
   loading: boolean;
   suggestedTitle: string;
   suggestedPosts: Array<Post>;
+  crossPosts: Array<Post>;
 }
 
 export class PostForm extends Component<PostFormProps, PostFormState> {
@@ -40,6 +41,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
     loading: false,
     suggestedTitle: undefined,
     suggestedPosts: [],
+    crossPosts: [],
   }
 
   constructor(props: any, context: any) {
@@ -95,6 +97,12 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
               {this.state.suggestedTitle && 
                 <div class="mt-1 text-muted small font-weight-bold pointer" onClick={linkEvent(this, this.copySuggestedTitle)}><T i18nKey="copy_suggested_title" interpolation={{title: this.state.suggestedTitle}}>#</T></div>
               }
+              {this.state.crossPosts.length > 0 && 
+                <>
+                  <div class="my-1 text-muted small font-weight-bold"><T i18nKey="cross_posts">#</T></div>
+                  <PostListings showCommunity posts={this.state.crossPosts} />
+                </>
+              }
             </div>
           </div>
           <div class="form-group row">
@@ -170,13 +178,27 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
   handlePostUrlChange(i: PostForm, event: any) {
     i.state.postForm.url = event.target.value;
     if (validURL(i.state.postForm.url)) {
+
+      let form: SearchForm = {
+        q: i.state.postForm.url,
+        type_: SearchType[SearchType.Url],
+        sort: SortType[SortType.TopAll],
+        page: 1,
+        limit: 6,
+      };
+
+      WebSocketService.Instance.search(form);
+
+      // Fetch the page title
       getPageTitle(i.state.postForm.url).then(d => {
         i.state.suggestedTitle = d;
         i.setState(i.state);
       });
     } else {
       i.state.suggestedTitle = undefined;
+      i.state.crossPosts = [];
     }
+
     i.setState(i.state);
   }
 
@@ -248,7 +270,12 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
       this.props.onEdit(res.post);
     } else if (op == UserOperation.Search) {
       let res: SearchResponse = msg;
-      this.state.suggestedPosts = res.posts;
+      
+      if (res.type_ == SearchType[SearchType.Posts]) {
+        this.state.suggestedPosts = res.posts;
+      } else if (res.type_ == SearchType[SearchType.Url]) {
+        this.state.crossPosts = res.posts;
+      }
       this.setState(this.state);
     }
   }
index b0204d38844f8d20be5dd93ee2845874eed1e279..97a9cd722b1a1ba18d9f34c312ef44a543ec22d4 100644 (file)
@@ -1,10 +1,11 @@
 import { Component, linkEvent } from 'inferno';
 import { Subscription } from "rxjs";
 import { retryWhen, delay, take } from 'rxjs/operators';
-import { UserOperation, Community, Post as PostI, GetPostResponse, PostResponse, Comment, CommentForm as CommentFormI, CommentResponse, CommentSortType, CreatePostLikeResponse, CommunityUser, CommunityResponse, CommentNode as CommentNodeI, BanFromCommunityResponse, BanUserResponse, AddModToCommunityResponse, AddAdminResponse, UserView } from '../interfaces';
+import { UserOperation, Community, Post as PostI, GetPostResponse, PostResponse, Comment, CommentForm as CommentFormI, CommentResponse, CommentSortType, CreatePostLikeResponse, CommunityUser, CommunityResponse, CommentNode as CommentNodeI, BanFromCommunityResponse, BanUserResponse, AddModToCommunityResponse, AddAdminResponse, UserView, SearchType, SortType, SearchForm, SearchResponse } from '../interfaces';
 import { WebSocketService, UserService } from '../services';
 import { msgOp, hotRank } from '../utils';
 import { PostListing } from './post-listing';
+import { PostListings } from './post-listings';
 import { Sidebar } from './sidebar';
 import { CommentForm } from './comment-form';
 import { CommentNodes } from './comment-nodes';
@@ -22,6 +23,7 @@ interface PostState {
   scrolled?: boolean;
   scrolled_comment_id?: number;
   loading: boolean;
+  crossPosts: Array<PostI>;
 }
 
 export class Post extends Component<any, PostState> {
@@ -35,7 +37,8 @@ export class Post extends Component<any, PostState> {
     moderators: [],
     admins: [],
     scrolled: false, 
-    loading: true
+    loading: true,
+    crossPosts: [],
   }
 
   constructor(props: any, context: any) {
@@ -112,6 +115,12 @@ export class Post extends Component<any, PostState> {
                 moderators={this.state.moderators} 
                 admins={this.state.admins}
               />
+              {this.state.crossPosts.length > 0 && 
+                <>
+                  <div class="my-1 text-muted small font-weight-bold"><T i18nKey="cross_posts">#</T></div>
+                  <PostListings showCommunity posts={this.state.crossPosts} />
+                </>
+              }
               <div className="mb-2" />
               <CommentForm postId={this.state.post.id} disabled={this.state.post.locked} />
               {this.sortRadios()}
@@ -256,6 +265,18 @@ export class Post extends Component<any, PostState> {
       this.state.admins = res.admins;
       this.state.loading = false;
       document.title = `${this.state.post.name} - ${WebSocketService.Instance.site.name}`;
+
+      // Get cross-posts  
+      let form: SearchForm = {
+        q: res.post.url,
+        type_: SearchType[SearchType.Url],
+        sort: SortType[SortType.TopAll],
+        page: 1,
+        limit: 6,
+      };
+
+      WebSocketService.Instance.search(form);
+
       this.setState(this.state);
     } else if (op == UserOperation.CreateComment) {
       let res: CommentResponse = msg;
@@ -332,6 +353,10 @@ export class Post extends Component<any, PostState> {
       let res: AddAdminResponse = msg;
       this.state.admins = res.admins;
       this.setState(this.state);
+    } else if (op == UserOperation.Search) {
+      let res: SearchResponse = msg;
+      this.state.crossPosts = res.posts.filter(p => p.id != this.state.post.id);
+      this.setState(this.state);
     }
 
   }
index 0f8727cb875b5d537db9543233d9ba6b98188c73..34a4a3d3178f4e1e6b52c68c1f91b9c5bfb6bd5c 100644 (file)
@@ -29,6 +29,7 @@ export class Search extends Component<any, SearchState> {
     page: 1,
     searchResponse: {
       op: null,
+      type_: null,
       posts: [],
       comments: [],
       communities: [],
index ebd42340d193034aaf89aad017e9b4b6066e3da3..91d89783d4abb20858c6f2c6926dbd6458f1453e 100644 (file)
@@ -15,7 +15,7 @@ export enum SortType {
 }
 
 export enum SearchType {
-  All, Comments, Posts, Communities, Users
+  All, Comments, Posts, Communities, Users, Url
 }
 
 export interface User {
@@ -551,6 +551,7 @@ export interface SearchForm {
 
 export interface SearchResponse {
   op: string;
+  type_: string;
   posts?: Array<Post>;
   comments?: Array<Comment>;
   communities: Array<Community>;  
index b5c066729e748ff4910175cdacb9241e2632bca7..90497ada59833ff061fc6fe84f5e776008e9db3d 100644 (file)
@@ -8,6 +8,7 @@ export const en = {
     number_of_posts:'{{count}} Posts',
     posts: 'Posts',
     related_posts: 'These posts might be related',
+    cross_posts: 'This link has also been posted to:',
     comments: 'Comments',
     number_of_comments:'{{count}} Comments',
     remove_comment: 'Remove Comment',