summaryrefslogtreecommitdiffstats
path: root/server/src
diff options
context:
space:
mode:
authorDessalines <happydooby@gmail.com>2019-04-23 15:05:50 -0700
committerDessalines <happydooby@gmail.com>2019-04-23 15:05:50 -0700
commit73b9266580d23724e79983c49740546015ad74f8 (patch)
tree111202d1a63fc9524ae1e15aaaa7cd153f5bae41 /server/src
parentc96aa4819cbd65dd704e03ddbd63d553d0cf18f2 (diff)
Adding a search page
- Fixes # 70
Diffstat (limited to 'server/src')
-rw-r--r--server/src/actions/comment_view.rs29
-rw-r--r--server/src/actions/post_view.rs30
-rw-r--r--server/src/lib.rs18
-rw-r--r--server/src/websocket_server/server.rs163
4 files changed, 225 insertions, 15 deletions
diff --git a/server/src/actions/comment_view.rs b/server/src/actions/comment_view.rs
index 2e3ae058..85ddf587 100644
--- a/server/src/actions/comment_view.rs
+++ b/server/src/actions/comment_view.rs
@@ -3,7 +3,7 @@ use diesel::*;
use diesel::result::Error;
use diesel::dsl::*;
use serde::{Deserialize, Serialize};
-use { SortType, limit_and_offset };
+use { SortType, limit_and_offset, fuzzy_search };
// The faked schema since diesel doesn't do views
table! {
@@ -60,6 +60,7 @@ impl CommentView {
sort: &SortType,
for_post_id: Option<i32>,
for_creator_id: Option<i32>,
+ search_term: Option<String>,
my_user_id: Option<i32>,
saved_only: bool,
page: Option<i64>,
@@ -86,6 +87,10 @@ impl CommentView {
if let Some(for_post_id) = for_post_id {
query = query.filter(post_id.eq(for_post_id));
};
+
+ if let Some(search_term) = search_term {
+ query = query.filter(content.ilike(fuzzy_search(&search_term)));
+ };
if saved_only {
query = query.filter(saved.eq(true));
@@ -353,8 +358,26 @@ mod tests {
saved: None,
};
- let read_comment_views_no_user = CommentView::list(&conn, &SortType::New, Some(inserted_post.id), None, None, false, None, None).unwrap();
- let read_comment_views_with_user = CommentView::list(&conn, &SortType::New, Some(inserted_post.id), None, Some(inserted_user.id), false, None, None).unwrap();
+ let read_comment_views_no_user = CommentView::list(
+ &conn,
+ &SortType::New,
+ Some(inserted_post.id),
+ None,
+ None,
+ None,
+ false,
+ None,
+ None).unwrap();
+ let read_comment_views_with_user = CommentView::list(
+ &conn,
+ &SortType::New,
+ Some(inserted_post.id),
+ None,
+ None,
+ Some(inserted_user.id),
+ false,
+ None,
+ None).unwrap();
let like_removed = CommentLike::remove(&conn, &comment_like_form).unwrap();
let num_deleted = Comment::delete(&conn, inserted_comment.id).unwrap();
Post::delete(&conn, inserted_post.id).unwrap();
diff --git a/server/src/actions/post_view.rs b/server/src/actions/post_view.rs
index ccad9317..e24b0ed2 100644
--- a/server/src/actions/post_view.rs
+++ b/server/src/actions/post_view.rs
@@ -3,7 +3,7 @@ use diesel::*;
use diesel::result::Error;
use diesel::dsl::*;
use serde::{Deserialize, Serialize};
-use { SortType, limit_and_offset };
+use { SortType, limit_and_offset, fuzzy_search };
#[derive(EnumString,ToString,Debug, Serialize, Deserialize)]
pub enum PostListingType {
@@ -74,6 +74,7 @@ impl PostView {
sort: &SortType,
for_community_id: Option<i32>,
for_creator_id: Option<i32>,
+ search_term: Option<String>,
my_user_id: Option<i32>,
saved_only: bool,
unread_only: bool,
@@ -94,6 +95,10 @@ impl PostView {
query = query.filter(creator_id.eq(for_creator_id));
};
+ if let Some(search_term) = search_term {
+ query = query.filter(name.ilike(fuzzy_search(&search_term)));
+ };
+
// 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));
@@ -295,8 +300,27 @@ mod tests {
};
- let read_post_listings_with_user = PostView::list(&conn, PostListingType::Community, &SortType::New, Some(inserted_community.id), None, Some(inserted_user.id), false, false, None, None).unwrap();
- let read_post_listings_no_user = PostView::list(&conn, PostListingType::Community, &SortType::New, Some(inserted_community.id), None, None, false, false, None, None).unwrap();
+ 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,
+ 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,
+ 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();
diff --git a/server/src/lib.rs b/server/src/lib.rs
index 8347c23d..d8d7f152 100644
--- a/server/src/lib.rs
+++ b/server/src/lib.rs
@@ -97,6 +97,11 @@ pub enum SortType {
Hot, New, TopDay, TopWeek, TopMonth, TopYear, TopAll
}
+#[derive(EnumString,ToString,Debug, Serialize, Deserialize)]
+pub enum SearchType {
+ Both, Comments, Posts
+}
+
pub fn to_datetime_utc(ndt: NaiveDateTime) -> DateTime<Utc> {
DateTime::<Utc>::from_utc(ndt, Utc)
}
@@ -121,6 +126,11 @@ pub fn has_slurs(test: &str) -> bool {
SLUR_REGEX.is_match(test)
}
+pub fn fuzzy_search(q: &str) -> String {
+ let replaced = q.replace(" ", "%");
+ format!("%{}%", replaced)
+}
+
pub fn limit_and_offset(page: Option<i64>, limit: Option<i64>) -> (i64, i64) {
let page = page.unwrap_or(1);
let limit = limit.unwrap_or(10);
@@ -130,7 +140,7 @@ pub fn limit_and_offset(page: Option<i64>, limit: Option<i64>) -> (i64, i64) {
#[cfg(test)]
mod tests {
- use {Settings, is_email_regex, remove_slurs, has_slurs};
+ use {Settings, is_email_regex, remove_slurs, has_slurs, fuzzy_search};
#[test]
fn test_api() {
assert_eq!(Settings::get().api_endpoint(), "http://0.0.0.0/api/v1");
@@ -148,9 +158,15 @@ mod tests {
assert!(has_slurs(&test));
assert!(!has_slurs(slur_free));
}
+
+ #[test] fn test_fuzzy_search() {
+ let test = "This is a fuzzy search";
+ assert_eq!(fuzzy_search(test), "%This%is%a%fuzzy%search%".to_string());
+ }
}
+
lazy_static! {
static ref EMAIL_REGEX: Regex = Regex::new(r"^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$").unwrap();
static ref SLUR_REGEX: Regex = Regex::new(r"(fag(g|got|tard)?|maricos?|cock\s?sucker(s|ing)?|\bnig(\b|g?(a|er)?s?)\b|dindu(s?)|mudslime?s?|kikes?|mongoloids?|towel\s*heads?|\bspi(c|k)s?\b|\bchinks?|niglets?|beaners?|\bnips?\b|\bcoons?\b|jungle\s*bunn(y|ies?)|jigg?aboo?s?|\bpakis?\b|rag\s*heads?|gooks?|cunts?|bitch(es|ing|y)?|puss(y|ies?)|twats?|feminazis?|whor(es?|ing)|\bslut(s|t?y)?|\btrann?(y|ies?)|ladyboy(s?))").unwrap();
diff --git a/server/src/websocket_server/server.rs b/server/src/websocket_server/server.rs
index c61756e1..d7b93416 100644
--- a/server/src/websocket_server/server.rs
+++ b/server/src/websocket_server/server.rs
@@ -12,7 +12,7 @@ use std::str::FromStr;
use diesel::PgConnection;
use failure::Error;
-use {Crud, Joinable, Likeable, Followable, Bannable, Saveable, establish_connection, naive_now, naive_from_unix, SortType, has_slurs, remove_slurs};
+use {Crud, Joinable, Likeable, Followable, Bannable, Saveable, establish_connection, naive_now, naive_from_unix, SortType, SearchType, has_slurs, remove_slurs};
use actions::community::*;
use actions::user::*;
use actions::post::*;
@@ -27,7 +27,7 @@ use actions::moderator::*;
#[derive(EnumString,ToString,Debug)]
pub enum UserOperation {
- Login, Register, CreateCommunity, CreatePost, ListCommunities, ListCategories, GetPost, GetCommunity, CreateComment, EditComment, SaveComment, CreateCommentLike, GetPosts, CreatePostLike, EditPost, SavePost, EditCommunity, FollowCommunity, GetFollowedCommunities, GetUserDetails, GetReplies, GetModlog, BanFromCommunity, AddModToCommunity, CreateSite, EditSite, GetSite, AddAdmin, BanUser
+ Login, Register, CreateCommunity, CreatePost, ListCommunities, ListCategories, GetPost, GetCommunity, CreateComment, EditComment, SaveComment, CreateCommentLike, GetPosts, CreatePostLike, EditPost, SavePost, EditCommunity, FollowCommunity, GetFollowedCommunities, GetUserDetails, GetReplies, GetModlog, BanFromCommunity, AddModToCommunity, CreateSite, EditSite, GetSite, AddAdmin, BanUser, Search
}
#[derive(Fail, Debug)]
@@ -458,6 +458,23 @@ pub struct GetRepliesResponse {
replies: Vec<ReplyView>,
}
+#[derive(Serialize, Deserialize)]
+pub struct Search {
+ q: String,
+ type_: String,
+ community_id: Option<i32>,
+ sort: String,
+ page: Option<i64>,
+ limit: Option<i64>,
+}
+
+#[derive(Serialize, Deserialize)]
+pub struct SearchResponse {
+ op: String,
+ comments: Vec<CommentView>,
+ posts: Vec<PostView>,
+}
+
/// `ChatServer` manages chat rooms and responsible for coordinating chat
/// session. implementation is super primitive
pub struct ChatServer {
@@ -500,6 +517,7 @@ impl ChatServer {
Some(community_id),
None,
None,
+ None,
false,
false,
None,
@@ -703,6 +721,10 @@ fn parse_json_message(chat: &mut ChatServer, msg: StandardMessage) -> Result<Str
let get_replies: GetReplies = serde_json::from_str(data)?;
get_replies.perform(chat, msg.id)
},
+ UserOperation::Search => {
+ let search: Search = serde_json::from_str(data)?;
+ search.perform(chat, msg.id)
+ },
}
}
@@ -1106,7 +1128,7 @@ impl Perform for GetPost {
chat.rooms.get_mut(&self.id).unwrap().insert(addr);
- let comments = CommentView::list(&conn, &SortType::New, Some(self.id), None, user_id, false, None, Some(9999))?;
+ let comments = CommentView::list(&conn, &SortType::New, Some(self.id), None, None, user_id, false, None, Some(9999))?;
let community = CommunityView::read(&conn, post_view.community_id, user_id)?;
@@ -1537,7 +1559,17 @@ impl Perform for GetPosts {
let type_ = PostListingType::from_str(&self.type_)?;
let sort = SortType::from_str(&self.sort)?;
- let posts = match PostView::list(&conn, type_, &sort, self.community_id, None, user_id, false, false, self.page, self.limit) {
+ let posts = match PostView::list(&conn,
+ type_,
+ &sort,
+ self.community_id,
+ None,
+ None,
+ user_id,
+ false,
+ false,
+ self.page,
+ self.limit) {
Ok(posts) => posts,
Err(_e) => {
return Err(self.error("Couldn't get posts"))?
@@ -2006,15 +2038,52 @@ impl Perform for GetUserDetails {
let sort = SortType::from_str(&self.sort)?;
let user_view = UserView::read(&conn, self.user_id)?;
+ // If its saved only, you don't care what creator it was
let posts = if self.saved_only {
- PostView::list(&conn, PostListingType::All, &sort, self.community_id, None, Some(self.user_id), self.saved_only, false, self.page, self.limit)?
+ PostView::list(&conn,
+ PostListingType::All,
+ &sort,
+ self.community_id,
+ None,
+ None,
+ Some(self.user_id),
+ self.saved_only,
+ false,
+ self.page,
+ self.limit)?
} else {
- PostView::list(&conn, PostListingType::All, &sort, self.community_id, Some(self.user_id), None, self.saved_only, false, self.page, self.limit)?
+ PostView::list(&conn,
+ PostListingType::All,
+ &sort,
+ self.community_id,
+ Some(self.user_id),
+ None,
+ None,
+ self.saved_only,
+ false,
+ self.page,
+ self.limit)?
};
let comments = if self.saved_only {
- CommentView::list(&conn, &sort, None, None, Some(self.user_id), self.saved_only, self.page, self.limit)?
+ CommentView::list(&conn,
+ &sort,
+ None,
+ None,
+ None,
+ Some(self.user_id),
+ self.saved_only,
+ self.page,
+ self.limit)?
} else {
- CommentView::list(&conn, &sort, None, Some(self.user_id), None, self.saved_only, self.page, self.limit)?
+ CommentView::list(&conn,
+ &sort,
+ None,
+ Some(self.user_id),
+ None,
+ None,
+ self.saved_only,
+ self.page,
+ self.limit)?
};
let follows = CommunityFollowerView::for_user(&conn, self.user_id)?;
@@ -2539,3 +2608,81 @@ impl Perform for BanUser {
}
}
+
+impl Perform for Search {
+ fn op_type(&self) -> UserOperation {
+ UserOperation::Search
+ }
+
+ fn perform(&self, _chat: &mut ChatServer, _addr: usize) -> Result<String, Error> {
+
+ let conn = establish_connection();
+
+ let sort = SortType::from_str(&self.sort)?;
+ let type_ = SearchType::from_str(&self.type_)?;
+
+ let mut posts = Vec::new();
+ let mut comments = Vec::new();
+
+ match type_ {
+ SearchType::Posts => {
+ posts = PostView::list(&conn,
+ PostListingType::All,
+ &sort,
+ self.community_id,
+ None,
+ Some(self.q.to_owned()),
+ None,
+ false,
+ false,
+ self.page,
+ self.limit)?;
+ },
+ SearchType::Comments => {
+ comments = CommentView::list(&conn,
+ &sort,
+ None,
+ None,
+ Some(self.q.to_owned()),
+ None,
+ false,
+ self.page,
+ self.limit)?;
+ },
+ SearchType::Both => {
+ posts = PostView::list(&conn,
+ PostListingType::All,
+ &sort,
+ self.community_id,
+ None,
+ Some(self.q.to_owned()),
+ None,
+ false,
+ false,
+ self.page,
+ self.limit)?;
+ comments = CommentView::list(&conn,
+ &sort,
+ None,
+ None,
+ Some(self.q.to_owned()),
+ None,
+ false,
+ self.page,
+ self.limit)?;
+ }
+ };
+
+
+ // Return the jwt
+ Ok(
+ serde_json::to_string(
+ &SearchResponse {
+ op: self.op_type().to_string(),
+ comments: comments,
+ posts: posts,
+ }
+ )?
+ )
+ }
+}