Merge branch 'dev'
This commit is contained in:
commit
9f5a328186
5 changed files with 33 additions and 9 deletions
|
@ -105,6 +105,7 @@ pub struct GetReplies {
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct DeleteAccount {
|
pub struct DeleteAccount {
|
||||||
|
password: String,
|
||||||
auth: String,
|
auth: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -601,6 +602,14 @@ impl Perform<LoginResponse> for Oper<DeleteAccount> {
|
||||||
|
|
||||||
let user_id = claims.id;
|
let user_id = claims.id;
|
||||||
|
|
||||||
|
let user: User_ = User_::read(&conn, user_id)?;
|
||||||
|
|
||||||
|
// Verify the password
|
||||||
|
let valid: bool = verify(&data.password, &user.password_encrypted).unwrap_or(false);
|
||||||
|
if !valid {
|
||||||
|
return Err(APIError::err(&self.op, "password_incorrect"))?;
|
||||||
|
}
|
||||||
|
|
||||||
// Comments
|
// Comments
|
||||||
let comments = CommentView::list(
|
let comments = CommentView::list(
|
||||||
&conn,
|
&conn,
|
||||||
|
|
22
ui/src/components/user.tsx
vendored
22
ui/src/components/user.tsx
vendored
|
@ -2,7 +2,7 @@ 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, UserSettingsForm, LoginResponse, BanUserResponse, AddAdminResponse } from '../interfaces';
|
import { UserOperation, Post, Comment, CommunityUser, GetUserDetailsForm, SortType, UserDetailsResponse, UserView, CommentResponse, UserSettingsForm, LoginResponse, BanUserResponse, AddAdminResponse, DeleteAccountForm } from '../interfaces';
|
||||||
import { WebSocketService, UserService } from '../services';
|
import { WebSocketService, UserService } from '../services';
|
||||||
import { msgOp, fetchLimit, routeSortTypeToEnum, capitalizeFirstLetter, themes, setTheme } from '../utils';
|
import { msgOp, fetchLimit, routeSortTypeToEnum, capitalizeFirstLetter, themes, setTheme } from '../utils';
|
||||||
import { PostListing } from './post-listing';
|
import { PostListing } from './post-listing';
|
||||||
|
@ -33,6 +33,7 @@ interface UserState {
|
||||||
userSettingsLoading: boolean;
|
userSettingsLoading: boolean;
|
||||||
deleteAccountLoading: boolean;
|
deleteAccountLoading: boolean;
|
||||||
deleteAccountShowConfirm: boolean;
|
deleteAccountShowConfirm: boolean;
|
||||||
|
deleteAccountForm: DeleteAccountForm;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class User extends Component<any, UserState> {
|
export class User extends Component<any, UserState> {
|
||||||
|
@ -69,6 +70,9 @@ export class User extends Component<any, UserState> {
|
||||||
userSettingsLoading: null,
|
userSettingsLoading: null,
|
||||||
deleteAccountLoading: null,
|
deleteAccountLoading: null,
|
||||||
deleteAccountShowConfirm: false,
|
deleteAccountShowConfirm: false,
|
||||||
|
deleteAccountForm: {
|
||||||
|
password: null,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(props: any, context: any) {
|
constructor(props: any, context: any) {
|
||||||
|
@ -316,9 +320,10 @@ export class User extends Component<any, UserState> {
|
||||||
<button class="btn btn-danger" onClick={linkEvent(this, this.handleDeleteAccountShowConfirmToggle)}><T i18nKey="delete_account">#</T></button>
|
<button class="btn btn-danger" onClick={linkEvent(this, this.handleDeleteAccountShowConfirmToggle)}><T i18nKey="delete_account">#</T></button>
|
||||||
{this.state.deleteAccountShowConfirm &&
|
{this.state.deleteAccountShowConfirm &&
|
||||||
<>
|
<>
|
||||||
<div class="mt-2 alert alert-danger" role="alert"><T i18nKey="delete_account_confirm">#</T></div>
|
<div class="my-2 alert alert-danger" role="alert"><T i18nKey="delete_account_confirm">#</T></div>
|
||||||
<button class="btn btn-danger mr-4" onClick={linkEvent(this, this.handleDeleteAccount)}>{this.state.deleteAccountLoading ?
|
<input type="password" value={this.state.deleteAccountForm.password} onInput={linkEvent(this, this.handleDeleteAccountPasswordChange)} class="form-control my-2" />
|
||||||
<svg class="icon icon-spinner spin"><use xlinkHref="#icon-spinner"></use></svg> : capitalizeFirstLetter(i18n.t('yes'))}</button>
|
<button class="btn btn-danger mr-4" disabled={!this.state.deleteAccountForm.password} onClick={linkEvent(this, this.handleDeleteAccount)}>{this.state.deleteAccountLoading ?
|
||||||
|
<svg class="icon icon-spinner spin"><use xlinkHref="#icon-spinner"></use></svg> : capitalizeFirstLetter(i18n.t('delete'))}</button>
|
||||||
<button class="btn btn-secondary" onClick={linkEvent(this, this.handleDeleteAccountShowConfirmToggle)}><T i18nKey="cancel">#</T></button>
|
<button class="btn btn-secondary" onClick={linkEvent(this, this.handleDeleteAccountShowConfirmToggle)}><T i18nKey="cancel">#</T></button>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
|
@ -453,12 +458,17 @@ export class User extends Component<any, UserState> {
|
||||||
i.setState(i.state);
|
i.setState(i.state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleDeleteAccountPasswordChange(i: User, event: any) {
|
||||||
|
i.state.deleteAccountForm.password = event.target.value;
|
||||||
|
i.setState(i.state);
|
||||||
|
}
|
||||||
|
|
||||||
handleDeleteAccount(i: User, event: any) {
|
handleDeleteAccount(i: User, event: any) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
i.state.deleteAccountLoading = true;
|
i.state.deleteAccountLoading = true;
|
||||||
i.setState(i.state);
|
i.setState(i.state);
|
||||||
|
|
||||||
WebSocketService.Instance.deleteAccount();
|
WebSocketService.Instance.deleteAccount(i.state.deleteAccountForm);
|
||||||
}
|
}
|
||||||
|
|
||||||
parseMessage(msg: any) {
|
parseMessage(msg: any) {
|
||||||
|
@ -466,6 +476,8 @@ export class User extends Component<any, UserState> {
|
||||||
let op: UserOperation = msgOp(msg);
|
let op: UserOperation = msgOp(msg);
|
||||||
if (msg.error) {
|
if (msg.error) {
|
||||||
alert(i18n.t(msg.error));
|
alert(i18n.t(msg.error));
|
||||||
|
this.state.deleteAccountLoading = false;
|
||||||
|
this.setState(this.state);
|
||||||
return;
|
return;
|
||||||
} else if (op == UserOperation.GetUserDetails) {
|
} else if (op == UserOperation.GetUserDetails) {
|
||||||
let res: UserDetailsResponse = msg;
|
let res: UserDetailsResponse = msg;
|
||||||
|
|
4
ui/src/interfaces.ts
vendored
4
ui/src/interfaces.ts
vendored
|
@ -600,3 +600,7 @@ export interface SearchResponse {
|
||||||
communities: Array<Community>;
|
communities: Array<Community>;
|
||||||
users: Array<UserView>;
|
users: Array<UserView>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface DeleteAccountForm {
|
||||||
|
password: string;
|
||||||
|
}
|
||||||
|
|
5
ui/src/services/WebSocketService.ts
vendored
5
ui/src/services/WebSocketService.ts
vendored
|
@ -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, TransferCommunityForm, AddAdminForm, TransferSiteForm, BanUserForm, SiteForm, Site, UserView, GetRepliesForm, SearchForm, UserSettingsForm } from '../interfaces';
|
import { LoginForm, RegisterForm, UserOperation, CommunityForm, PostForm, SavePostForm, CommentForm, SaveCommentForm, CommentLikeForm, GetPostsForm, CreatePostLikeForm, FollowCommunityForm, GetUserDetailsForm, ListCommunitiesForm, GetModlogForm, BanFromCommunityForm, AddModToCommunityForm, TransferCommunityForm, AddAdminForm, TransferSiteForm, BanUserForm, SiteForm, Site, UserView, GetRepliesForm, SearchForm, UserSettingsForm, DeleteAccountForm } 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';
|
||||||
|
@ -199,8 +199,7 @@ export class WebSocketService {
|
||||||
this.subject.next(this.wsSendWrapper(UserOperation.SaveUserSettings, userSettingsForm));
|
this.subject.next(this.wsSendWrapper(UserOperation.SaveUserSettings, userSettingsForm));
|
||||||
}
|
}
|
||||||
|
|
||||||
public deleteAccount() {
|
public deleteAccount(form: DeleteAccountForm) {
|
||||||
let form = {};
|
|
||||||
this.setAuth(form);
|
this.setAuth(form);
|
||||||
this.subject.next(this.wsSendWrapper(UserOperation.DeleteAccount, form));
|
this.subject.next(this.wsSendWrapper(UserOperation.DeleteAccount, form));
|
||||||
}
|
}
|
||||||
|
|
2
ui/src/translations/en.ts
vendored
2
ui/src/translations/en.ts
vendored
|
@ -56,7 +56,7 @@ export const en = {
|
||||||
delete: 'delete',
|
delete: 'delete',
|
||||||
deleted: 'deleted',
|
deleted: 'deleted',
|
||||||
delete_account: 'Delete Account',
|
delete_account: 'Delete Account',
|
||||||
delete_account_confirm: 'Warning: this will permanently delete all your data. Are you sure?',
|
delete_account_confirm: 'Warning: this will permanently delete all your data. Enter your password to confirm.',
|
||||||
restore: 'restore',
|
restore: 'restore',
|
||||||
ban: 'ban',
|
ban: 'ban',
|
||||||
ban_from_site: 'ban from site',
|
ban_from_site: 'ban from site',
|
||||||
|
|
Loading…
Reference in a new issue