Allow comment/post upvoting from other pages.
- Fixes #355 - Votes now coming back for posts and comments on search page.
This commit is contained in:
parent
dc35c7b126
commit
fc86b83e36
6 changed files with 154 additions and 99 deletions
|
@ -19,6 +19,7 @@ pub struct Search {
|
|||
sort: String,
|
||||
page: Option<i64>,
|
||||
limit: Option<i64>,
|
||||
auth: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
|
@ -313,6 +314,17 @@ impl Perform<SearchResponse> for Oper<Search> {
|
|||
fn perform(&self, conn: &PgConnection) -> Result<SearchResponse, Error> {
|
||||
let data: &Search = &self.data;
|
||||
|
||||
let user_id: Option<i32> = match &data.auth {
|
||||
Some(auth) => match Claims::decode(&auth) {
|
||||
Ok(claims) => {
|
||||
let user_id = claims.claims.id;
|
||||
Some(user_id)
|
||||
}
|
||||
Err(_e) => None,
|
||||
},
|
||||
None => None,
|
||||
};
|
||||
|
||||
let sort = SortType::from_str(&data.sort)?;
|
||||
let type_ = SearchType::from_str(&data.type_)?;
|
||||
|
||||
|
@ -330,6 +342,7 @@ impl Perform<SearchResponse> for Oper<Search> {
|
|||
.show_nsfw(true)
|
||||
.for_community_id(data.community_id)
|
||||
.search_term(data.q.to_owned())
|
||||
.my_user_id(user_id)
|
||||
.page(data.page)
|
||||
.limit(data.limit)
|
||||
.list()?;
|
||||
|
@ -338,6 +351,7 @@ impl Perform<SearchResponse> for Oper<Search> {
|
|||
comments = CommentQueryBuilder::create(&conn)
|
||||
.sort(&sort)
|
||||
.search_term(data.q.to_owned())
|
||||
.my_user_id(user_id)
|
||||
.page(data.page)
|
||||
.limit(data.limit)
|
||||
.list()?;
|
||||
|
@ -364,6 +378,7 @@ impl Perform<SearchResponse> for Oper<Search> {
|
|||
.show_nsfw(true)
|
||||
.for_community_id(data.community_id)
|
||||
.search_term(data.q.to_owned())
|
||||
.my_user_id(user_id)
|
||||
.page(data.page)
|
||||
.limit(data.limit)
|
||||
.list()?;
|
||||
|
@ -371,6 +386,7 @@ impl Perform<SearchResponse> for Oper<Search> {
|
|||
comments = CommentQueryBuilder::create(&conn)
|
||||
.sort(&sort)
|
||||
.search_term(data.q.to_owned())
|
||||
.my_user_id(user_id)
|
||||
.page(data.page)
|
||||
.limit(data.limit)
|
||||
.list()?;
|
||||
|
|
6
ui/src/components/post-listing.tsx
vendored
6
ui/src/components/post-listing.tsx
vendored
|
@ -52,7 +52,6 @@ interface PostListingProps {
|
|||
post: Post;
|
||||
showCommunity?: boolean;
|
||||
showBody?: boolean;
|
||||
viewOnly?: boolean;
|
||||
moderators?: Array<CommunityUser>;
|
||||
admins?: Array<UserView>;
|
||||
}
|
||||
|
@ -118,10 +117,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
|
|||
let post = this.props.post;
|
||||
return (
|
||||
<div class="listing col-12">
|
||||
<div
|
||||
className={`vote-bar mr-2 float-left small text-center ${this.props
|
||||
.viewOnly && 'no-click'}`}
|
||||
>
|
||||
<div className={`vote-bar mr-2 float-left small text-center`}>
|
||||
<button
|
||||
disabled={!UserService.Instance.user}
|
||||
className={`btn p-0 ${
|
||||
|
|
212
ui/src/components/search.tsx
vendored
212
ui/src/components/search.tsx
vendored
|
@ -12,6 +12,8 @@ import {
|
|||
SearchForm,
|
||||
SearchResponse,
|
||||
SearchType,
|
||||
CreatePostLikeResponse,
|
||||
CommentResponse,
|
||||
} from '../interfaces';
|
||||
import { WebSocketService } from '../services';
|
||||
import {
|
||||
|
@ -123,22 +125,18 @@ export class Search extends Component<any, SearchState> {
|
|||
render() {
|
||||
return (
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h5>
|
||||
<T i18nKey="search">#</T>
|
||||
</h5>
|
||||
{this.selects()}
|
||||
{this.searchForm()}
|
||||
{this.state.type_ == SearchType.All && this.all()}
|
||||
{this.state.type_ == SearchType.Comments && this.comments()}
|
||||
{this.state.type_ == SearchType.Posts && this.posts()}
|
||||
{this.state.type_ == SearchType.Communities && this.communities()}
|
||||
{this.state.type_ == SearchType.Users && this.users()}
|
||||
{this.noResults()}
|
||||
{this.paginator()}
|
||||
</div>
|
||||
</div>
|
||||
<h5>
|
||||
<T i18nKey="search">#</T>
|
||||
</h5>
|
||||
{this.selects()}
|
||||
{this.searchForm()}
|
||||
{this.state.type_ == SearchType.All && this.all()}
|
||||
{this.state.type_ == SearchType.Comments && this.comments()}
|
||||
{this.state.type_ == SearchType.Posts && this.posts()}
|
||||
{this.state.type_ == SearchType.Communities && this.communities()}
|
||||
{this.state.type_ == SearchType.Users && this.users()}
|
||||
{this.noResults()}
|
||||
{this.paginator()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -252,54 +250,56 @@ export class Search extends Component<any, SearchState> {
|
|||
return (
|
||||
<div>
|
||||
{combined.map(i => (
|
||||
<div>
|
||||
{i.type_ == 'posts' && (
|
||||
<PostListing post={i.data as Post} showCommunity viewOnly />
|
||||
)}
|
||||
{i.type_ == 'comments' && (
|
||||
<CommentNodes
|
||||
nodes={[{ comment: i.data as Comment }]}
|
||||
locked
|
||||
noIndent
|
||||
/>
|
||||
)}
|
||||
{i.type_ == 'communities' && (
|
||||
<div>
|
||||
<span>
|
||||
<Link to={`/c/${(i.data as Community).name}`}>{`/c/${
|
||||
(i.data as Community).name
|
||||
}`}</Link>
|
||||
</span>
|
||||
<span>{` - ${(i.data as Community).title} - ${
|
||||
(i.data as Community).number_of_subscribers
|
||||
} subscribers`}</span>
|
||||
</div>
|
||||
)}
|
||||
{i.type_ == 'users' && (
|
||||
<div>
|
||||
<span>
|
||||
<Link
|
||||
className="text-info"
|
||||
to={`/u/${(i.data as UserView).name}`}
|
||||
>
|
||||
{(i.data as UserView).avatar && showAvatars() && (
|
||||
<img
|
||||
height="32"
|
||||
width="32"
|
||||
src={pictshareAvatarThumbnail(
|
||||
(i.data as UserView).avatar
|
||||
)}
|
||||
class="rounded-circle mr-1"
|
||||
/>
|
||||
)}
|
||||
<span>{`/u/${(i.data as UserView).name}`}</span>
|
||||
</Link>
|
||||
</span>
|
||||
<span>{` - ${
|
||||
(i.data as UserView).comment_score
|
||||
} comment karma`}</span>
|
||||
</div>
|
||||
)}
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
{i.type_ == 'posts' && (
|
||||
<PostListing post={i.data as Post} showCommunity />
|
||||
)}
|
||||
{i.type_ == 'comments' && (
|
||||
<CommentNodes
|
||||
nodes={[{ comment: i.data as Comment }]}
|
||||
locked
|
||||
noIndent
|
||||
/>
|
||||
)}
|
||||
{i.type_ == 'communities' && (
|
||||
<div>
|
||||
<span>
|
||||
<Link to={`/c/${(i.data as Community).name}`}>{`/c/${
|
||||
(i.data as Community).name
|
||||
}`}</Link>
|
||||
</span>
|
||||
<span>{` - ${(i.data as Community).title} - ${
|
||||
(i.data as Community).number_of_subscribers
|
||||
} subscribers`}</span>
|
||||
</div>
|
||||
)}
|
||||
{i.type_ == 'users' && (
|
||||
<div>
|
||||
<span>
|
||||
<Link
|
||||
className="text-info"
|
||||
to={`/u/${(i.data as UserView).name}`}
|
||||
>
|
||||
{(i.data as UserView).avatar && showAvatars() && (
|
||||
<img
|
||||
height="32"
|
||||
width="32"
|
||||
src={pictshareAvatarThumbnail(
|
||||
(i.data as UserView).avatar
|
||||
)}
|
||||
class="rounded-circle mr-1"
|
||||
/>
|
||||
)}
|
||||
<span>{`/u/${(i.data as UserView).name}`}</span>
|
||||
</Link>
|
||||
</span>
|
||||
<span>{` - ${
|
||||
(i.data as UserView).comment_score
|
||||
} comment karma`}</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
@ -308,55 +308,69 @@ export class Search extends Component<any, SearchState> {
|
|||
|
||||
comments() {
|
||||
return (
|
||||
<div>
|
||||
<>
|
||||
{this.state.searchResponse.comments.map(comment => (
|
||||
<CommentNodes nodes={[{ comment: comment }]} locked noIndent />
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<CommentNodes nodes={[{ comment: comment }]} locked noIndent />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
posts() {
|
||||
return (
|
||||
<div>
|
||||
<>
|
||||
{this.state.searchResponse.posts.map(post => (
|
||||
<PostListing post={post} showCommunity viewOnly />
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<PostListing post={post} showCommunity />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
// Todo possibly create UserListing and CommunityListing
|
||||
communities() {
|
||||
return (
|
||||
<div>
|
||||
<>
|
||||
{this.state.searchResponse.communities.map(community => (
|
||||
<div>
|
||||
<span>
|
||||
<Link to={`/c/${community.name}`}>{`/c/${community.name}`}</Link>
|
||||
</span>
|
||||
<span>{` - ${community.title} - ${community.number_of_subscribers} subscribers`}</span>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<span>
|
||||
<Link
|
||||
to={`/c/${community.name}`}
|
||||
>{`/c/${community.name}`}</Link>
|
||||
</span>
|
||||
<span>{` - ${community.title} - ${community.number_of_subscribers} subscribers`}</span>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
users() {
|
||||
return (
|
||||
<div>
|
||||
<>
|
||||
{this.state.searchResponse.users.map(user => (
|
||||
<div>
|
||||
<span>
|
||||
<Link
|
||||
className="text-info"
|
||||
to={`/u/${user.name}`}
|
||||
>{`/u/${user.name}`}</Link>
|
||||
</span>
|
||||
<span>{` - ${user.comment_score} comment karma`}</span>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<span>
|
||||
<Link
|
||||
className="text-info"
|
||||
to={`/u/${user.name}`}
|
||||
>{`/u/${user.name}`}</Link>
|
||||
</span>
|
||||
<span>{` - ${user.comment_score} comment karma`}</span>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -477,6 +491,30 @@ export class Search extends Component<any, SearchState> {
|
|||
}`;
|
||||
window.scrollTo(0, 0);
|
||||
this.setState(this.state);
|
||||
} else if (op == UserOperation.CreateCommentLike) {
|
||||
let res: CommentResponse = msg;
|
||||
let found: Comment = this.state.searchResponse.comments.find(
|
||||
c => c.id === res.comment.id
|
||||
);
|
||||
found.score = res.comment.score;
|
||||
found.upvotes = res.comment.upvotes;
|
||||
found.downvotes = res.comment.downvotes;
|
||||
if (res.comment.my_vote !== null) {
|
||||
found.my_vote = res.comment.my_vote;
|
||||
found.upvoteLoading = false;
|
||||
found.downvoteLoading = false;
|
||||
}
|
||||
this.setState(this.state);
|
||||
} else if (op == UserOperation.CreatePostLike) {
|
||||
let res: CreatePostLikeResponse = msg;
|
||||
let found = this.state.searchResponse.posts.find(
|
||||
c => c.id == res.post.id
|
||||
);
|
||||
found.my_vote = res.post.my_vote;
|
||||
found.score = res.post.score;
|
||||
found.upvotes = res.post.upvotes;
|
||||
found.downvotes = res.post.downvotes;
|
||||
this.setState(this.state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
17
ui/src/components/user.tsx
vendored
17
ui/src/components/user.tsx
vendored
|
@ -18,6 +18,7 @@ import {
|
|||
BanUserResponse,
|
||||
AddAdminResponse,
|
||||
DeleteAccountForm,
|
||||
CreatePostLikeResponse,
|
||||
} from '../interfaces';
|
||||
import { WebSocketService, UserService } from '../services';
|
||||
import {
|
||||
|
@ -307,7 +308,6 @@ export class User extends Component<any, UserState> {
|
|||
post={i.data as Post}
|
||||
admins={this.state.admins}
|
||||
showCommunity
|
||||
viewOnly
|
||||
/>
|
||||
) : (
|
||||
<CommentNodes
|
||||
|
@ -340,12 +340,7 @@ export class User extends Component<any, UserState> {
|
|||
return (
|
||||
<div>
|
||||
{this.state.posts.map(post => (
|
||||
<PostListing
|
||||
post={post}
|
||||
admins={this.state.admins}
|
||||
showCommunity
|
||||
viewOnly
|
||||
/>
|
||||
<PostListing post={post} admins={this.state.admins} showCommunity />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
@ -1043,6 +1038,14 @@ export class User extends Component<any, UserState> {
|
|||
found.downvotes = res.comment.downvotes;
|
||||
if (res.comment.my_vote !== null) found.my_vote = res.comment.my_vote;
|
||||
this.setState(this.state);
|
||||
} else if (op == UserOperation.CreatePostLike) {
|
||||
let res: CreatePostLikeResponse = msg;
|
||||
let found = this.state.posts.find(c => c.id == res.post.id);
|
||||
found.my_vote = res.post.my_vote;
|
||||
found.score = res.post.score;
|
||||
found.upvotes = res.post.upvotes;
|
||||
found.downvotes = res.post.downvotes;
|
||||
this.setState(this.state);
|
||||
} else if (op == UserOperation.BanUser) {
|
||||
let res: BanUserResponse = msg;
|
||||
this.state.comments
|
||||
|
|
1
ui/src/interfaces.ts
vendored
1
ui/src/interfaces.ts
vendored
|
@ -700,6 +700,7 @@ export interface SearchForm {
|
|||
sort: string;
|
||||
page?: number;
|
||||
limit?: number;
|
||||
auth?: string;
|
||||
}
|
||||
|
||||
export interface SearchResponse {
|
||||
|
|
1
ui/src/services/WebSocketService.ts
vendored
1
ui/src/services/WebSocketService.ts
vendored
|
@ -255,6 +255,7 @@ export class WebSocketService {
|
|||
}
|
||||
|
||||
public search(form: SearchForm) {
|
||||
this.setAuth(form, false);
|
||||
this.subject.next(this.wsSendWrapper(UserOperation.Search, form));
|
||||
}
|
||||
|
||||
|
|
Reference in a new issue