diff --git a/app/admin/forms.py b/app/admin/forms.py
index b063b938a45ce939764d96ecb4733775f22621ea..f24ce8f36ae2776c1382cd38c464842a2f98b70b 100644
--- a/app/admin/forms.py
+++ b/app/admin/forms.py
@@ -3,11 +3,12 @@ from app.forms import NopaqueForm
 from app.models import Role
 
 
-class AdminEditUserForm(NopaqueForm):
-    confirmed = BooleanField('Confirmed')
+class UpdateUserForm(NopaqueForm):
     role = SelectField('Role')
-    submit = SubmitField('Submit')
+    submit = SubmitField()
 
-    def __init__(self, *args, **kwargs):
+    def __init__(self, user, *args, **kwargs):
+        if 'data' not in kwargs:
+            kwargs['data'] = {'role': user.role.hashid}
         super().__init__(*args, **kwargs)
         self.role.choices = [(x.hashid, x.name) for x in Role.query.all()]
diff --git a/app/admin/json_routes.py b/app/admin/json_routes.py
index d8b454255092384f9b7eac898e7792e2330f5504..d4c21307940395a72fa5253025670c342625ee37 100644
--- a/app/admin/json_routes.py
+++ b/app/admin/json_routes.py
@@ -1,22 +1,23 @@
-from flask import current_app
-from threading import Thread
+from flask import abort, request
 from app import db
+from app.decorators import content_negotiation
 from app.models import User
 from . import bp
 
 
-@bp.route('/users/<hashid:user_id>/delete', methods=['DELETE'])
-def delete_user(user_id):
-    def _delete_user(app, user_id):
-        with app.app_context():
-            user = User.query.get(user_id)
-            user.delete()
-            db.session.commit()
-
-    User.query.get_or_404(user_id)
-    thread = Thread(
-        target=_delete_user,
-        args=(current_app._get_current_object(), user_id)
-    )
-    thread.start()
-    return {}, 202
+@bp.route('/users/<hashid:user_id>/confirmed', methods=['PUT'])
+@content_negotiation(consumes='application/json', produces='application/json')
+def update_user_role(user_id):
+    confirmed = request.json
+    if not isinstance(confirmed, bool):
+        abort(400)
+    user = User.query.get_or_404(user_id)
+    user.confirmed = confirmed
+    db.session.commit()
+    resonse_data = {
+        'message': (
+            f'User "{user.username}" is now '
+            f'{"confirmed" if confirmed else "unconfirmed"}'
+        )
+    }
+    return resonse_data, 200
diff --git a/app/admin/routes.py b/app/admin/routes.py
index 899b4dfd5b7d9ce00252b71ba2ae1e77abceb2ec..9a5401b8ed6debe0c051a42dd0f7db8a7ad942d6 100644
--- a/app/admin/routes.py
+++ b/app/admin/routes.py
@@ -1,15 +1,16 @@
 from flask import abort, flash, redirect, render_template, url_for
 from flask_breadcrumbs import register_breadcrumb
-from app import db
-from app.models import Avatar, Corpus, User
+from app import db, hashids
+from app.models import Avatar, Corpus, Role, User
 from app.settings.forms import (
-  ChangePasswordForm,
-  EditNotificationsForm,
-  EditAccountForm,
-  EditProfileForm
+    UpdateAvatarForm,
+    UpdatePasswordForm,
+    UpdateNotificationsForm,
+    UpdateAccountInformationForm,
+    UpdateProfileInformationForm
 )
 from . import bp
-from .forms import AdminEditUserForm
+from .forms import UpdateUserForm
 from app.users.utils import (
     user_endpoint_arguments_constructor as user_eac,
     user_dynamic_list_constructor as user_dlc
@@ -62,112 +63,82 @@ def user(user_id):
 @register_breadcrumb(bp, '.users.entity.settings', '<i class="material-icons left">settings</i>Settings')
 def user_settings(user_id):
     user = User.query.get_or_404(user_id)
-    # region forms
-    edit_account_form = EditAccountForm(user=user)
-    edit_profile_form = EditProfileForm(user=user)
-    change_password_form = ChangePasswordForm(user=user)
-    edit_notifications_form = EditNotificationsForm(user=user)
-    # endregion forms
-    # region handle edit profile settings form
-    if edit_account_form.validate_on_submit():
-        user.email = edit_account_form.email.data
-        user.username = edit_account_form.username.data
+    update_account_information_form = UpdateAccountInformationForm(user=user)
+    update_profile_information_form = UpdateProfileInformationForm(user=user)
+    update_avatar_form = UpdateAvatarForm(user=user)
+    update_password_form = UpdatePasswordForm(user=user)
+    update_notifications_form = UpdateNotificationsForm(user=user)
+    update_user_form = UpdateUserForm(user)
+
+    # region handle update profile information form
+    if update_profile_information_form.submit.data and update_profile_information_form.validate():
+        user.about_me = update_profile_information_form.about_me.data
+        user.location = update_profile_information_form.location.data
+        user.organization = update_profile_information_form.organization.data
+        user.website = update_profile_information_form.website.data
+        user.full_name = update_profile_information_form.full_name.data
         db.session.commit()
-        flash('Profile settings updated')
-        return redirect(url_for('.user_settings'))
-    # endregion handle edit profile settings forms
-    # region handle edit public profile information form
-    if edit_profile_form.validate_on_submit():
-        if edit_profile_form.avatar.data:
-            try:
-                Avatar.create(
-                    edit_profile_form.avatar.data,
-                    user=user
-                )
-            except (AttributeError, OSError):
-                abort(500)
-        user.about_me = edit_profile_form.about_me.data
-        user.location = edit_profile_form.location.data
-        user.organization = edit_profile_form.organization.data
-        user.website = edit_profile_form.website.data
-        user.full_name = edit_profile_form.full_name.data
+        flash('Your changes have been saved')
+        return redirect(url_for('.user_settings', user_id=user.id))
+    # endregion handle update profile information form
+
+    # region handle update avatar form
+    if update_avatar_form.submit.data and update_avatar_form.validate():
+        try:
+            Avatar.create(
+                update_avatar_form.avatar.data,
+                user=user
+            )
+        except (AttributeError, OSError):
+            abort(500)
         db.session.commit()
         flash('Your changes have been saved')
-        return redirect(url_for('.user_settings'))
-    # endregion handle edit public profile information form
-    # region handle change_password_form POST
-    if change_password_form.validate_on_submit():
-        user.password = change_password_form.new_password.data
+        return redirect(url_for('.user_settings', user_id=user.id))
+    # endregion handle update avatar form
+
+    # region handle update account information form
+    if update_account_information_form.submit.data and update_account_information_form.validate():
+        user.email = update_account_information_form.email.data
+        user.username = update_account_information_form.username.data
+        db.session.commit()
+        flash('Profile settings updated')
+        return redirect(url_for('.user_settings', user_id=user.id))
+    # endregion handle update account information form
+
+    # region handle update password form
+    if update_password_form.submit.data and update_password_form.validate():
+        user.password = update_password_form.new_password.data
         db.session.commit()
         flash('Your changes have been saved')
-        return redirect(url_for('.user_settings'))
-    # endregion handle change_password_form POST
-    # region handle edit_notification_settings_form POST
-    if edit_notifications_form.validate_on_submit():
+        return redirect(url_for('.user_settings', user_id=user.id))
+    # endregion handle update password form
+
+    # region handle update notifications form
+    if update_notifications_form.submit.data and update_notifications_form.validate():
         user.setting_job_status_mail_notification_level = \
-            edit_notifications_form.job_status_mail_notification_level.data
+            update_notifications_form.job_status_mail_notification_level.data
+        db.session.commit()
+        flash('Your changes have been saved')
+        return redirect(url_for('.user_settings', user_id=user.id))
+    # endregion handle update notifications form
+
+    # region handle update user form
+    if update_user_form.submit.data and update_user_form.validate():
+        role_id = hashids.decode(update_user_form.role.data)
+        user.role = Role.query.get(role_id)
         db.session.commit()
         flash('Your changes have been saved')
-        return redirect(url_for('.user_settings'))
-    # endregion handle edit_notification_settings_form POST
+        return redirect(url_for('.user_settings', user_id=user.id))
+    # endregion handle update user form
+
     return render_template(
         'admin/user_settings.html.j2',
         title='Settings',
-        change_password_form=change_password_form,
-        edit_account_form=edit_account_form,
-        edit_notifications_form=edit_notifications_form,
-        edit_profile_form=edit_profile_form,
+        update_account_information_form=update_account_information_form,
+        update_avatar_form=update_avatar_form,
+        update_notifications_form=update_notifications_form,
+        update_password_form=update_password_form,
+        update_profile_information_form=update_profile_information_form,
+        update_user_form=update_user_form,
         user=user
     )
-
-
-
-# @bp.route('/users/<hashid:user_id>/edit', methods=['GET', 'POST'])
-# @register_breadcrumb(bp, '.users.entity.edit', 'Edit', endpoint_arguments_constructor=user_eac)
-# def edit_user(user_id):
-#     user = User.query.get_or_404(user_id)
-#     admin_edit_user_form = AdminEditUserForm(
-#         data={'confirmed': user.confirmed, 'role': user.role.hashid},
-#         prefix='admin-edit-user-form'
-#     )
-#     edit_profile_settings_form = EditAccountForm(
-#         user,
-#         data=user.to_json_serializeable(),
-#         prefix='edit-profile-settings-form'
-#     )
-#     edit_notification_settings_form = EditNotificationsForm(
-#         data=user.to_json_serializeable(),
-#         prefix='edit-notification-settings-form'
-#     )
-#     if (admin_edit_user_form.submit.data
-#             and admin_edit_user_form.validate()):
-#         user.confirmed = admin_edit_user_form.confirmed.data
-#         role_id = hashids.decode(admin_edit_user_form.role.data)
-#         user.role = Role.query.get(role_id)
-#         db.session.commit()
-#         flash('Your changes have been saved')
-#         return redirect(url_for('.edit_user', user_id=user.id))
-#     if (edit_profile_settings_form.submit.data
-#             and edit_profile_settings_form.validate()):
-#         user.email = edit_profile_settings_form.email.data
-#         user.username = edit_profile_settings_form.username.data
-#         db.session.commit()
-#         flash('Your changes have been saved')
-#         return redirect(url_for('.edit_user', user_id=user.id))
-#     if (edit_notification_settings_form.submit.data
-#             and edit_notification_settings_form.validate()):
-#         user.setting_job_status_mail_notification_level = \
-#             UserSettingJobStatusMailNotificationLevel[
-#                 edit_notification_settings_form.job_status_mail_notification_level.data  # noqa
-#             ]
-#         db.session.commit()
-#         flash('Your changes have been saved')
-#         return redirect(url_for('.edit_user', user_id=user.id))
-#     return render_template(
-#         'admin/edit_user.html.j2',
-#         admin_edit_user_form=admin_edit_user_form,
-#         edit_profile_settings_form=edit_profile_settings_form,
-#         edit_notification_settings_form=edit_notification_settings_form,
-#         title='Edit user',
-#         user=user
-#     )
diff --git a/app/api/schemas.py b/app/api/schemas.py
index f0792f7c4a32c5ca8c92b3b6da06bf55feee1c54..74f4cb2acd234ebce50edadb7a2c258658c3744d 100644
--- a/app/api/schemas.py
+++ b/app/api/schemas.py
@@ -2,7 +2,6 @@ from apifairy.fields import FileField
 from marshmallow import validate, validates, ValidationError
 from marshmallow.decorators import post_dump
 from app import ma
-from app.auth import USERNAME_REGEX
 from app.models import (
     Job,
     JobStatus,
@@ -142,7 +141,10 @@ class UserSchema(ma.SQLAlchemySchema):
     username = ma.auto_field(
         validate=[
             validate.Length(min=1, max=64),
-            validate.Regexp(USERNAME_REGEX, error='Usernames must have only letters, numbers, dots or underscores')
+            validate.Regexp(
+                User.username_pattern,
+                error='Usernames must have only letters, numbers, dots or underscores'
+            )
         ]
     )
     email = ma.auto_field(validate=validate.Email())
diff --git a/app/auth/__init__.py b/app/auth/__init__.py
index 505e7e424b80a144a62ef2c6caaac7f2796c68f5..6f6ba82da7ab031509e4865c49b9f0c13c0f8f5a 100644
--- a/app/auth/__init__.py
+++ b/app/auth/__init__.py
@@ -1,8 +1,5 @@
 from flask import Blueprint
 
 
-USERNAME_REGEX = '^[A-Za-zÄÖÜäöüß0-9_.]*$'
-
-
 bp = Blueprint('auth', __name__)
 from . import routes
diff --git a/app/auth/forms.py b/app/auth/forms.py
index 5655b3af9fbcb697757ad39e39d4c5c5c0c08441..43db510ae5b29a5926e7891825fbe161e22e76c6 100644
--- a/app/auth/forms.py
+++ b/app/auth/forms.py
@@ -8,7 +8,6 @@ from wtforms import (
 from wtforms.validators import InputRequired, Email, EqualTo, Length, Regexp
 from app.forms import NopaqueForm
 from app.models import User
-from . import USERNAME_REGEX
 
 
 class RegistrationForm(NopaqueForm):
@@ -22,7 +21,7 @@ class RegistrationForm(NopaqueForm):
             InputRequired(),
             Length(max=64),
             Regexp(
-                USERNAME_REGEX,
+                User.username_pattern,
                 message=(
                     'Usernames must have only letters, numbers, dots or '
                     'underscores'
diff --git a/app/forms.py b/app/forms.py
index 55e80d01ec1b2d4a960a2c6f631a3246bba7671d..6ac58347d86dab0bd7980573224c8d8f53cefd96 100644
--- a/app/forms.py
+++ b/app/forms.py
@@ -1,9 +1,26 @@
 from flask_wtf import FlaskForm
+from wtforms.validators import ValidationError
 import re
 
 
+form_prefix_pattern = re.compile(r'(?<!^)(?=[A-Z])')
+
+
+def LimitFileSize(max_size_mb):
+    max_size_b = max_size_mb * 1024 * 1024
+    def file_length_check(form, field):
+        if len(field.data.read()) >= max_size_b:
+            raise ValidationError(
+                f'File size must be less or equal than {max_size_mb} MB'
+            )
+        field.data.seek(0)
+    return file_length_check
+
+
 class NopaqueForm(FlaskForm):
     def __init__(self, *args, **kwargs):
         if 'prefix' not in kwargs:
-            kwargs['prefix'] = re.sub(r'(?<!^)(?=[A-Z])', '-', self.__class__.__name__).lower()
+            kwargs['prefix'] = \
+                form_prefix_pattern.sub('-', self.__class__.__name__).lower()
         super().__init__(*args, **kwargs)
+
diff --git a/app/settings/forms.py b/app/settings/forms.py
index 2cfccf5fe3dc8c187c4b9271265c84107cfa6d3a..6778bbe6ad236a9a7d5f7044588dac5511e9437e 100644
--- a/app/settings/forms.py
+++ b/app/settings/forms.py
@@ -1,6 +1,6 @@
 from flask_login import current_user
+from flask_wtf.file import FileField, FileRequired
 from wtforms import (
-    FileField,
     PasswordField,
     SelectField,
     StringField,
@@ -15,13 +15,11 @@ from wtforms.validators import (
     Length,
     Regexp
 )
-from app.forms import NopaqueForm
+from app.forms import NopaqueForm, LimitFileSize
 from app.models import User, UserSettingJobStatusMailNotificationLevel
-from app.auth import USERNAME_REGEX
-from app.wtf_validators import FileSizeLimit
 
 
-class EditAccountForm(NopaqueForm):
+class UpdateAccountInformationForm(NopaqueForm):
     email = StringField(
         'E-Mail',
         validators=[DataRequired(), Length(max=254), Email()]
@@ -32,7 +30,7 @@ class EditAccountForm(NopaqueForm):
             DataRequired(),
             Length(max=64),
             Regexp(
-                USERNAME_REGEX,
+                User.username_pattern,
                 message=(
                     'Usernames must have only letters, numbers, dots or '
                     'underscores'
@@ -42,8 +40,7 @@ class EditAccountForm(NopaqueForm):
     )
     submit = SubmitField()
     
-    def __init__(self, *args, **kwargs):
-        user = kwargs.get('user', current_user._get_current_object())
+    def __init__(self, *args, user=current_user, **kwargs):
         if 'data' not in kwargs:
             kwargs['data'] = user.to_json_serializeable()
         super().__init__(*args, **kwargs)
@@ -59,15 +56,8 @@ class EditAccountForm(NopaqueForm):
                 and User.query.filter_by(username=field.data).first()):
             raise ValidationError('Username already in use')
 
-    def validate_on_submit(self):
-        return self.submit.data and self.validate()
 
-
-class EditProfileForm(NopaqueForm):
-    avatar = FileField(
-        'Image File', 
-        [FileSizeLimit(max_size_in_mb=2)]
-    )
+class UpdateProfileInformationForm(NopaqueForm):
     full_name = StringField(
         'Full name',
         validators=[Length(max=128)]
@@ -98,21 +88,22 @@ class EditProfileForm(NopaqueForm):
     )
     submit = SubmitField()
 
-    def __init__(self, *args, **kwargs):
+    def __init__(self, *args, user=current_user, **kwargs):
         if 'data' not in kwargs:
-            user = current_user._get_current_object()
             kwargs['data'] = user.to_json_serializeable()
         super().__init__(*args, **kwargs)
 
-    def validate_image_file(self, field):
-        if not field.data.filename.lower().endswith('.jpg' or '.png' or '.jpeg'):
-            raise ValidationError('only .jpg, .png and .jpeg!')
 
-    def validate_on_submit(self):
-        return self.submit.data and self.validate()
+class UpdateAvatarForm(NopaqueForm):
+    avatar = FileField('File', validators=[FileRequired(), LimitFileSize(2)])
+    submit = SubmitField()
 
+    def validate_avatar(self, field):
+        valid_mimetypes = ['image/jpeg', 'image/png']
+        if field.data.mimetype not in valid_mimetypes:
+            raise ValidationError('JPEG and PNG files only!')
 
-class ChangePasswordForm(NopaqueForm):
+class UpdatePasswordForm(NopaqueForm):
     password = PasswordField('Old password', validators=[DataRequired()])
     new_password = PasswordField(
         'New password',
@@ -130,8 +121,7 @@ class ChangePasswordForm(NopaqueForm):
     )
     submit = SubmitField()
 
-    def __init__(self, *args, **kwargs):
-        user = kwargs.get('user', current_user._get_current_object())
+    def __init__(self, *args, user=current_user, **kwargs):
         super().__init__(*args, **kwargs)
         self.user = user
 
@@ -139,11 +129,8 @@ class ChangePasswordForm(NopaqueForm):
         if not self.user.verify_password(field.data):
             raise ValidationError('Invalid password')
 
-    def validate_on_submit(self):
-        return self.submit.data and self.validate()
 
-
-class EditNotificationsForm(NopaqueForm):
+class UpdateNotificationsForm(NopaqueForm):
     job_status_mail_notification_level = SelectField(
         'Job status mail notification level',
         choices=[
@@ -154,11 +141,7 @@ class EditNotificationsForm(NopaqueForm):
     )
     submit = SubmitField()
 
-    def __init__(self, *args, **kwargs):
+    def __init__(self, *args, user=current_user, **kwargs):
         if 'data' not in kwargs:
-            user = current_user._get_current_object()
             kwargs['data'] = user.to_json_serializeable()
         super().__init__(*args, **kwargs)
-
-    def validate_on_submit(self):
-        return self.submit.data and self.validate()
diff --git a/app/settings/routes.py b/app/settings/routes.py
index 7a9b8a0938c5da374ce04302f8f739c5b01ceb53..70b69d6ca7e9b6d7aaea97fb2a158667a9d2c68c 100644
--- a/app/settings/routes.py
+++ b/app/settings/routes.py
@@ -5,10 +5,11 @@ from app import db
 from app.models import Avatar
 from . import bp
 from .forms import (
-  ChangePasswordForm,
-  EditNotificationsForm,
-  EditAccountForm,
-  EditProfileForm
+    UpdateAvatarForm,
+    UpdatePasswordForm,
+    UpdateNotificationsForm,
+    UpdateAccountInformationForm,
+    UpdateProfileInformationForm
 )
 
 
@@ -16,61 +17,72 @@ from .forms import (
 @register_breadcrumb(bp, '.', '<i class="material-icons left">settings</i>Settings')
 @login_required
 def settings():
-    user = current_user._get_current_object()
-    # region forms
-    edit_account_form = EditAccountForm()
-    edit_profile_form = EditProfileForm()
-    change_password_form = ChangePasswordForm()
-    edit_notifications_form = EditNotificationsForm()
-    # endregion forms
-    # region handle edit profile settings form
-    if edit_account_form.validate_on_submit():
-        user.email = edit_account_form.email.data
-        user.username = edit_account_form.username.data
+    user = current_user
+    update_account_information_form = UpdateAccountInformationForm()
+    update_profile_information_form = UpdateProfileInformationForm()
+    update_avatar_form = UpdateAvatarForm()
+    update_password_form = UpdatePasswordForm()
+    update_notifications_form = UpdateNotificationsForm()
+
+    # region handle update profile information form
+    if update_profile_information_form.submit.data and update_profile_information_form.validate():
+        user.about_me = update_profile_information_form.about_me.data
+        user.location = update_profile_information_form.location.data
+        user.organization = update_profile_information_form.organization.data
+        user.website = update_profile_information_form.website.data
+        user.full_name = update_profile_information_form.full_name.data
         db.session.commit()
-        flash('Profile settings updated')
+        flash('Your changes have been saved')
         return redirect(url_for('.settings'))
-    # endregion handle edit profile settings forms
-    # region handle edit public profile information form
-    if edit_profile_form.validate_on_submit():
-        if edit_profile_form.avatar.data:
-            try:
-                Avatar.create(
-                    edit_profile_form.avatar.data,
-                    user=user
-                )
-            except (AttributeError, OSError):
-                abort(500)
-        user.about_me = edit_profile_form.about_me.data
-        user.location = edit_profile_form.location.data
-        user.organization = edit_profile_form.organization.data
-        user.website = edit_profile_form.website.data
-        user.full_name = edit_profile_form.full_name.data
+    # endregion handle update profile information form
+
+    # region handle update avatar form
+    if update_avatar_form.submit.data and update_avatar_form.validate():
+        try:
+            Avatar.create(
+                update_avatar_form.avatar.data,
+                user=user
+            )
+        except (AttributeError, OSError):
+            abort(500)
         db.session.commit()
         flash('Your changes have been saved')
         return redirect(url_for('.settings'))
-    # endregion handle edit public profile information form
-    # region handle change_password_form POST
-    if change_password_form.validate_on_submit():
-        user.password = change_password_form.new_password.data
+    # endregion handle update avatar form
+
+    # region handle update account information form
+    if update_account_information_form.submit.data and update_account_information_form.validate():
+        user.email = update_account_information_form.email.data
+        user.username = update_account_information_form.username.data
+        db.session.commit()
+        flash('Profile settings updated')
+        return redirect(url_for('.settings'))
+    # endregion handle update account information form
+
+    # region handle update password form
+    if update_password_form.submit.data and update_password_form.validate():
+        user.password = update_password_form.new_password.data
         db.session.commit()
         flash('Your changes have been saved')
         return redirect(url_for('.settings'))
-    # endregion handle change_password_form POST
-    # region handle edit_notification_settings_form POST
-    if edit_notifications_form.validate_on_submit():
+    # endregion handle update password form
+
+    # region handle update notifications form
+    if update_notifications_form.submit.data and update_notifications_form.validate():
         user.setting_job_status_mail_notification_level = \
-            edit_notifications_form.job_status_mail_notification_level.data
+            update_notifications_form.job_status_mail_notification_level.data
         db.session.commit()
         flash('Your changes have been saved')
         return redirect(url_for('.settings'))
-    # endregion handle edit_notification_settings_form POST
+    # endregion handle update notifications form
+
     return render_template(
         'settings/settings.html.j2',
         title='Settings',
-        change_password_form=change_password_form,
-        edit_account_form=edit_account_form,
-        edit_notifications_form=edit_notifications_form,
-        edit_profile_form=edit_profile_form,
+        update_account_information_form=update_account_information_form,
+        update_avatar_form=update_avatar_form,
+        update_notifications_form=update_notifications_form,
+        update_password_form=update_password_form,
+        update_profile_information_form=update_profile_information_form,
         user=user
     )
diff --git a/app/static/js/Requests/admin/admin.js b/app/static/js/Requests/admin/admin.js
new file mode 100644
index 0000000000000000000000000000000000000000..77fdb6b12105658507dae35a14e807256448ca79
--- /dev/null
+++ b/app/static/js/Requests/admin/admin.js
@@ -0,0 +1,20 @@
+/*****************************************************************************
+* Admin                                                                      *
+* Fetch requests for /admin routes                                           *
+*****************************************************************************/
+Requests.admin = {};
+
+Requests.admin.users = {};
+
+Requests.admin.users.entity = {};
+
+Requests.admin.users.entity.confirmed = {};
+
+Requests.admin.users.entity.confirmed.update = (userId, value) => {
+  let input = `/admin/users/${userId}/confirmed`;
+  let init = {
+    method: 'PUT',
+    body: JSON.stringify(value)
+  };
+  return Requests.JSONfetch(input, init);
+};
diff --git a/app/templates/_scripts.html.j2 b/app/templates/_scripts.html.j2
index bed2aef2ce9a4c91e1ec8ca55d83453bbc5fe142..45e5457bf6ba668d964c658867a543fb2a386b6f 100644
--- a/app/templates/_scripts.html.j2
+++ b/app/templates/_scripts.html.j2
@@ -58,6 +58,7 @@
   filters='rjsmin',
   output='gen/Requests.%(version)s.js',
   'js/Requests/Requests.js',
+  'js/Requests/admin/admin.js',
   'js/Requests/contributions/contributions.js',
   'js/Requests/contributions/spacy_nlp_pipeline_models.js',
   'js/Requests/contributions/tesseract_ocr_pipeline_models.js',
diff --git a/app/templates/admin/user.html.j2 b/app/templates/admin/user.html.j2
index dc5af986209a98928940fd0a96d5d6fccc4a9b2b..0512db75e03488fee1bbdb4a0b0da791708f5685 100644
--- a/app/templates/admin/user.html.j2
+++ b/app/templates/admin/user.html.j2
@@ -96,7 +96,7 @@
   </div>
   <div class="modal-footer">
     <a class="btn modal-close waves-effect waves-light">Cancel</a>
-    <a href="{{ url_for('.delete_user', user_id=user.id) }}" class="btn red modal-close waves-effect waves-light"><i class="material-icons left">delete</i>Delete</a>
+    <a class="btn red modal-close waves-effect waves-light"><i class="material-icons left">delete</i>Delete</a>
   </div>
 </div>
 {% endblock modals %}
diff --git a/app/templates/admin/user_settings.html.j2 b/app/templates/admin/user_settings.html.j2
index 49d8ba4d0f669b2ef50e743945e31345f4f147db..66d6250e5d95daaf679e036bdbe04ffe2e65c2ac 100644
--- a/app/templates/admin/user_settings.html.j2
+++ b/app/templates/admin/user_settings.html.j2
@@ -1,6 +1,74 @@
 {% extends "settings/settings.html.j2" %}
 
-{% block page_content %}
+{% block admin_settings %}
+<div class="col s12 l4">
+  <h4>Administrator Settings</h4>
+  <p>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam 
+  nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, 
+  sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. 
+  Stet clita kasd gubergren, no sea tak</p>
+</div>
+<div class="col s12 l8">
+  <br>
+  <ul class="collapsible no-autoinit settings-collapsible">
+    <li>
+      <div class="collapsible-header" style="justify-content: space-between;">
+        <span>Confirmation status</span>
+        <i class="caret material-icons">keyboard_arrow_right</i>
+      </div>
+      <div class="collapsible-body">
+        <div class="row">
+          <div class="col s12 l1">
+            <p><i class="material-icons">check</i></p>
+          </div>
+          <div class="col s12 l7">
+            <p>
+              Confirmed<br>
+              <span class="light">Change confirmation status manually.</span>
+            </p>
+          </div>
+          <div class="col s3 l4">
+            <div class="switch">
+              <label>
+                unconfirmed
+                <input {% if user.confirmed %}checked{% endif %} id="user-confirmed-switch" type="checkbox">
+                <span class="lever"></span>
+                confirmed
+              </label>
+            </div>
+          </div>
+        </div>
+      </div>
+    </li>
+    <li>
+      <div class="collapsible-header" style="justify-content: space-between;">
+        <span>Role</span>
+        <i class="caret material-icons">keyboard_arrow_right</i>
+      </div>
+      <div class="collapsible-body">
+        <form method="POST">
+          {{ update_user_form.hidden_tag() }}
+          {{ wtf.render_field(update_user_form.role, material_icon='manage_accounts') }}
+          <div class="right-align">
+            {{ wtf.render_field(update_user_form.submit, material_icon='send') }}
+          </div>
+        </form>
+      </div>
+    </li>
+  </ul>
+</div>
+{% endblock admin_settings %}
+
+{% block scripts %}
 {{ super() }}
-ADMIN ADDITIONS
-{% endblock page_content %}
+<script>
+let userConfirmedSwitchElement = document.querySelector('#user-confirmed-switch');
+userConfirmedSwitchElement.addEventListener('change', (event) => {
+  let newConfirmed = userConfirmedSwitchElement.checked;
+  Requests.admin.users.entity.confirmed.update({{ user.hashid|tojson }}, newConfirmed)
+    .catch((response) => {
+      userConfirmedSwitchElement.checked = !userConfirmedSwitchElement;
+    });
+});
+</script>
+{% endblock scripts %}
diff --git a/app/templates/base.html.j2 b/app/templates/base.html.j2
index a924e9b76d5574b67f1e3e747992f7570ee1abf7..82132828d8562d1196ca96a0fc9413e55603a944 100644
--- a/app/templates/base.html.j2
+++ b/app/templates/base.html.j2
@@ -50,8 +50,4 @@
 {% block scripts %}
 {{ super() }}
 {% include "_scripts.html.j2" %}
-{% set page_script = self._TemplateReference__context.name|replace('.html.j2', '.js.j2') %}
-<script>
-{% include page_script ignore missing %}
-</script>
 {% endblock scripts %}
diff --git a/app/templates/settings/settings.html.j2 b/app/templates/settings/settings.html.j2
index b6ec4fa53e86e3d9d872a8a4a10c4a53da534629..004a553add1c526962247b273eba179ca4a26992 100644
--- a/app/templates/settings/settings.html.j2
+++ b/app/templates/settings/settings.html.j2
@@ -7,8 +7,7 @@
     <div class="col s12">
       <h1 id="title">{{ title }}</h1>
     </div>
-  </div>
-  <div class="row">
+
     <div class="col s12 l4">
       <h4>Profile Settings</h4>
       <p>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam 
@@ -21,7 +20,7 @@
       <ul class="collapsible no-autoinit settings-collapsible">
         <li>
           <div class="collapsible-header" style="justify-content: space-between;">
-            <span>Profile Privacy Settings</span>
+            <span>Profile Privacy</span>
             <i class="material-icons caret">keyboard_arrow_right</i>
           </div>
           <div class="collapsible-body">
@@ -62,38 +61,47 @@
             <span>Profile information</span>
             <i class="material-icons caret">keyboard_arrow_right</i>
           </div>
+          <div class="collapsible-body">
+            <form method="POST">
+              {{ update_profile_information_form.hidden_tag() }}
+              {{ wtf.render_field(update_profile_information_form.full_name, material_icon='badge') }}
+              {{ wtf.render_field(update_profile_information_form.about_me, material_icon='description', id='about-me-textfield') }}
+              {{ wtf.render_field(update_profile_information_form.website, material_icon='laptop') }}
+              {{ wtf.render_field(update_profile_information_form.organization, material_icon='business') }}
+              {{ wtf.render_field(update_profile_information_form.location, material_icon='location_on') }}
+              <div class="right-align">
+                {{ wtf.render_field(update_profile_information_form.submit, material_icon='send') }}
+              </div>              
+            </form>
+          </div>
+        </li>
+        <li>
+          <div class="collapsible-header" style="justify-content: space-between;">
+            <span>Avatar</span>
+            <i class="material-icons caret">keyboard_arrow_right</i>
+          </div>
           <div class="collapsible-body">
             <form method="POST" enctype="multipart/form-data">
-              {{ edit_profile_form.hidden_tag() }}
-              {{ wtf.render_field(edit_profile_form.full_name, material_icon='badge') }}
-              {{ wtf.render_field(edit_profile_form.about_me, material_icon='description', id='about-me-textfield') }}
-              {{ wtf.render_field(edit_profile_form.website, material_icon='laptop') }}
-              {{ wtf.render_field(edit_profile_form.organization, material_icon='business') }}
-              {{ wtf.render_field(edit_profile_form.location, material_icon='location_on') }}
-              <p></p>
+              {{ update_avatar_form.hidden_tag() }}
               <div class="row">
-                <div class="col s12 m2">
-                  <img src="{{ url_for('users.user_avatar', user_id=user.id) }}" alt="user-image" class="circle responsive-img" id="avatar">
-                </div>
-                <div class="col s12 m6">
-                  {{ wtf.render_field(edit_profile_form.avatar, accept='image/jpeg, image/png, image/gif', placeholder='Choose an image file', id='avatar-upload') }}
+                <div class="col s12 l2">
+                  <img src="{{ url_for('users.user_avatar', user_id=user.id) }}" alt="Avatar" class="circle responsive-img" id="update-avatar-form-avatar-preview">
                 </div>
-                <div class="col s12 m1">
-                  <a class="btn-floating red waves-effect waves-light modal-trigger" style="margin-top:15px;" href="#delete-avatar-modal"><i class="material-icons">delete</i></a>
+                <div class="col s12 l10">
+                  <br class="hide-on-med-and-down">
+                  {{ wtf.render_field(update_avatar_form.avatar, accept='image/jpeg, image/png, image/gif', placeholder='Choose a JPEG or PNG file') }}
                 </div>
               </div>
-              <br>
-              <p></p>
               <div class="right-align">
-                {{ wtf.render_field(edit_profile_form.submit, material_icon='send') }}
+                <a class="btn red waves-effect waves-light modal-trigger" href="#delete-avatar-modal"><i class="material-icons left">delete</i>Delete</a>
+                {{ wtf.render_field(update_avatar_form.submit, material_icon='send') }}
               </div>              
             </form>
           </div>
         </li>
       </ul>
     </div>
-  </div>
-  <div class="row">
+
     <div class="col s12 l4">
       <h4>General Settings</h4>
       <p>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam 
@@ -110,60 +118,53 @@
             <i class="caret material-icons">keyboard_arrow_right</i>
           </div>
           <div class="collapsible-body">
-            <form method="POST" enctype="multipart/form-data">
-              {{ edit_account_form.hidden_tag() }}
-              {{ wtf.render_field(edit_account_form.username, material_icon='person') }}
-              {{ wtf.render_field(edit_account_form.email, material_icon='email') }}
+            <form method="POST">
+              {{ update_account_information_form.hidden_tag() }}
+              {{ wtf.render_field(update_account_information_form.username, material_icon='person') }}
+              {{ wtf.render_field(update_account_information_form.email, material_icon='email') }}
               <div class="right-align">
-                {{ wtf.render_field(edit_account_form.submit, material_icon='send') }}
+                <a class="btn red waves-effect waves-light modal-trigger" href="#delete-user"><i class="material-icons left">delete</i>Delete</a>
+                {{ wtf.render_field(update_account_information_form.submit, material_icon='send') }}
               </div>
             </form>
-            <br>
-            <div class="divider"></div>
-            <p>Deleting an account has the following effects:</p>
-            <ul>
-              <li>All data associated with your corpora and jobs will be permanently deleted.</li>
-              <li>All settings will be permanently deleted.</li>
-            </ul>
-            <div class="right-align">
-              <a class="btn red waves-effect waves-light modal-trigger" href="#delete-user"><i class="material-icons left">delete</i>Delete</a>
-            </div>
           </div>
         </li>
         <li>
           <div class="collapsible-header" style="justify-content: space-between;">
-            <span>Notifications</span>
+            <span>Change Password</span>
             <i class="caret material-icons">keyboard_arrow_right</i>
-          </div>
+          </div>          
           <div class="collapsible-body">
             <form method="POST">
-              {{ edit_notifications_form.hidden_tag() }}
-              {{ wtf.render_field(edit_notifications_form.job_status_mail_notification_level, material_icon='notifications') }}
+              {{ update_password_form.hidden_tag() }}
+              {{ wtf.render_field(update_password_form.password, material_icon='vpn_key') }}
+              {{ wtf.render_field(update_password_form.new_password, material_icon='vpn_key') }}
+              {{ wtf.render_field(update_password_form.new_password_2, material_icon='vpn_key') }}
               <div class="right-align">
-                {{ wtf.render_field(edit_notifications_form.submit, material_icon='send') }}
+                {{ wtf.render_field(update_password_form.submit, material_icon='send') }}
               </div>
             </form>
           </div>
         </li>
         <li>
           <div class="collapsible-header" style="justify-content: space-between;">
-            <span>Change Password</span>
+            <span>Notifications</span>
             <i class="caret material-icons">keyboard_arrow_right</i>
-          </div>          
+          </div>
           <div class="collapsible-body">
             <form method="POST">
-              {{ change_password_form.hidden_tag() }}
-              {{ wtf.render_field(change_password_form.password, material_icon='vpn_key') }}
-              {{ wtf.render_field(change_password_form.new_password, material_icon='vpn_key') }}
-              {{ wtf.render_field(change_password_form.new_password_2, material_icon='vpn_key') }}
+              {{ update_notifications_form.hidden_tag() }}
+              {{ wtf.render_field(update_notifications_form.job_status_mail_notification_level, material_icon='notifications') }}
               <div class="right-align">
-                {{ wtf.render_field(change_password_form.submit, material_icon='send') }}
+                {{ wtf.render_field(update_notifications_form.submit, material_icon='send') }}
               </div>
             </form>
           </div>
         </li>
       </ul>
     </div>
+
+    {% block admin_settings %}{% endblock admin_settings %}
   </div>
 </div>
 {% endblock page_content %}
@@ -184,11 +185,16 @@
 <div class="modal" id="delete-user">
   <div class="modal-content">
     <h4>Confirm User deletion</h4>
-    <p>Do you really want to delete the User <b>{{ user.username }}</b>? All files will be permanently deleted!</p>
+    <p>Do you really want to delete the User <b>{{ user.username }}</b>?</p>
+    <p>Deleting an account has the following effects:</p>
+    <ul>
+      <li>All data (Jobs, Corpora, ...) associated with the account will be permanently deleted.</li>
+      <li>All settings will be permanently deleted.</li>
+    </ul>
   </div>
   <div class="modal-footer">
     <a class="btn modal-close waves-effect waves-light">Cancel</a>
-    <a class="btn modal-close red waves-effect waves-light" id="delete-user-button">Delete</a>
+    <a class="btn modal-close red waves-effect waves-light" id="delete-user">Delete</a>
   </div>
 </div>
 {% endblock modals %}
@@ -196,25 +202,25 @@
 {% block scripts %}
 {{ super() }}
 <script>
-let deleteButtonElement = document.querySelector('#delete-avatar');
-let avatarElement = document.querySelector('#avatar');
-let avatarUploadElement = document.querySelector('#avatar-upload');
+let deleteAvatarButtonElement = document.querySelector('#delete-avatar');
+let avatarPreviewElement = document.querySelector('#update-avatar-form-avatar-preview');
+let avatarUploadElement = document.querySelector('#update-avatar-form-avatar');
 
 avatarUploadElement.addEventListener('change', () => {
   let file = avatarUploadElement.files[0];
-  avatarElement.src = URL.createObjectURL(file);
+  avatarPreviewElement.src = URL.createObjectURL(file);
 });
 
-deleteButtonElement.addEventListener('click', () => {
+deleteAvatarButtonElement.addEventListener('click', () => {
   Requests.settings.entity.deleteAvatar({{ user.hashid|tojson }})
     .then(
       (response) => {
-        avatarElement.src = {{ url_for('static', filename='images/user_avatar.png')|tojson }};
+        avatarPreviewElement.src = {{ url_for('static', filename='images/user_avatar.png')|tojson }};
       }
     );
 });
 
-document.querySelector('#delete-user-button').addEventListener('click', (event) => {
+document.querySelector('#delete-user').addEventListener('click', (event) => {
   Requests.settings.entity.delete({{ user.hashid|tojson }})
     .then((response) => {window.location.href = '/';});
 });
diff --git a/app/wtf_validators.py b/app/wtf_validators.py
deleted file mode 100644
index 326ef7e709c7d13fb28327dd5daaa95febd117a9..0000000000000000000000000000000000000000
--- a/app/wtf_validators.py
+++ /dev/null
@@ -1,9 +0,0 @@
-from wtforms.validators import ValidationError
-
-def FileSizeLimit(max_size_in_mb):
-    max_bytes = max_size_in_mb*1024*1024
-    def file_length_check(form, field):
-        if len(field.data.read()) > max_bytes:
-            raise ValidationError(f"File size must be less than {max_size_in_mb}MB")
-        field.data.seek(0)
-    return file_length_check