]> Untitled Git - lemmy.git/commitdiff
Adding permanently delete account comments and posts.
authorDessalines <tyhou13@gmx.com>
Tue, 15 Oct 2019 22:09:01 +0000 (15:09 -0700)
committerDessalines <tyhou13@gmx.com>
Tue, 15 Oct 2019 22:09:01 +0000 (15:09 -0700)
- Fixes #285
- Fixes #58

server/src/api/mod.rs
server/src/api/user.rs
server/src/websocket/server.rs
ui/src/components/user.tsx
ui/src/interfaces.ts
ui/src/services/WebSocketService.ts
ui/src/translations/en.ts

index 8872cd213981da775650b104dbb46bbe7cdc0637..5ffb57d89db0b8bb02745f0b480644906e349c7e 100644 (file)
@@ -56,6 +56,7 @@ pub enum UserOperation {
   SaveUserSettings,
   TransferCommunity,
   TransferSite,
+  DeleteAccount,
 }
 
 #[derive(Fail, Debug)]
index 785f99c48acaf8e67b36e75265ee09149b24688a..2fc0a92ca241ba9980d326f0c1a656943b668593 100644 (file)
@@ -103,6 +103,11 @@ pub struct GetReplies {
   auth: String,
 }
 
+#[derive(Serialize, Deserialize)]
+pub struct DeleteAccount {
+  auth: String,
+}
+
 impl Perform<LoginResponse> for Oper<Login> {
   fn perform(&self) -> Result<LoginResponse, Error> {
     let data: &Login = &self.data;
@@ -583,3 +588,67 @@ impl Perform<GetRepliesResponse> for Oper<MarkAllAsRead> {
     })
   }
 }
+
+impl Perform<LoginResponse> for Oper<DeleteAccount> {
+  fn perform(&self) -> Result<LoginResponse, Error> {
+    let data: &DeleteAccount = &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;
+
+    // Comments
+    let comments = CommentView::list(&conn, &SortType::New, None, Some(user_id), None, None, false, None, Some(std::i64::MAX))?;
+
+    for comment in &comments {
+      let comment_form = CommentForm {
+        content: "*Permananently Deleted*".to_string(),
+        parent_id: comment.to_owned().parent_id,
+        post_id: comment.to_owned().post_id,
+        creator_id: comment.to_owned().creator_id,
+        removed: None,
+        deleted: Some(true),
+        read: None,
+        updated: Some(naive_now()),
+      };
+
+      let _updated_comment = match Comment::update(&conn, comment.id, &comment_form) {
+        Ok(comment) => comment,
+        Err(_e) => return Err(APIError::err(&self.op, "couldnt_update_comment"))?,
+      };
+    }
+
+    // Posts
+    let posts = PostView::list(&conn, PostListingType::All, &SortType::New,None, Some(user_id), None, None, None, true, false, false, None, Some(std::i64::MAX))?;
+
+    for post in &posts {
+      let post_form = PostForm {
+        name: "*Permananently Deleted*".to_string(),
+        url: Some("https://deleted.com".to_string()),
+        body: Some("*Permananently Deleted*".to_string()),
+        creator_id: post.to_owned().creator_id,
+        community_id: post.to_owned().community_id,
+        removed: None,
+        deleted: Some(true),
+        nsfw: post.to_owned().nsfw,
+        locked: None,
+        stickied: None,
+        updated: Some(naive_now()),
+      };
+
+      let _updated_post = match Post::update(&conn, post.id, &post_form) {
+        Ok(post) => post,
+        Err(_e) => return Err(APIError::err(&self.op, "couldnt_update_post"))?,
+      };
+    }
+
+    Ok(LoginResponse {
+      op: self.op.to_string(),
+      jwt: data.auth.to_owned(),
+    })
+  }
+}
index 85de7eeabfee5aaf7a4c53d7f58a1294ce28c612..a00cfc3b032afbc669e5c9813390aa5ef58795f2 100644 (file)
@@ -519,5 +519,10 @@ fn parse_json_message(chat: &mut ChatServer, msg: StandardMessage) -> Result<Str
       let res = Oper::new(user_operation, transfer_site).perform()?;
       Ok(serde_json::to_string(&res)?)
     }
+    UserOperation::DeleteAccount => {
+      let delete_account: DeleteAccount = serde_json::from_str(data)?;
+      let res = Oper::new(user_operation, delete_account).perform()?;
+      Ok(serde_json::to_string(&res)?)
+    }
   }
 }
index 2a2a81240e683f76601c6d8f72913c5a95333fef..c53a672a0d102e3e79812003c82d8b5365405304 100644 (file)
@@ -31,6 +31,8 @@ interface UserState {
   loading: boolean;
   userSettingsForm: UserSettingsForm;
   userSettingsLoading: boolean;
+  deleteAccountLoading: boolean;
+  deleteAccountShowConfirm: boolean;
 }
 
 export class User extends Component<any, UserState> {
@@ -65,6 +67,8 @@ export class User extends Component<any, UserState> {
       auth: null,
     },
     userSettingsLoading: null,
+    deleteAccountLoading: null,
+    deleteAccountShowConfirm: false,
   }
 
   constructor(props: any, context: any) {
@@ -307,8 +311,17 @@ export class User extends Component<any, UserState> {
               </div>
               <div class="form-group row mb-0">
                 <div class="col-12">
-                  <button type="submit" class="btn btn-secondary">{this.state.userSettingsLoading ? 
+                  <button type="submit" class="btn btn-secondary mr-4">{this.state.userSettingsLoading ? 
                   <svg class="icon icon-spinner spin"><use xlinkHref="#icon-spinner"></use></svg> : capitalizeFirstLetter(i18n.t('save'))}</button>
+                  <button class="btn btn-danger" onClick={linkEvent(this, this.handleDeleteAccountShowConfirmToggle)}><T i18nKey="delete_account">#</T></button>
+                  {this.state.deleteAccountShowConfirm && 
+                    <>
+                      <div class="mt-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 ? 
+                      <svg class="icon icon-spinner spin"><use xlinkHref="#icon-spinner"></use></svg> : capitalizeFirstLetter(i18n.t('yes'))}</button>
+                      <button class="btn btn-secondary" onClick={linkEvent(this, this.handleDeleteAccountShowConfirmToggle)}><T i18nKey="cancel">#</T></button>
+                    </>
+                  }
                 </div>
               </div>
             </form>
@@ -434,6 +447,20 @@ export class User extends Component<any, UserState> {
     WebSocketService.Instance.saveUserSettings(i.state.userSettingsForm);
   }
 
+  handleDeleteAccountShowConfirmToggle(i: User, event: any) {
+    event.preventDefault();
+    i.state.deleteAccountShowConfirm = !i.state.deleteAccountShowConfirm;
+    i.setState(i.state);
+  }
+
+  handleDeleteAccount(i: User, event: any) {
+    event.preventDefault();
+    i.state.deleteAccountLoading = true;
+    i.setState(i.state);
+
+    WebSocketService.Instance.deleteAccount();
+  }
+
   parseMessage(msg: any) {
     console.log(msg);
     let op: UserOperation = msgOp(msg);
@@ -505,6 +532,11 @@ export class User extends Component<any, UserState> {
         this.setState(this.state);
         let res: LoginResponse = msg;
         UserService.Instance.login(res);
+    } else if (op == UserOperation.DeleteAccount) {
+        this.state.deleteAccountLoading = false;
+        this.state.deleteAccountShowConfirm = false;
+        this.setState(this.state);
+        this.context.router.history.push('/');
     }
   }
 }
index ab40d16a346d400d3753d0d5ae408a0da7a53e9e..4bd013ce9ec93ce13c980dc1535ce4e2b5a00a4a 100644 (file)
@@ -1,5 +1,5 @@
 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, SaveUserSettings, TransferCommunity, TransferSite
+  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, TransferCommunity, TransferSite, DeleteAccount
 }
 
 export enum CommentSortType {
index f67dbf6d94b82f11a4fcd2090a5d012b312b92f4..f8838d400ac7e93928a3aca4c745493c6fc4387a 100644 (file)
@@ -199,6 +199,12 @@ export class WebSocketService {
     this.subject.next(this.wsSendWrapper(UserOperation.SaveUserSettings, userSettingsForm));
   }
 
+  public deleteAccount() {
+    let form = {};
+    this.setAuth(form);
+    this.subject.next(this.wsSendWrapper(UserOperation.DeleteAccount, form));
+  }
+
   private wsSendWrapper(op: UserOperation, data: any) {
     let send = { op: UserOperation[op], data: data };
     console.log(send);
index 3d10cfa41a899eac9597b0a400726a335c89953e..9c45c71558e8fae5a10e5be0e864e03d2299f006 100644 (file)
@@ -55,6 +55,8 @@ export const en = {
     mark_as_unread: 'mark as unread',
     delete: 'delete',
     deleted: 'deleted',
+    delete_account: 'Delete Account',
+    delete_account_confirm: 'Warning: this will permanently delete all your data. Are you sure?',
     restore: 'restore',
     ban: 'ban',
     ban_from_site: 'ban from site',