feat(webui): delete account #615
19
src/controllers/custom/deleteAccountController.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { RequestHandler } from "express";
|
||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||
import { Account } from "@/src/models/loginModel";
|
||||
import { Inventory } from "@/src/models/inventoryModels/inventoryModel";
|
||||
import { Loadout } from "@/src/models/inventoryModels/loadoutModel";
|
||||
import { PersonalRooms } from "@/src/models/personalRoomsModel";
|
||||
import { Ship } from "@/src/models/shipModel";
|
||||
|
||||
export const deleteAccountController: RequestHandler = async (req, res) => {
|
||||
const accountId = await getAccountIdForRequest(req);
|
||||
await Promise.all([
|
||||
Account.deleteOne({ _id: accountId }),
|
||||
Inventory.deleteOne({ accountOwnerId: accountId }),
|
||||
Loadout.deleteOne({ loadoutOwnerId: accountId }),
|
||||
PersonalRooms.deleteOne({ personalRoomsOwnerId: accountId }),
|
||||
Ship.deleteOne({ ShipOwnerId: accountId })
|
||||
]);
|
||||
res.end();
|
||||
};
|
||||
|
@ -4,6 +4,7 @@ import { tunablesController } from "@/src/controllers/custom/tunablesController"
|
||||
import { getItemListsController } from "@/src/controllers/custom/getItemListsController";
|
||||
import { pushArchonCrystalUpgradeController } from "@/src/controllers/custom/pushArchonCrystalUpgradeController";
|
||||
import { popArchonCrystalUpgradeController } from "@/src/controllers/custom/popArchonCrystalUpgradeController";
|
||||
import { deleteAccountController } from "@/src/controllers/custom/deleteAccountController";
|
||||
|
||||
import { createAccountController } from "@/src/controllers/custom/createAccountController";
|
||||
import { addItemController } from "@/src/controllers/custom/addItemController";
|
||||
@ -17,6 +18,7 @@ customRouter.get("/tunables.json", tunablesController);
|
||||
customRouter.get("/getItemLists", getItemListsController);
|
||||
customRouter.get("/pushArchonCrystalUpgrade", pushArchonCrystalUpgradeController);
|
||||
customRouter.get("/popArchonCrystalUpgrade", popArchonCrystalUpgradeController);
|
||||
customRouter.get("/deleteAccount", deleteAccountController);
|
||||
|
||||
customRouter.post("/createAccount", createAccountController);
|
||||
customRouter.post("/addItem", addItemController);
|
||||
|
@ -38,6 +38,8 @@
|
||||
<button class="nav-link dropdown-toggle displayname" data-bs-toggle="dropdown" aria-expanded="false"></button>
|
||||
<ul class="dropdown-menu dropdown-menu-end">
|
||||
<li><a class="dropdown-item" href="/webui/" onclick="logout();">Logout</a></li>
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
<li><a class="dropdown-item" onclick="deleteAccount();">Delete Account</a></li>
|
||||
![]() 🛠️ Refactor suggestion Enhance user safety and accessibility The current implementation lacks:
Consider these improvements:
Add this modal for confirmation:
_:hammer_and_wrench: Refactor suggestion_
**Enhance user safety and accessibility**
The current implementation lacks:
1. Visual warning about the irreversible action
2. Confirmation dialog
3. Accessibility attributes
4. Loading state during deletion
Consider these improvements:
```diff
<li><hr class="dropdown-divider"></li>
-<li><a class="dropdown-item" onclick="deleteAccount();">Delete Account</a></li>
+<li>
+ <button
+ class="dropdown-item text-danger"
+ data-bs-toggle="modal"
+ data-bs-target="#deleteAccountModal"
+ aria-label="Delete account permanently"
+ >
+ Delete Account
+ </button>
+</li>
```
Add this modal for confirmation:
```html
<div class="modal fade" id="deleteAccountModal" tabindex="-1" aria-labelledby="deleteAccountModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="deleteAccountModalLabel">Delete Account</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<p class="text-danger">Warning: This action cannot be undone. All your data will be permanently deleted.</p>
<p>Please type "DELETE" to confirm:</p>
<input type="text" class="form-control" id="deleteConfirmation" />
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-danger" id="confirmDeleteAccount" disabled>Delete Account</button>
</div>
</div>
</div>
</div>
```
<!-- This is an auto-generated comment by CodeRabbit -->
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
@ -47,13 +49,7 @@
|
||||
<div class="offcanvas-lg offcanvas-start" tabindex="-1" id="sidebar" aria-labelledby="sidebarLabel">
|
||||
<div class="offcanvas-header">
|
||||
<h5 class="offcanvas-title" id="sidebarLabel">Sidebar</h5>
|
||||
<button
|
||||
type="button"
|
||||
class="btn-close"
|
||||
data-bs-dismiss="offcanvas"
|
||||
data-bs-target="#sidebar"
|
||||
aria-label="Close"
|
||||
></button>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" data-bs-target="#sidebar" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="offcanvas-body">
|
||||
<div class="navbar p-0">
|
||||
|
@ -61,6 +61,23 @@ function logout() {
|
||||
localStorage.removeItem("password");
|
||||
}
|
||||
|
||||
function deleteAccount() {
|
||||
if (
|
||||
window.confirm(
|
||||
"Are you sure you want to delete your account " +
|
||||
$(".displayname").text() +
|
||||
" (" +
|
||||
localStorage.getItem("email") +
|
||||
")? This action cannot be undone."
|
||||
)
|
||||
) {
|
||||
fetch("/custom/deleteAccount?" + window.authz).then(function () {
|
||||
logout();
|
||||
single.loadRoute("/webui/"); // Show login screen
|
||||
});
|
||||
}
|
||||
}
|
||||
![]() ⚠️ Potential issue Enhance error handling and security in account deletion. The account deletion implementation needs improvements in several areas:
Consider applying these improvements:
📝 Committable suggestion
🧰 Tools🪛 eslint[error] 64-64: 'deleteAccount' is defined but never used. (@typescript-eslint/no-unused-vars) [error] 68-68: '$' is not defined. (no-undef) [error] 76-76: 'single' is not defined. (no-undef) 💡 Codebase verification Account deletion implementation needs error handling improvements The verification revealed several issues that need attention:
🔗 Analysis chainVerify the account deletion implementation across the codebase. Let's ensure the account deletion feature is properly integrated. Let me generate additional verification scripts to check for error handling and response handling in both frontend and backend: 🏁 Scripts executedThe following scripts were executed for the analysis: Script:
Length of output: 5308 Script:
Length of output: 2179 🧰 Tools🪛 eslint[error] 64-64: 'deleteAccount' is defined but never used. (@typescript-eslint/no-unused-vars) [error] 68-68: '$' is not defined. (no-undef) [error] 76-76: 'single' is not defined. (no-undef) _:warning: Potential issue_
**Enhance error handling and security in account deletion.**
The account deletion implementation needs improvements in several areas:
1. Error handling is missing for failed requests
2. Auth token in URL could be exposed in logs
3. No loading state during deletion
Consider applying these improvements:
```diff
function deleteAccount() {
if (
window.confirm(
"Are you sure you want to delete your account " +
$(".displayname").text() +
" (" +
localStorage.getItem("email") +
")? This action cannot be undone."
)
) {
- fetch("/custom/deleteAccount?" + window.authz).then(function () {
- logout();
- single.loadRoute("/webui/"); // Show login screen
- });
+ const button = document.querySelector("#delete-account-btn");
+ if (button) button.disabled = true;
+
+ fetch("/custom/deleteAccount", {
+ method: 'POST',
+ headers: {
+ 'Authorization': window.authz
+ }
+ })
+ .then(response => {
+ if (!response.ok) {
+ throw new Error('Account deletion failed');
+ }
+ logout();
+ single.loadRoute("/webui/");
+ })
+ .catch(error => {
+ alert("Failed to delete account: " + error.message);
+ })
+ .finally(() => {
+ if (button) button.disabled = false;
+ });
}
}
```
<!-- suggestion_start -->
<details>
<summary>📝 Committable suggestion</summary>
> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
`````suggestion
function deleteAccount() {
if (
window.confirm(
"Are you sure you want to delete your account " +
$(".displayname").text() +
" (" +
localStorage.getItem("email") +
")? This action cannot be undone."
)
) {
const button = document.querySelector("#delete-account-btn");
if (button) button.disabled = true;
fetch("/custom/deleteAccount", {
method: 'POST',
headers: {
'Authorization': window.authz
}
})
.then(response => {
if (!response.ok) {
throw new Error('Account deletion failed');
}
logout();
single.loadRoute("/webui/");
})
.catch(error => {
alert("Failed to delete account: " + error.message);
})
.finally(() => {
if (button) button.disabled = false;
});
}
}
`````
</details>
<!-- suggestion_end -->
<details>
<summary>🧰 Tools</summary>
<details>
<summary>🪛 eslint</summary>
[error] 64-64: 'deleteAccount' is defined but never used.
(@typescript-eslint/no-unused-vars)
---
[error] 68-68: '$' is not defined.
(no-undef)
---
[error] 76-76: 'single' is not defined.
(no-undef)
</details>
</details>
---
_:bulb: Codebase verification_
**Account deletion implementation needs error handling improvements**
The verification revealed several issues that need attention:
* Frontend: The fetch call lacks error handling and doesn't handle failed requests
```javascript
fetch("/custom/deleteAccount?" + window.authz).then(function () {
```
* Backend: The controller doesn't include try-catch blocks or error responses
```typescript
export const deleteAccountController: RequestHandler = async (req, res) => {
const accountId = await getAccountIdForRequest(req);
await Promise.all([...]);
res.end();
};
```
* Both frontend and backend should handle cases where:
- Account ID retrieval fails
- Database operations fail
- Network requests fail
- Authentication errors occur
<details>
<summary>🔗 Analysis chain</summary>
**Verify the account deletion implementation across the codebase.**
Let's ensure the account deletion feature is properly integrated.
---
Let me generate additional verification scripts to check for error handling and response handling in both frontend and backend:
</details>
<details>
<summary>🏁 Scripts executed</summary>
The following scripts were executed for the analysis:
Script:
```shell
#!/bin/bash
# Description: Verify the account deletion implementation
# Test 1: Check if deleteAccount function is properly bound to a UI element
echo "Checking for deleteAccount button/link in HTML..."
rg -l "deleteAccount\(\)" --type html
# Test 2: Check for related backend route implementation
echo "Checking for deleteAccount route implementation..."
rg -l "deleteAccount" --type typescript --type javascript
# Test 3: Check for proper error handling in related files
echo "Checking error handling in related files..."
rg "deleteAccount" -A 5 -B 5
```
Length of output: 5308
---
Script:
```shell
#!/bin/bash
# Check frontend error handling for the fetch call
echo "Checking frontend error handling..."
rg "fetch\(.*deleteAccount.*\)" -A 10 -B 2
# Check backend error handling in the controller
echo "Checking backend error handling..."
ast-grep --pattern 'export const deleteAccountController: RequestHandler = async (req, res) => {
$$$
}'
# Check if all necessary models are properly cleaned up
echo "Checking for all database models that might need cleanup..."
rg "mongoose\.model|Schema\(" --type typescript
```
Length of output: 2179
</details>
<details>
<summary>🧰 Tools</summary>
<details>
<summary>🪛 eslint</summary>
[error] 64-64: 'deleteAccount' is defined but never used.
(@typescript-eslint/no-unused-vars)
---
[error] 68-68: '$' is not defined.
(no-undef)
---
[error] 76-76: 'single' is not defined.
(no-undef)
</details>
</details>
<!-- This is an auto-generated comment by CodeRabbit -->
|
||||
|
||||
if (localStorage.getItem("email") && localStorage.getItem("password")) {
|
||||
loginFromLocalStorage();
|
||||
}
|
||||
|
⚠️ Potential issue
Critical: Implement proper security measures and error handling
The current implementation has several security and reliability concerns:
Consider implementing these improvements: