Skip to content

Commit

Permalink
Add option for users to delete their accounts
Browse files Browse the repository at this point in the history
And one for admins
  • Loading branch information
HebaruSan committed Mar 20, 2023
1 parent d94e729 commit 309896a
Show file tree
Hide file tree
Showing 5 changed files with 173 additions and 8 deletions.
37 changes: 36 additions & 1 deletion KerbalStuff/blueprints/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@
import zipfile
from datetime import datetime
from functools import wraps
from shutil import rmtree
from typing import Dict, Any, Callable, Optional, Tuple, Iterable, List, Union

from flask import Blueprint, url_for, current_app, request, abort
from flask_login import login_user, current_user
from flask_login import login_user, current_user, logout_user
from sqlalchemy import desc, asc
from sqlalchemy.orm import Query
from werkzeug.utils import secure_filename
Expand Down Expand Up @@ -551,6 +552,40 @@ def change_password(username: str) -> Union[Dict[str, Any], Tuple[Union[str, Any
return {'error': True, 'reason': pw_message}


@api.route("/api/user/<username>/delete", methods=['POST'])
@with_session
@user_required
@json_output
def delete(username: str) -> Tuple[Dict[str, Any], int]:
deletable = False
if current_user:
if current_user.admin:
deletable = True
if current_user.username == username:
deletable = True
if not deletable:
return {'error': True, 'reason': 'Unauthorized'}, 401

form_username = request.form.get('username')
if form_username != username:
return {'error': True, 'reason': 'Wrong username'}, 403

user = User.query.filter(User.username == username).one_or_none()
if not user:
return {'error': True, 'reason': 'User does not exist'}, 404

storage = _cfg('storage')
if storage:
full_path = os.path.join(storage, user.base_path())
rmtree(full_path, ignore_errors=True)

db.delete(user)
if user == current_user:
logout_user()

return {"error": False}, 400


@api.route('/api/mod/<int:mod_id>/update-bg', methods=['POST'])
@with_session
@json_output
Expand Down
8 changes: 6 additions & 2 deletions KerbalStuff/blueprints/mods.py
Original file line number Diff line number Diff line change
Expand Up @@ -405,8 +405,7 @@ def delete(mod_id: int) -> werkzeug.wrappers.Response:
storage = _cfg('storage')
if storage:
full_path = os.path.join(storage, mod.base_path())
rmtree(full_path)

rmtree(full_path, ignore_errors=True)
db.delete(mod)
db.commit()
notify_ckan(mod, 'delete', True)
Expand Down Expand Up @@ -638,6 +637,11 @@ def delete_version(mod_id: int, version_id: str) -> werkzeug.wrappers.Response:

purge_download(version[0].download_path)

storage = _cfg('storage')
if storage:
full_path = os.path.join(storage, version.download_path)
os.remove(full_path)

db.delete(version)
db.commit()
return redirect(url_for("mods.mod", _anchor='changelog', mod_id=mod.id, mod_name=mod.name))
Expand Down
58 changes: 56 additions & 2 deletions frontend/coffee/profile.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ window.upload_bg = (files, box) ->
xhr.upload.onprogress = (e) ->
if e.lengthComputable
progress.style.width = (e.loaded / e.total) * 100 + '%'
xhr.onload = (e) ->
xhr.onload = () ->
if xhr.status != 200
p.textContent = 'Please upload JPG or PNG only.'
setTimeout(() ->
Expand Down Expand Up @@ -98,6 +98,60 @@ resetPasswordModalDialog = () ->

$('#change-password').on('hidden.bs.modal', resetPasswordModalDialog)

# Handling of the delete-account dialog
$('#delete-account-form').submit((e) ->
e.preventDefault()

# Disable the buttons until we get an response
buttons = document.getElementsByClassName('btn-account-del')
for button in buttons
button.setAttribute('disabled', '')

form_username = $('#username').val()

xhr = new XMLHttpRequest()
xhr.open('POST', "/api/user/#{window.username}/delete")
# Triggered after we get an response from the server.
# It's in the form {'error': bool, 'reason': string)
xhr.onload = () ->
result = JSON.parse(this.responseText)
error_message_display = $('#delete-account-error-message')

if result.error == true
error_message_display.html(result.reason)
error_message_display.addClass('text-danger')
error_message_display.removeClass('hidden')
# Re-enable the buttons.
for button in buttons
button.removeAttribute('disabled')
else
error_message_display.html('Account deleted successfully.')
error_message_display.removeClass('text-danger')
error_message_display.addClass('text-success')
error_message_display.removeClass('hidden')
# .modal('hide') doesn't work. Let's reload the page instead.
# Delay it a bit to give the user a chance to read the response message.
setTimeout((() -> window.location = '/'), 1000)

form = new FormData()
form.append('username', form_username)
xhr.send(form)
)

deleteAccountModalDialog = () ->
$('#delete-account-form').trigger('reset')
error_message_display = $('#delete-account-error-message')
error_message_display.html('')
error_message_display.removeClass('text-danger')
error_message_display.removeClass('text-success')
error_message_display.addClass('hidden')

buttons = document.getElementsByClassName('btn-account-del')
for button in buttons
button.removeAttribute('disabled')

$('#delete-account').on('hidden.bs.modal', deleteAccountModalDialog)

$('#check-all-updates' ).on('click', () -> $('[id^=updates-]' ).prop('checked', true))
$('#uncheck-all-updates' ).on('click', () -> $('[id^=updates-]' ).prop('checked', false))
$('#check-all-autoupdates' ).on('click', () -> $('[id^=autoupdates-]').prop('checked', true))
Expand All @@ -117,4 +171,4 @@ $('#save-changes').on 'click', () ->
$('#overall-error').hide()
else
$('#overall-error').show()
return allValid
return allValid
42 changes: 39 additions & 3 deletions templates/profile.html
Original file line number Diff line number Diff line change
Expand Up @@ -211,11 +211,21 @@ <h2>Change Password</h2>
<a class="btn btn-default" href="#" data-toggle="modal" data-target="#change-password" role="button">Click to change password</a>
</div>
</div>
<div class="row">
<div class="col-md-12">
<h2>Delete User Account</h2>
</div>
</div>
<div class="row">
<div class="col-md-12">
<a class="btn btn-default" href="#" data-toggle="modal" data-target="#confirm-delete-account" role="button">Click to delete your account</a>
</div>
</div>
</div>

<div class="container lead">
<div class="row">
<div class="col-md-8">
<div class="col-md-12">
<h2>Connected Accounts</h2>
</div>

Expand Down Expand Up @@ -280,7 +290,7 @@ <h2 style="margin-top: -10px; margin-bottom: 0;">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title" id="myModalLabel">Disconnect Account: {{provider_full_name}}</h4>
<h4 class="modal-title">Disconnect Account: {{provider_full_name}}</h4>
</div>
<div class="modal-body">
<p>This action will disconnect your {{provider_full_name}} account from your {{ site_name }} account.</p>
Expand All @@ -303,7 +313,7 @@ <h4 class="modal-title" id="myModalLabel">Disconnect Account: {{provider_full_na
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title" id="myModalLabel">Change Password</h4>
<h4 class="modal-title">Change Password</h4>
</div>
<form action="#" id="password-form">
<div class="modal-body">
Expand Down Expand Up @@ -334,6 +344,32 @@ <h4 class="modal-title" id="myModalLabel">Change Password</h4>
</div>
</div>
</div>
<div class="modal fade" id="confirm-delete-account" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title">Delete User Account</h4>
</div>
<form action="#" id="delete-account-form">
<div class="modal-body">
<p>Are you really, really, really sure you want to delete your account? You can't undo this. It'll be gone.
This will delete any data associated with your account, including uploaded mods.</p>
<div class="form-group">
<label for="username">Your username</label>
<input type="text" id="username" placeholder="Enter your username to confirm" class="form-control"
name="username">
</div>
</div>
<div class="modal-footer">
<p id="delete-account-error-message" class="hidden"></p>
<a href="#" class="btn btn-default btn-account-del" data-dismiss="modal">Cancel</a>
<input type="submit" id="delete-user-submit" class="btn btn-danger btn-account-del" value="Delete account">
</div>
</form>
</div>
</div>
</div>
{% endblock %}
{% block scripts %}
<script>
Expand Down
36 changes: 36 additions & 0 deletions templates/view_profile.html
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,10 @@ <h2>
<span class="glyphicon glyphicon-fire"></span>
Impersonate user
</a>
<a href="#" class="btn btn-danger" data-toggle="modal" data-target="#confirm-delete-account" role="button" style="margin-bottom: 10px; margin-top: 5px;">
<span class="glyphicon glyphicon-fire"></span>
Delete user
</a>
{% endif %}
</div>
</div>
Expand Down Expand Up @@ -234,6 +238,32 @@ <h4 class="modal-title" id="myModalLabel">Grant Administrator Privileges</h4>
</div>
</div>
</div>
<div class="modal fade" id="confirm-delete-account" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title">Delete User Account</h4>
</div>
<form action="#" id="delete-account-form">
<div class="modal-body">
<p>Are you really, really, really sure you want to delete that account? It can't be undone. It'll be gone.
This will delete any data associated with this account, including uploaded mods.</p>
<div class="form-group">
<label for="username">Username</label>
<input type="text" id="username" placeholder="Enter the user's username to confirm" class="form-control"
name="username">
</div>
</div>
<div class="modal-footer">
<p id="delete-account-error-message" class="hidden"></p>
<a href="#" class="btn btn-default btn-account-del" data-dismiss="modal">Cancel</a>
<input type="submit" id="delete-user-submit" class="btn btn-danger btn-account-del" value="Delete account">
</div>
</form>
</div>
</div>
</div>
{%- endif -%}

{% if len(profile.packs) != 0 %}
Expand Down Expand Up @@ -304,3 +334,9 @@ <h4 class="modal-title" id="myModalLabel">Publicize Profile</h4>
</div>
{% endif %}
{% endblock %}
{% block scripts %}
<script>
window.username = "{{profile.username}}";
</script>
<script src="/static/profile.js"></script>
{% endblock %}

0 comments on commit 309896a

Please sign in to comment.