Skip to content

Commit

Permalink
Merge pull request galaxyproject#10107 from astrovsky01/user-delete
Browse files Browse the repository at this point in the history
User self-delete
  • Loading branch information
dannon authored Sep 19, 2020
2 parents c7d7d63 + 0e406df commit a5da3f5
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 16 deletions.
2 changes: 1 addition & 1 deletion client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"@babel/polyfill": "^7.10.1",
"@fortawesome/fontawesome-free": "^5.13.0",
"@fortawesome/fontawesome-svg-core": "^1.2.28",
"@fortawesome/free-regular-svg-icons": "^5.13.0",
"@fortawesome/free-regular-svg-icons": "^5.14.0",
"@fortawesome/free-solid-svg-icons": "^5.13.0",
"@fortawesome/vue-fontawesome": "^0.1.9",
"@handsontable/vue": "^2.0.0-beta1",
Expand Down
86 changes: 85 additions & 1 deletion client/src/components/User/UserPreferences.vue
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,43 @@
</div>
</div>
</b-row>
<b-row class="ml-3 mb-1">
<i class="pref-icon pt-1 fa fa-lg fa-radiation" />
<div class="pref-content pr-1">
<a href="javascript:void(0)"><b v-b-modal.modal-prevent-closing>Delete Account</b></a>
<div class="form-text text-muted">
Delete your account on this Galaxy server.
</div>
<b-modal
id="modal-prevent-closing"
centered
ref="modal"
title="Account Deletion"
title-tag="h2"
@show="resetModal"
@hidden="resetModal"
@ok="handleOk"
>
<p>
<b-alert variant="danger" :show="showDeleteError">{{ deleteError }}</b-alert>
<b>
This action cannot be undone. Your account will be permanently deleted, along with the data
contained in it.
</b>
</p>
<b-form ref="form" @submit.prevent="handleSubmit">
<b-form-group
:state="nameState"
label="Enter your user email for this account as confirmation."
label-for="Email"
invalid-feedback="Incorrect email"
>
<b-form-input id="name-input" v-model="name" :state="nameState" required></b-form-input>
</b-form-group>
</b-form>
</b-modal>
</div>
</b-row>
<p class="mt-2">
You are using <strong>{{ diskUsage }}</strong> of disk space in this Galaxy instance.
<span v-html="quotaUsageString"></span>
Expand All @@ -51,6 +88,7 @@ import _l from "utils/localization";
import axios from "axios";
import QueryStringParsing from "utils/query-string-parsing";
import { getUserPreferencesModel } from "components/User/UserPreferencesModel";
import "@fortawesome/fontawesome-svg-core";
Vue.use(BootstrapVue);
Expand All @@ -73,6 +111,10 @@ export default {
baseUrl: `${getAppRoot()}user`,
messageVariant: null,
message: null,
name: "",
nameState: null,
deleteError: "",
submittedNames: [],
};
},
created() {
Expand Down Expand Up @@ -107,6 +149,8 @@ export default {
case "logout":
activeLinks[key].onclick = this.signOut;
break;
// case "delete_user":
// activeLinks[key].onclick = this.deleteUser;
default:
activeLinks[key].action = key;
}
Expand All @@ -115,6 +159,9 @@ export default {
return activeLinks;
},
showDeleteError() {
return this.deleteError !== "";
},
},
methods: {
toggleNotifications() {
Expand Down Expand Up @@ -178,10 +225,47 @@ export default {
},
});
},
checkFormValidity() {
const valid = this.$refs.form.checkValidity();
this.nameState = valid;
return valid;
},
resetModal() {
this.name = "";
this.nameState = null;
},
handleOk(bvModalEvt) {
// Prevent modal from closing
bvModalEvt.preventDefault();
// Trigger submit handler
this.handleSubmit();
},
async handleSubmit() {
const Galaxy = getGalaxyInstance();
const userId = Galaxy.user.id;
if (!this.checkFormValidity()) {
return false;
}
if (this.email === this.name) {
this.nameState = true;
try {
await axios.delete(`${getAppRoot()}api/users/${userId}`);
} catch (e) {
if (e.response.status === 403) {
this.deleteError =
"User deletion must be configured on this instance in order to allow user self-deletion. Please contact an administrator for assistance.";
return false;
}
}
window.location.href = `${getAppRoot()}user/logout?session_csrf_token=${Galaxy.session_csrf_token}`;
} else {
this.nameState = false;
return false;
}
},
},
};
</script>

<style scoped>
.pref-content {
width: calc(100% - 3rem);
Expand Down
15 changes: 10 additions & 5 deletions client/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1340,6 +1340,11 @@
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.28.tgz#1091bdfe63b3f139441e9cba27aa022bff97d8b2"
integrity sha512-gtis2/5yLdfI6n0ia0jH7NJs5i/Z/8M/ZbQL6jXQhCthEOe5Cr5NcQPhgTvFxNOtURE03/ZqUcEskdn2M+QaBg==

"@fortawesome/fontawesome-common-types@^0.2.30":
version "0.2.30"
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.30.tgz#2f1cc5b46bd76723be41d0013a8450c9ba92b777"
integrity sha512-TsRwpTuKwFNiPhk1UfKgw7zNPeV5RhNp2Uw3pws+9gDAkPGKrtjR1y2lI3SYn7+YzyfuNknflpBA1LRKjt7hMg==

"@fortawesome/fontawesome-free@^5.13.0":
version "5.13.0"
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-free/-/fontawesome-free-5.13.0.tgz#fcb113d1aca4b471b709e8c9c168674fbd6e06d9"
Expand All @@ -1352,12 +1357,12 @@
dependencies:
"@fortawesome/fontawesome-common-types" "^0.2.28"

"@fortawesome/free-regular-svg-icons@^5.13.0":
version "5.13.0"
resolved "https://registry.yarnpkg.com/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-5.13.0.tgz#925a13d8bdda0678f71551828cac80ab47b8150c"
integrity sha512-70FAyiS5j+ANYD4dh9NGowTorNDnyvQHHpCM7FpnF7GxtDjBUCKdrFqCPzesEIpNDFNd+La3vex+jDk4nnUfpA==
"@fortawesome/free-regular-svg-icons@^5.14.0":
version "5.14.0"
resolved "https://registry.yarnpkg.com/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-5.14.0.tgz#ca513ac7699625af42938744297ac483361da043"
integrity sha512-6LCFvjGSMPoUQbn3NVlgiG4CY5iIY8fOm+to/D6QS/GvdqhDt+xZklQeERdCvVRbnFa1ITc1rJHPRXqkX5wztQ==
dependencies:
"@fortawesome/fontawesome-common-types" "^0.2.28"
"@fortawesome/fontawesome-common-types" "^0.2.30"

"@fortawesome/free-solid-svg-icons@^5.13.0":
version "5.13.0"
Expand Down
24 changes: 15 additions & 9 deletions lib/galaxy/webapps/galaxy/api/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -224,32 +224,38 @@ def update(self, trans, id, payload, **kwd):
editing_someone_else = current_user != user_to_update
is_admin = trans.api_inherit_admin or self.user_manager.is_admin(current_user)
if editing_someone_else and not is_admin:
raise exceptions.InsufficientPermissionsException('you are not allowed to update that user', id=id)
raise exceptions.InsufficientPermissionsException('You are not allowed to update that user', id=id)

self.user_deserializer.deserialize(user_to_update, payload, user=current_user, trans=trans)
return self.user_serializer.serialize_to_view(user_to_update, view='detailed')

@web.require_admin
@expose_api
def delete(self, trans, id, **kwd):
"""
DELETE /api/users/{id}
delete the user with the given ``id``
Functionality restricted based on admin status
:param id: the encoded id of the user to delete
:type id: str
:param purge: (optional) if True, purge the user
:type purge: bool
"""
user = self.get_user(trans, id)
purge = util.string_as_bool(kwd.get('purge', False))
if purge:
log.debug("Purging user %s" % user)
self.user_manager.purge(user)
user_to_update = self.user_manager.by_id(self.decode_id(id))
if trans.user_is_admin:
purge = util.string_as_bool(kwd.get('purge', False))
if purge:
log.debug("Purging user %s", user_to_update)
self.user_manager.purge(user_to_update)
else:
self.user_manager.delete(user_to_update)
else:
self.user_manager.delete(user)
return self.user_serializer.serialize_to_view(user, view='detailed')
if trans.user == user_to_update:
self.user_manager.delete(user_to_update)
else:
raise exceptions.InsufficientPermissionsException('You may only delete your own account.', id=id)
return self.user_serializer.serialize_to_view(user_to_update, view='detailed')

@web.require_admin
@expose_api
Expand Down

0 comments on commit a5da3f5

Please sign in to comment.