forked from nutomic/lemmy
Adding save user settings
This commit is contained in:
parent
6e8da9cc9e
commit
3babd09aff
12 changed files with 136 additions and 11 deletions
|
@ -1 +1 @@
|
||||||
docker exec -it lemmy_db_1 pg_dumpall -c -U rrr > dump_`date +%d-%m-%Y"_"%H_%M_%S`.sql
|
docker exec -it lemmy_db_1 pg_dumpall -c -U rrr > dump_`date +%Y-%m-%d"_"%H_%M_%S`.sql
|
||||||
|
|
|
@ -22,7 +22,7 @@ pub mod site;
|
||||||
|
|
||||||
#[derive(EnumString,ToString,Debug)]
|
#[derive(EnumString,ToString,Debug)]
|
||||||
pub enum UserOperation {
|
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, Search, MarkAllAsRead
|
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, MarkAllAsRead, SaveUserSettings
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Fail, Debug)]
|
#[derive(Fail, Debug)]
|
||||||
|
|
|
@ -18,6 +18,12 @@ pub struct Register {
|
||||||
show_nsfw: bool,
|
show_nsfw: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct SaveUserSettings {
|
||||||
|
show_nsfw: bool,
|
||||||
|
auth: String,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct LoginResponse {
|
pub struct LoginResponse {
|
||||||
op: String,
|
op: String,
|
||||||
|
@ -221,6 +227,50 @@ impl Perform<LoginResponse> for Oper<Register> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Perform<LoginResponse> for Oper<SaveUserSettings> {
|
||||||
|
fn perform(&self) -> Result<LoginResponse, Error> {
|
||||||
|
let data: &SaveUserSettings = &self.data;
|
||||||
|
let conn = establish_connection();
|
||||||
|
|
||||||
|
let claims = match Claims::decode(&data.auth) {
|
||||||
|
Ok(claims) => claims.claims,
|
||||||
|
Err(_e) => {
|
||||||
|
return Err(APIError::err(&self.op, "not_logged_in"))?
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let user_id = claims.id;
|
||||||
|
|
||||||
|
let read_user = User_::read(&conn, user_id)?;
|
||||||
|
|
||||||
|
let user_form = UserForm {
|
||||||
|
name: read_user.name,
|
||||||
|
fedi_name: read_user.fedi_name,
|
||||||
|
email: read_user.email,
|
||||||
|
password_encrypted: read_user.password_encrypted,
|
||||||
|
preferred_username: read_user.preferred_username,
|
||||||
|
updated: Some(naive_now()),
|
||||||
|
admin: read_user.admin,
|
||||||
|
banned: read_user.banned,
|
||||||
|
show_nsfw: data.show_nsfw,
|
||||||
|
};
|
||||||
|
|
||||||
|
let updated_user = match User_::update(&conn, user_id, &user_form) {
|
||||||
|
Ok(user) => user,
|
||||||
|
Err(_e) => {
|
||||||
|
return Err(APIError::err(&self.op, "couldnt_update_user"))?
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Return the jwt
|
||||||
|
Ok(
|
||||||
|
LoginResponse {
|
||||||
|
op: self.op.to_string(),
|
||||||
|
jwt: updated_user.jwt()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Perform<GetUserDetailsResponse> for Oper<GetUserDetails> {
|
impl Perform<GetUserDetailsResponse> for Oper<GetUserDetails> {
|
||||||
fn perform(&self) -> Result<GetUserDetailsResponse, Error> {
|
fn perform(&self) -> Result<GetUserDetailsResponse, Error> {
|
||||||
|
|
|
@ -305,6 +305,11 @@ fn parse_json_message(chat: &mut ChatServer, msg: StandardMessage) -> Result<Str
|
||||||
let res = Oper::new(user_operation, get_user_details).perform()?;
|
let res = Oper::new(user_operation, get_user_details).perform()?;
|
||||||
Ok(serde_json::to_string(&res)?)
|
Ok(serde_json::to_string(&res)?)
|
||||||
},
|
},
|
||||||
|
UserOperation::SaveUserSettings => {
|
||||||
|
let save_user_settings: SaveUserSettings = serde_json::from_str(data)?;
|
||||||
|
let res = Oper::new(user_operation, save_user_settings).perform()?;
|
||||||
|
Ok(serde_json::to_string(&res)?)
|
||||||
|
},
|
||||||
UserOperation::AddAdmin => {
|
UserOperation::AddAdmin => {
|
||||||
let add_admin: AddAdmin = serde_json::from_str(data)?;
|
let add_admin: AddAdmin = serde_json::from_str(data)?;
|
||||||
let res = Oper::new(user_operation, add_admin).perform()?;
|
let res = Oper::new(user_operation, add_admin).perform()?;
|
||||||
|
|
|
@ -41,6 +41,6 @@
|
||||||
"fuse-box": "^3.1.3",
|
"fuse-box": "^3.1.3",
|
||||||
"ts-transform-classcat": "^0.0.2",
|
"ts-transform-classcat": "^0.0.2",
|
||||||
"ts-transform-inferno": "^4.0.2",
|
"ts-transform-inferno": "^4.0.2",
|
||||||
"typescript": "^3.3.3333"
|
"typescript": "^3.5.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ export class Setup extends Component<any, State> {
|
||||||
password: undefined,
|
password: undefined,
|
||||||
password_verify: undefined,
|
password_verify: undefined,
|
||||||
admin: true,
|
admin: true,
|
||||||
|
show_nsfw: true,
|
||||||
},
|
},
|
||||||
doneRegisteringUser: false,
|
doneRegisteringUser: false,
|
||||||
userLoading: false,
|
userLoading: false,
|
||||||
|
|
|
@ -2,8 +2,8 @@ import { Component, linkEvent } from 'inferno';
|
||||||
import { Link } from 'inferno-router';
|
import { Link } from 'inferno-router';
|
||||||
import { Subscription } from "rxjs";
|
import { Subscription } from "rxjs";
|
||||||
import { retryWhen, delay, take } from 'rxjs/operators';
|
import { retryWhen, delay, take } from 'rxjs/operators';
|
||||||
import { UserOperation, Post, Comment, CommunityUser, GetUserDetailsForm, SortType, UserDetailsResponse, UserView, CommentResponse } from '../interfaces';
|
import { UserOperation, Post, Comment, CommunityUser, GetUserDetailsForm, SortType, UserDetailsResponse, UserView, CommentResponse, UserSettingsForm, LoginResponse } from '../interfaces';
|
||||||
import { WebSocketService } from '../services';
|
import { WebSocketService, UserService } from '../services';
|
||||||
import { msgOp, fetchLimit, routeSortTypeToEnum, capitalizeFirstLetter } from '../utils';
|
import { msgOp, fetchLimit, routeSortTypeToEnum, capitalizeFirstLetter } from '../utils';
|
||||||
import { PostListing } from './post-listing';
|
import { PostListing } from './post-listing';
|
||||||
import { CommentNodes } from './comment-nodes';
|
import { CommentNodes } from './comment-nodes';
|
||||||
|
@ -28,6 +28,8 @@ interface UserState {
|
||||||
sort: SortType;
|
sort: SortType;
|
||||||
page: number;
|
page: number;
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
|
userSettingsForm: UserSettingsForm;
|
||||||
|
userSettingsLoading: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class User extends Component<any, UserState> {
|
export class User extends Component<any, UserState> {
|
||||||
|
@ -54,6 +56,11 @@ export class User extends Component<any, UserState> {
|
||||||
view: this.getViewFromProps(this.props),
|
view: this.getViewFromProps(this.props),
|
||||||
sort: this.getSortTypeFromProps(this.props),
|
sort: this.getSortTypeFromProps(this.props),
|
||||||
page: this.getPageFromProps(this.props),
|
page: this.getPageFromProps(this.props),
|
||||||
|
userSettingsForm: {
|
||||||
|
show_nsfw: null,
|
||||||
|
auth: null,
|
||||||
|
},
|
||||||
|
userSettingsLoading: null,
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(props: any, context: any) {
|
constructor(props: any, context: any) {
|
||||||
|
@ -75,6 +82,10 @@ export class User extends Component<any, UserState> {
|
||||||
this.refetch();
|
this.refetch();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get isCurrentUser() {
|
||||||
|
return UserService.Instance.user && UserService.Instance.user.id == this.state.user.id;
|
||||||
|
}
|
||||||
|
|
||||||
getViewFromProps(props: any): View {
|
getViewFromProps(props: any): View {
|
||||||
return (props.match.params.view) ?
|
return (props.match.params.view) ?
|
||||||
View[capitalizeFirstLetter(props.match.params.view)] :
|
View[capitalizeFirstLetter(props.match.params.view)] :
|
||||||
|
@ -131,6 +142,9 @@ export class User extends Component<any, UserState> {
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-3">
|
<div class="col-12 col-md-3">
|
||||||
{this.userInfo()}
|
{this.userInfo()}
|
||||||
|
{this.isCurrentUser &&
|
||||||
|
this.userSettings()
|
||||||
|
}
|
||||||
{this.moderates()}
|
{this.moderates()}
|
||||||
{this.follows()}
|
{this.follows()}
|
||||||
</div>
|
</div>
|
||||||
|
@ -219,7 +233,7 @@ export class User extends Component<any, UserState> {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h5>{user.name}</h5>
|
<h5>{user.name}</h5>
|
||||||
<div>{i18n.t('joined')}<MomentTime data={user} /></div>
|
<div>{i18n.t('joined')} <MomentTime data={user} /></div>
|
||||||
<table class="table table-bordered table-sm mt-2">
|
<table class="table table-bordered table-sm mt-2">
|
||||||
<tr>
|
<tr>
|
||||||
<td><T i18nKey="number_of_points" interpolation={{count: user.post_score}}>#</T></td>
|
<td><T i18nKey="number_of_points" interpolation={{count: user.post_score}}>#</T></td>
|
||||||
|
@ -235,6 +249,30 @@ export class User extends Component<any, UserState> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
userSettings() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h5><T i18nKey="settings">#</T></h5>
|
||||||
|
<form onSubmit={linkEvent(this, this.handleUserSettingsSubmit)}>
|
||||||
|
<div class="form-group row">
|
||||||
|
<div class="col-12">
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="checkbox" checked={this.state.userSettingsForm.show_nsfw} onChange={linkEvent(this, this.handleUserSettingsShowNsfwChange)}/>
|
||||||
|
<label class="form-check-label"><T i18nKey="show_nsfw">#</T></label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group row">
|
||||||
|
<div class="col-12">
|
||||||
|
<button type="submit" class="btn btn-secondary">{this.state.userSettingsLoading ?
|
||||||
|
<svg class="icon icon-spinner spin"><use xlinkHref="#icon-spinner"></use></svg> : capitalizeFirstLetter(i18n.t('save'))}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
moderates() {
|
moderates() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
@ -329,6 +367,19 @@ export class User extends Component<any, UserState> {
|
||||||
i.refetch();
|
i.refetch();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleUserSettingsShowNsfwChange(i: User, event: any) {
|
||||||
|
i.state.userSettingsForm.show_nsfw = event.target.checked;
|
||||||
|
i.setState(i.state);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleUserSettingsSubmit(i: User, event: any) {
|
||||||
|
event.preventDefault();
|
||||||
|
i.state.userSettingsLoading = true;
|
||||||
|
i.setState(i.state);
|
||||||
|
|
||||||
|
WebSocketService.Instance.saveUserSettings(i.state.userSettingsForm);
|
||||||
|
}
|
||||||
|
|
||||||
parseMessage(msg: any) {
|
parseMessage(msg: any) {
|
||||||
console.log(msg);
|
console.log(msg);
|
||||||
let op: UserOperation = msgOp(msg);
|
let op: UserOperation = msgOp(msg);
|
||||||
|
@ -343,6 +394,9 @@ export class User extends Component<any, UserState> {
|
||||||
this.state.moderates = res.moderates;
|
this.state.moderates = res.moderates;
|
||||||
this.state.posts = res.posts;
|
this.state.posts = res.posts;
|
||||||
this.state.loading = false;
|
this.state.loading = false;
|
||||||
|
if (this.isCurrentUser) {
|
||||||
|
this.state.userSettingsForm.show_nsfw = UserService.Instance.user.show_nsfw;
|
||||||
|
}
|
||||||
document.title = `/u/${this.state.user.name} - ${WebSocketService.Instance.site.name}`;
|
document.title = `/u/${this.state.user.name} - ${WebSocketService.Instance.site.name}`;
|
||||||
window.scrollTo(0,0);
|
window.scrollTo(0,0);
|
||||||
this.setState(this.state);
|
this.setState(this.state);
|
||||||
|
@ -378,6 +432,12 @@ export class User extends Component<any, UserState> {
|
||||||
if (res.comment.my_vote !== null)
|
if (res.comment.my_vote !== null)
|
||||||
found.my_vote = res.comment.my_vote;
|
found.my_vote = res.comment.my_vote;
|
||||||
this.setState(this.state);
|
this.setState(this.state);
|
||||||
|
} else if (op == UserOperation.SaveUserSettings) {
|
||||||
|
this.state = this.emptyState;
|
||||||
|
this.state.userSettingsLoading = false;
|
||||||
|
this.setState(this.state);
|
||||||
|
let res: LoginResponse = msg;
|
||||||
|
UserService.Instance.login(res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
export enum UserOperation {
|
export 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, Search, MarkAllAsRead
|
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, MarkAllAsRead, SaveUserSettings
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum CommentSortType {
|
export enum CommentSortType {
|
||||||
|
@ -347,7 +347,10 @@ export interface LoginResponse {
|
||||||
jwt: string;
|
jwt: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface UserSettingsForm {
|
||||||
|
show_nsfw: boolean;
|
||||||
|
auth: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface CommunityForm {
|
export interface CommunityForm {
|
||||||
name: string;
|
name: string;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { wsUri } from '../env';
|
import { wsUri } from '../env';
|
||||||
import { LoginForm, RegisterForm, UserOperation, CommunityForm, PostForm, SavePostForm, CommentForm, SaveCommentForm, CommentLikeForm, GetPostsForm, CreatePostLikeForm, FollowCommunityForm, GetUserDetailsForm, ListCommunitiesForm, GetModlogForm, BanFromCommunityForm, AddModToCommunityForm, AddAdminForm, BanUserForm, SiteForm, Site, UserView, GetRepliesForm, SearchForm } from '../interfaces';
|
import { LoginForm, RegisterForm, UserOperation, CommunityForm, PostForm, SavePostForm, CommentForm, SaveCommentForm, CommentLikeForm, GetPostsForm, CreatePostLikeForm, FollowCommunityForm, GetUserDetailsForm, ListCommunitiesForm, GetModlogForm, BanFromCommunityForm, AddModToCommunityForm, AddAdminForm, BanUserForm, SiteForm, Site, UserView, GetRepliesForm, SearchForm, UserSettingsForm } from '../interfaces';
|
||||||
import { webSocket } from 'rxjs/webSocket';
|
import { webSocket } from 'rxjs/webSocket';
|
||||||
import { Subject } from 'rxjs';
|
import { Subject } from 'rxjs';
|
||||||
import { retryWhen, delay, take } from 'rxjs/operators';
|
import { retryWhen, delay, take } from 'rxjs/operators';
|
||||||
|
@ -184,6 +184,11 @@ export class WebSocketService {
|
||||||
this.subject.next(this.wsSendWrapper(UserOperation.MarkAllAsRead, form));
|
this.subject.next(this.wsSendWrapper(UserOperation.MarkAllAsRead, form));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public saveUserSettings(userSettingsForm: UserSettingsForm) {
|
||||||
|
this.setAuth(userSettingsForm);
|
||||||
|
this.subject.next(this.wsSendWrapper(UserOperation.SaveUserSettings, userSettingsForm));
|
||||||
|
}
|
||||||
|
|
||||||
private wsSendWrapper(op: UserOperation, data: any) {
|
private wsSendWrapper(op: UserOperation, data: any) {
|
||||||
let send = { op: UserOperation[op], data: data };
|
let send = { op: UserOperation[op], data: data };
|
||||||
console.log(send);
|
console.log(send);
|
||||||
|
|
|
@ -29,6 +29,7 @@ export const en = {
|
||||||
mod: 'mod',
|
mod: 'mod',
|
||||||
mods: 'mods',
|
mods: 'mods',
|
||||||
moderates: 'Moderates',
|
moderates: 'Moderates',
|
||||||
|
settings: 'Settings',
|
||||||
remove_as_mod: 'remove as mod',
|
remove_as_mod: 'remove as mod',
|
||||||
appoint_as_mod: 'appoint as mod',
|
appoint_as_mod: 'appoint as mod',
|
||||||
modlog: 'Modlog',
|
modlog: 'Modlog',
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
"extends": "tslint:recommended",
|
"extends": "tslint:recommended",
|
||||||
"rules": {
|
"rules": {
|
||||||
"forin": false,
|
"forin": false,
|
||||||
"indent": [ true, "tabs" ],
|
"indent": [ true, "spaces" ],
|
||||||
"interface-name": false,
|
"interface-name": false,
|
||||||
"ban-types": true,
|
"ban-types": true,
|
||||||
"max-classes-per-file": true,
|
"max-classes-per-file": true,
|
||||||
|
|
|
@ -2773,7 +2773,7 @@ typescript@^2.6.2:
|
||||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.9.2.tgz#1cbf61d05d6b96269244eb6a3bce4bd914e0f00c"
|
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.9.2.tgz#1cbf61d05d6b96269244eb6a3bce4bd914e0f00c"
|
||||||
integrity sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w==
|
integrity sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w==
|
||||||
|
|
||||||
typescript@^3.3.3333:
|
typescript@^3.5.3:
|
||||||
version "3.5.3"
|
version "3.5.3"
|
||||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.3.tgz#c830f657f93f1ea846819e929092f5fe5983e977"
|
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.3.tgz#c830f657f93f1ea846819e929092f5fe5983e977"
|
||||||
integrity sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==
|
integrity sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==
|
||||||
|
|
Loading…
Reference in a new issue