diff --git a/app/main/views.py b/app/main/views.py index 9160434bb7d2b5aa8f87bea09e29cd70ddeb6031..80449e070884a41c5d88ad99d8e22c102c9bed4b 100644 --- a/app/main/views.py +++ b/app/main/views.py @@ -1,11 +1,11 @@ -from app.utils import background_delete_job +from app.utils import background_delete_job, background_delete_corpus from flask import (abort, current_app, flash, redirect, request, render_template, url_for, send_from_directory) from flask_login import current_user, login_required from . import main from .forms import CreateCorpusForm from .. import db -from ..models import Corpus +from ..models import Corpus, Job import os import threading @@ -18,13 +18,16 @@ def index(): @main.route('/corpora/<int:corpus_id>') @login_required def corpus(corpus_id): - corpus = current_user.corpora.filter_by(id=corpus_id).first() + if (current_user.is_administrator()): + corpus = Corpus.query.get_or_404(corpus_id) + else: + corpus = current_user.corpora.filter_by(id=corpus_id).first() if not corpus: print('Corpus not found.') abort(404) dir = os.path.join(current_app.config['OPAQUE_STORAGE_DIRECTORY'], - str(current_user.id), + str(corpus.user_id), 'corpora', str(corpus.id)) files = {} @@ -42,12 +45,15 @@ def corpus(corpus_id): @login_required def corpus_download(corpus_id): file = request.args.get('file') - corpus = current_user.corpora.filter_by(id=corpus_id).first() + if (current_user.is_administrator()): + corpus = Corpus.query.get_or_404(corpus_id) + else: + corpus = current_user.corpora.filter_by(id=corpus_id).first() if not file or not corpus: print('File not found.') abort(404) dir = os.path.join(current_app.config['OPAQUE_STORAGE_DIRECTORY'], - str(current_user.id), + str(corpus.user_id), 'corpora', str(corpus.id)) return send_from_directory(as_attachment=True, @@ -91,13 +97,16 @@ def dashboard(): @main.route('/jobs/<int:job_id>') @login_required def job(job_id): - job = current_user.jobs.filter_by(id=job_id).first() + if (current_user.is_administrator()): + job = Job.query.get_or_404(job_id) + else: + job = current_user.jobs.filter_by(id=job_id).first() if not job: print('Job not found.') abort(404) dir = os.path.join(current_app.config['OPAQUE_STORAGE_DIRECTORY'], - str(current_user.id), + str(job.user_id), 'jobs', str(job.id)) files = {} @@ -126,12 +135,15 @@ def job(job_id): @login_required def job_download(job_id): file = request.args.get('file') - job = current_user.jobs.filter_by(id=job_id).first() + if (current_user.is_administrator()): + job = Job.query.get_or_404(job_id) + else: + job = current_user.jobs.filter_by(id=job_id).first() if not file or not job: print('File not found.') abort(404) dir = os.path.join(current_app.config['OPAQUE_STORAGE_DIRECTORY'], - str(current_user.id), + str(job.user_id), 'jobs', str(job.id)) return send_from_directory(as_attachment=True, @@ -149,3 +161,15 @@ def delete_job(job_id): delete_thread.start() flash('Job has been deleted!') return redirect(url_for('main.dashboard')) + + +@main.route('/corpora/<int:corpus_id>/delete') +@login_required +def delete_corpus(corpus_id): + delete_thread = threading.Thread( + target=background_delete_corpus, + args=(current_app._get_current_object(), corpus_id) + ) + delete_thread.start() + flash('Corpus has been deleted!') + return redirect(url_for('main.dashboard')) diff --git a/app/models.py b/app/models.py index 8bf8481f718ed89b5e6d1dab829e6603150ef008..7ee5b455cb82d659e0d881d765bc504d551ab0a9 100644 --- a/app/models.py +++ b/app/models.py @@ -8,7 +8,6 @@ from datetime import datetime import os import shutil import logging -import time class Permission: @@ -357,6 +356,20 @@ class Corpus(db.Model): 'title': self.title, 'user_id': self.user_id} + def delete_corpus(self): + logger = logging.getLogger(__name__) + delete_path = os.path.join('/mnt/opaque/', str(self.user_id), 'corpora', + str(self.id)) + logger.warning('Delete path 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() + ''' ' Flask-Login is told to use the application’s custom anonymous user by setting diff --git a/app/templates/main/corpora/corpus.html.j2 b/app/templates/main/corpora/corpus.html.j2 index 2b83dad207fe8cb60571167f1bc625c2faa79a6c..6947aacd13a05bdf6501730b05643bc3d2d1b68b 100644 --- a/app/templates/main/corpora/corpus.html.j2 +++ b/app/templates/main/corpora/corpus.html.j2 @@ -2,18 +2,36 @@ {% block page_content %} <script> - var CORPUS_ID = {{ corpus.id }} + var corpus_user_id = {{ corpus.user_id|tojson|safe }} + socket.emit('inspect_user', {{ corpus_user_id }}); +</script> +<script> + var CORPUS_ID = {{ corpus.id|tojson|safe }} + var foreignCorpusFlag; + {% if current_user.id == corpus.user_id %} + foreignCorpusFlag = false; + {% else %} + foreignCorpusFlag = true; + {% endif %} class InformationUpdater { constructor(corpusId) { this.corpusId = corpusId; - corporaSubscribers.push(this); + if (foreignCorpusFlag) { + foreignCorpusSubscribers.push(this); + } else { + corporaSubscribers.push(this); + } } _init() { var creationDateElement, descriptionElement, titleElement; - this.corpus = corpora[this.corpusId]; + if (foreignCorpusFlag) { + this.corpus = foreignCorpora[this.corpusId]; + } else { + this.corpus = corpora[this.corpusId]; + } creationDateElement = document.getElementById("creation-date"); creationDateElement.value = (new Date(this.corpus.creation_date * 1000)).toLocaleString(); descriptionElement = document.getElementById("description"); @@ -62,6 +80,21 @@ <div class="col s12 m4"> <h3 id="title"></h3> <p id="description"></p> + <h2>Actions:</h2> + <!-- Confirm deletion of job with modal dialogue + Modal Trigger--> + <a href="#modal-confirm-delete" class="waves-effect waves-light btn red modal-trigger"><i class="material-icons left">delete</i>Delete Corpus</a> + <!-- Modal Strucutre --> + <div id="modal-confirm-delete" class="modal"> + <div class="modal-content"> + <h4>Confirm deletion</h4> + <p>Do you really want to delete the Corpus {{corpus.title}}? + All files will be permanently deleted.</p> + </div> + <div class="modal-footer"> + <a href="{{ url_for('main.delete_corpus', corpus_id=corpus.id) }}" class="modal-close waves-effect waves-green btn red"><i class="material-icons left">delete</i>Delete Corpus</a></a> + </div> + </div> </div> <div class="col s12 m8"> diff --git a/app/templates/main/jobs/job.html.j2 b/app/templates/main/jobs/job.html.j2 index f35d0e04933238450ef34401d704572bc630ea38..1859a9e3337d00e5098c4ebc26267b166ad3cdeb 100644 --- a/app/templates/main/jobs/job.html.j2 +++ b/app/templates/main/jobs/job.html.j2 @@ -2,12 +2,26 @@ {% block page_content %} <script> - var JOB_ID = {{ job.id }} + var job_user_id = {{ job.user_id|tojson|safe }} + socket.emit('inspect_user', job_user_id); +</script> +<script> + var JOB_ID = {{ job.id|tojson|safe }} + var foreignJobFlag; + {% if current_user.id == job.user_id %} + foreignJobFlag = false; + {% else %} + foreignJobFlag = true; + {% endif %} class InformationUpdater { constructor(jobId) { this.jobId = jobId; - jobsSubscribers.push(this); + if (foreignJobFlag) { + foreignJobsSubscribers.push(this); + } else { + jobsSubscribers.push(this); + } } _init() { @@ -15,7 +29,11 @@ memMbElement, nCoresElement, serviceElement, serviceArgsElement, serviceVersionElement, statusColor, statusElement, titleElement; - this.job = jobs[this.jobId]; + if (foreignJobFlag) { + this.job = foreignJobs[this.jobId]; + } else { + this.job = jobs[this.jobId]; + } creationDateElement = document.getElementById("creation-date"); creationDateElement.value = (new Date(this.job.creation_date * 1000)).toLocaleString(); descriptionElement = document.getElementById("description"); diff --git a/app/utils.py b/app/utils.py index eb2d1ea43e6c88ae86e671287409d45ebd69dc35..e68d068262fde893d3f164b55a7fec3f1bb887b0 100644 --- a/app/utils.py +++ b/app/utils.py @@ -1,4 +1,4 @@ -from .models import Job, User +from .models import Job, User, Corpus from . import db import logging @@ -15,6 +15,7 @@ def background_delete_user(app, current_user_id): 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() + corpora = Corpus.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: @@ -29,7 +30,10 @@ def background_delete_user(app, current_user_id): logger.warning('Job status is deleted.') job.delete_job() deleted = True - logger.warning('Loop has ended.') + logger.warning('Job deletion loop has ended.') + for corpus in corpora: + corpus.delete_corpus() + logger.warning('Corpus deletion loop has ended.') user.delete_user() @@ -51,3 +55,13 @@ def background_delete_job(app, job_id): job.delete_job() deleted = True logger.warning('Loop has ended.') + + +def background_delete_corpus(app, corpus_id): + logger = logging.getLogger(__name__) + with app.app_context(): + logger.warning('Called by delete_thread.') + logger.warning('Corpus id is: {}.'.format(corpus_id)) + corpus = Corpus.query.filter_by(id=corpus_id).first() + logger.warning('Corpus object is: {}'.format(corpus)) + corpus.delete_corpus()