Move job and user delete functions to utils.py

This commit is contained in:
Stephan Porada 2019-09-17 16:31:41 +02:00
parent 09f7d7ac68
commit 0d060f0cbf
6 changed files with 80 additions and 55 deletions

View File

@ -2,13 +2,13 @@ from flask import (abort, current_app, flash, redirect, request,
render_template, url_for, send_from_directory) render_template, url_for, send_from_directory)
from flask_login import current_user, login_required from flask_login import current_user, login_required
from .forms import EditProfileAdminForm from .forms import EditProfileAdminForm
from ..models import Corpus, User, Role from ..models import Corpus, User, Role, Job
from ..tables import AdminUserTable, AdminUserItem from ..tables import AdminUserTable, AdminUserItem
from . import admin from . import admin
from ..decorators import admin_required from ..decorators import admin_required
from .. import db from .. import db
import os import threading
import datetime from app.utils import background_delete_user
@admin.route('/overview', methods=['GET', 'POST']) @admin.route('/overview', methods=['GET', 'POST'])
@ -40,9 +40,10 @@ def admin_user_page(user_id):
@login_required @login_required
@admin_required @admin_required
def admin_delete_user(user_id): def admin_delete_user(user_id):
selected_user = User.query.filter_by(id=user_id).first() delete_thread = threading.Thread(target=background_delete_user,
db.session.delete(selected_user) args=(current_app._get_current_object(),
db.session.commit() user_id))
delete_thread.start()
flash('User {} has been deleted!'.format(user_id)) flash('User {} has been deleted!'.format(user_id))
return redirect(url_for('admin.for_admins_only')) return redirect(url_for('admin.for_admins_only'))

View File

@ -6,9 +6,9 @@ from .. import db
from .forms import (ChangePasswordForm, LoginForm, PasswordResetForm, from .forms import (ChangePasswordForm, LoginForm, PasswordResetForm,
PasswordResetRequestForm, RegistrationForm, EditProfileForm) PasswordResetRequestForm, RegistrationForm, EditProfileForm)
from ..email import send_email from ..email import send_email
from ..models import User, Job from ..models import User
import logging
import threading import threading
from app.utils import background_delete_user
@auth.route('/login', methods=['GET', 'POST']) @auth.route('/login', methods=['GET', 'POST'])
@ -169,30 +169,10 @@ def settings():
@auth.route('/settings/delete_self', methods=['GET', 'POST']) @auth.route('/settings/delete_self', methods=['GET', 'POST'])
@login_required @login_required
def delete_self(): def delete_self():
logger = logging.getLogger(__name__) delete_thread = threading.Thread(target=background_delete_user,
def background_delete(app, current_user_id):
with app.app_context():
logger.warning('Called by delete_thread.')
logger.warning('User id is: {}.'.format(current_user_id))
jobs = Job.query.join(User).filter_by(id=current_user_id).all()
logger.warning('Jobs to delete are: {}'.format(jobs))
for job in jobs:
job.flag_for_stop()
logger.warning('Job status: {}'.format(job.status))
deleted = False
while deleted is False:
db.session.refresh(job)
if job.status == 'deleted':
logger.warning('Job status is deleted.')
job.delete_job()
deleted = True
delete_thread = threading.Thread(target=background_delete,
args=(current_app._get_current_object(), args=(current_app._get_current_object(),
current_user.id)) current_user.id))
delete_thread.start() delete_thread.start()
db.session.delete(current_user) logout_user()
db.session.commit()
flash('Your account has been deleted!') flash('Your account has been deleted!')
return redirect(url_for('main.index')) return redirect(url_for('main.index'))

View File

@ -8,6 +8,7 @@ from ..models import Corpus, Job
import os import os
import logging import logging
import threading import threading
from app.utils import background_delete_job
@main.route('/') @main.route('/')
@ -144,28 +145,9 @@ def job_download(job_id):
@main.route('/jobs/<int:job_id>/delete') @main.route('/jobs/<int:job_id>/delete')
@login_required @login_required
def delete_job(job_id): def delete_job(job_id):
logger = logging.getLogger(__name__) delete_thread = threading.Thread(target=background_delete_job,
args=(current_app._get_current_object(),
def background_delete(job_id, app): job_id))
with app.app_context():
logger.warning('Called by delete_thread.')
logger.warning('Job id is: {}.'.format(job_id))
job = Job.query.filter_by(id=job_id).first()
logger.warning('Job object is: {}'.format(job))
logger.warning('Job status: {}'.format(job.status))
job.flag_for_stop()
logger.warning('Job status: {}'.format(job.status))
deleted = False
while deleted is False:
db.session.refresh(job)
if job.status == 'deleted':
logger.warning('Job status is deleted.')
job.delete_job()
deleted = True
delete_thread = threading.Thread(target=background_delete,
args=(job_id,
current_app._get_current_object()))
delete_thread.start() delete_thread.start()
flash('Job has been deleted!') flash('Job has been deleted!')
return redirect(url_for('main.dashboard')) return redirect(url_for('main.dashboard'))

View File

@ -220,13 +220,21 @@ class User(UserMixin, db.Model):
jobs[str(job.id)] = job.to_dict() jobs[str(job.id)] = job.to_dict()
return jobs return jobs
def delete_user(self, user_id): def delete_user(self):
""" """
Delete user from database. Also delete all associated jobs and corpora Delete user from database. Also delete all associated jobs and corpora
files. files.
""" """
user = User.query.filter_by(user_id=user_id) logger = logging.getLogger(__name__)
db.session.delete(user) delete_path = os.path.join('/mnt/opaque/', str(self.id))
logger.warning('Delete path for user is: {}'.format(delete_path))
while os.path.exists(delete_path):
try:
shutil.rmtree(delete_path, ignore_errors=True)
logger.warning('Path does still exist.')
except OSError:
pass
db.session.delete(self)
db.session.commit() db.session.commit()

View File

@ -85,6 +85,7 @@
<h4>Confirm deletion</h4> <h4>Confirm deletion</h4>
<p> <p>
Do you really want to delete your account and all associated data? Do you really want to delete your account and all associated data?
All associated jobs and job files will be permanently deleted!
</p> </p>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">

53
app/utils.py Normal file
View File

@ -0,0 +1,53 @@
from .models import Job, User
from . import db
import logging
'''
' A list of background process functions. Functions should be called using the
Thread class from the module threading.
'''
def background_delete_user(app, current_user_id):
with app.app_context():
logger = logging.getLogger(__name__)
logger.warning('Called by delete_thread.')
logger.warning('User id is: {}.'.format(current_user_id))
jobs = Job.query.filter_by(user_id=current_user_id).all()
logger.warning('Jobs to delete are: {}'.format(jobs))
user = User.query.get_or_404(current_user_id)
for job in jobs:
job.flag_for_stop()
logger.warning('Job status: {}'.format(job.status))
deleted = False
while deleted is False:
logger.warning('Refreshing')
db.session.refresh(job)
logger.warning('Refreshed')
if job.status == 'deleted':
logger.warning('Job status is deleted.')
job.delete_job()
deleted = True
logger.warning('Loop has ended.')
user.delete_user()
def background_delete_job(app, job_id):
logger = logging.getLogger(__name__)
with app.app_context():
logger.warning('Called by delete_thread.')
logger.warning('Job id is: {}.'.format(job_id))
job = Job.query.filter_by(id=job_id).first()
logger.warning('Job object is: {}'.format(job))
logger.warning('Job status: {}'.format(job.status))
job.flag_for_stop()
logger.warning('Job status: {}'.format(job.status))
deleted = False
while deleted is False:
db.session.refresh(job)
if job.status == 'deleted':
logger.warning('Job status is deleted.')
job.delete_job()
deleted = True
logger.warning('Loop has ended.')