Adding save user settings

This commit is contained in:
Dessalines 2019-08-13 19:28:46 -07:00
parent 795ea5d4ba
commit 76ab3e1a62
12 changed files with 136 additions and 11 deletions

View file

@ -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

View file

@ -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)]

View file

@ -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> {

View file

@ -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()?;

View file

@ -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"
} }
} }

View file

@ -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,

View file

@ -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);
} }
} }
} }

View file

@ -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;

View file

@ -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);

View file

@ -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',

View file

@ -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,

View file

@ -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==