mirror of
				https://gitlab.ub.uni-bielefeld.de/sfb1288inf/nopaque.git
				synced 2025-11-04 12:22:47 +00:00 
			
		
		
		
	Merge branch 'development' of gitlab.ub.uni-bielefeld.de:sfb1288inf/opaque into development
This commit is contained in:
		@@ -23,6 +23,8 @@ def create_app(config_name):
 | 
				
			|||||||
    mail.init_app(app)
 | 
					    mail.init_app(app)
 | 
				
			||||||
    socketio.init_app(app, message_qeue='redis://')
 | 
					    socketio.init_app(app, message_qeue='redis://')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    from . import events
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    from .admin import admin as admin_blueprint
 | 
					    from .admin import admin as admin_blueprint
 | 
				
			||||||
    app.register_blueprint(admin_blueprint, url_prefix='/admin')
 | 
					    app.register_blueprint(admin_blueprint, url_prefix='/admin')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,5 +2,4 @@ from flask import Blueprint
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
corpora = Blueprint('corpora', __name__)
 | 
					corpora = Blueprint('corpora', __name__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from . import events, views
 | 
				
			||||||
from . import views
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										34
									
								
								app/corpora/events.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								app/corpora/events.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,34 @@
 | 
				
			|||||||
 | 
					from app import db, socketio
 | 
				
			||||||
 | 
					from app.events import connected_sessions
 | 
				
			||||||
 | 
					from app.models import Corpus
 | 
				
			||||||
 | 
					from flask import current_app, request
 | 
				
			||||||
 | 
					from flask_login import login_required
 | 
				
			||||||
 | 
					import logging
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@socketio.on('init_corpus_analysis')
 | 
				
			||||||
 | 
					@login_required
 | 
				
			||||||
 | 
					def init_corpus_analysis(corpus_id):
 | 
				
			||||||
 | 
					    ''' TODO: Check if current_user is allowed to subscribe to this '''
 | 
				
			||||||
 | 
					    socketio.start_background_task(observe_corpus_analysis_connection,
 | 
				
			||||||
 | 
					                                   current_app._get_current_object(),
 | 
				
			||||||
 | 
					                                   corpus_id,
 | 
				
			||||||
 | 
					                                   request.sid)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@socketio.on('query_event')
 | 
				
			||||||
 | 
					def recv_query(message):
 | 
				
			||||||
 | 
					    logger = logging.getLogger(__name__)
 | 
				
			||||||
 | 
					    logger.warning(message)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def observe_corpus_analysis_connection(app, corpus_id, session_id):
 | 
				
			||||||
 | 
					    logger = logging.getLogger(__name__)
 | 
				
			||||||
 | 
					    with app.app_context():
 | 
				
			||||||
 | 
					        while session_id in connected_sessions:
 | 
				
			||||||
 | 
					            logger.warning('Run container, run!')
 | 
				
			||||||
 | 
					            socketio.sleep(3)
 | 
				
			||||||
 | 
					        corpus = Corpus.query.filter_by(id=corpus_id).first()
 | 
				
			||||||
 | 
					        corpus.status = 'stop analysis'
 | 
				
			||||||
 | 
					        db.session.commit()
 | 
				
			||||||
 | 
					        logger.warning('Stop container, stop!')
 | 
				
			||||||
@@ -1,18 +1,18 @@
 | 
				
			|||||||
from flask import current_app, request
 | 
					from flask import current_app, request
 | 
				
			||||||
from flask_login import current_user, login_required
 | 
					from flask_login import current_user, login_required
 | 
				
			||||||
from ..decorators import admin_required
 | 
					from .decorators import admin_required
 | 
				
			||||||
from .. import db, socketio
 | 
					from . import db, socketio
 | 
				
			||||||
from ..models import User
 | 
					from .models import User
 | 
				
			||||||
import json
 | 
					import json
 | 
				
			||||||
import jsonpatch
 | 
					import jsonpatch
 | 
				
			||||||
import logging
 | 
					import logging
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
'''
 | 
					'''
 | 
				
			||||||
' A list containing session ids of disconnected Socket.IO sessions. It is used
 | 
					' A list containing session ids of connected Socket.IO sessions. It is used to
 | 
				
			||||||
' to signal associated background tasks to stop.
 | 
					' determine runtimes of associated background tasks.
 | 
				
			||||||
'''
 | 
					'''
 | 
				
			||||||
disconnected = []
 | 
					connected_sessions = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@socketio.on('connect')
 | 
					@socketio.on('connect')
 | 
				
			||||||
@@ -24,12 +24,23 @@ def connect():
 | 
				
			|||||||
    ' will be used for further information exchange generated by a background
 | 
					    ' will be used for further information exchange generated by a background
 | 
				
			||||||
    ' task associated with the sid.
 | 
					    ' task associated with the sid.
 | 
				
			||||||
    '''
 | 
					    '''
 | 
				
			||||||
 | 
					    connected_sessions.append(request.sid)
 | 
				
			||||||
    socketio.start_background_task(background_task,
 | 
					    socketio.start_background_task(background_task,
 | 
				
			||||||
                                   current_app._get_current_object(),
 | 
					                                   current_app._get_current_object(),
 | 
				
			||||||
                                   current_user.id,
 | 
					                                   current_user.id,
 | 
				
			||||||
                                   request.sid)
 | 
					                                   request.sid)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@socketio.on('disconnect')
 | 
				
			||||||
 | 
					@login_required
 | 
				
			||||||
 | 
					def disconnect():
 | 
				
			||||||
 | 
					    '''
 | 
				
			||||||
 | 
					    ' On disconnect the session id (sid) of the connection gets removed from
 | 
				
			||||||
 | 
					    ' connected sessions list (see above).
 | 
				
			||||||
 | 
					    '''
 | 
				
			||||||
 | 
					    connected_sessions.remove(request.sid)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@socketio.on('inspect_user')
 | 
					@socketio.on('inspect_user')
 | 
				
			||||||
@login_required
 | 
					@login_required
 | 
				
			||||||
@admin_required
 | 
					@admin_required
 | 
				
			||||||
@@ -48,22 +59,6 @@ def inspect_user(user_id):
 | 
				
			|||||||
                                   True)
 | 
					                                   True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@socketio.on('disconnect')
 | 
					 | 
				
			||||||
@login_required
 | 
					 | 
				
			||||||
def disconnect():
 | 
					 | 
				
			||||||
    '''
 | 
					 | 
				
			||||||
    ' On disconnect the session id (sid) of the connection gets placed in the
 | 
					 | 
				
			||||||
    ' disconnected list (see above).
 | 
					 | 
				
			||||||
    '''
 | 
					 | 
				
			||||||
    disconnected.append(request.sid)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@socketio.on('query_event')
 | 
					 | 
				
			||||||
def recv_query(message):
 | 
					 | 
				
			||||||
    logger = logging.getLogger(__name__)
 | 
					 | 
				
			||||||
    logger.warning(message)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def background_task(app, user_id, session_id, foreign=False):
 | 
					def background_task(app, user_id, session_id, foreign=False):
 | 
				
			||||||
    '''
 | 
					    '''
 | 
				
			||||||
    ' Sends initial corpus and job lists to the client. Afterwards it checks
 | 
					    ' Sends initial corpus and job lists to the client. Afterwards it checks
 | 
				
			||||||
@@ -88,7 +83,7 @@ def background_task(app, user_id, session_id, foreign=False):
 | 
				
			|||||||
                      json.dumps(jobs),
 | 
					                      json.dumps(jobs),
 | 
				
			||||||
                      room=session_id)
 | 
					                      room=session_id)
 | 
				
			||||||
        ''' TODO: Implement maximum runtime for this loop. '''
 | 
					        ''' TODO: Implement maximum runtime for this loop. '''
 | 
				
			||||||
        while session_id not in disconnected:
 | 
					        while session_id in connected_sessions:
 | 
				
			||||||
            ''' Get current values from the database '''
 | 
					            ''' Get current values from the database '''
 | 
				
			||||||
            new_corpora = user.corpora_as_dict()
 | 
					            new_corpora = user.corpora_as_dict()
 | 
				
			||||||
            new_jobs = user.jobs_as_dict()
 | 
					            new_jobs = user.jobs_as_dict()
 | 
				
			||||||
@@ -108,4 +103,3 @@ def background_task(app, user_id, session_id, foreign=False):
 | 
				
			|||||||
            corpora = new_corpora
 | 
					            corpora = new_corpora
 | 
				
			||||||
            jobs = new_jobs
 | 
					            jobs = new_jobs
 | 
				
			||||||
            socketio.sleep(3)
 | 
					            socketio.sleep(3)
 | 
				
			||||||
    disconnected.remove(session_id)
 | 
					 | 
				
			||||||
@@ -3,7 +3,7 @@ from flask import Blueprint
 | 
				
			|||||||
main = Blueprint('main', __name__)
 | 
					main = Blueprint('main', __name__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from . import errors, events, views
 | 
					from . import errors, views
 | 
				
			||||||
from ..models import Permission
 | 
					from ..models import Permission
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,6 @@ from . import db
 | 
				
			|||||||
from . import login_manager
 | 
					from . import login_manager
 | 
				
			||||||
import os
 | 
					import os
 | 
				
			||||||
import shutil
 | 
					import shutil
 | 
				
			||||||
import logging
 | 
					 | 
				
			||||||
import xml.etree.ElementTree as ET
 | 
					import xml.etree.ElementTree as ET
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -226,13 +225,10 @@ class User(UserMixin, db.Model):
 | 
				
			|||||||
        Delete user from database. Also delete all associated jobs and corpora
 | 
					        Delete user from database. Also delete all associated jobs and corpora
 | 
				
			||||||
        files.
 | 
					        files.
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        logger = logging.getLogger(__name__)
 | 
					 | 
				
			||||||
        delete_path = os.path.join('/mnt/opaque/', str(self.id))
 | 
					        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):
 | 
					        while os.path.exists(delete_path):
 | 
				
			||||||
            try:
 | 
					            try:
 | 
				
			||||||
                shutil.rmtree(delete_path, ignore_errors=True)
 | 
					                shutil.rmtree(delete_path, ignore_errors=True)
 | 
				
			||||||
                logger.warning('Path does still exist.')
 | 
					 | 
				
			||||||
            except OSError:
 | 
					            except OSError:
 | 
				
			||||||
                pass
 | 
					                pass
 | 
				
			||||||
        db.session.delete(self)
 | 
					        db.session.delete(self)
 | 
				
			||||||
@@ -383,14 +379,11 @@ class Job(db.Model):
 | 
				
			|||||||
        for good.
 | 
					        for good.
 | 
				
			||||||
        See: https://docs.docker.com/engine/swarm/swarm-tutorial/delete-service/
 | 
					        See: https://docs.docker.com/engine/swarm/swarm-tutorial/delete-service/
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        logger = logging.getLogger(__name__)
 | 
					 | 
				
			||||||
        delete_path = os.path.join('/mnt/opaque/', str(self.user_id), 'jobs',
 | 
					        delete_path = os.path.join('/mnt/opaque/', str(self.user_id), 'jobs',
 | 
				
			||||||
                                   str(self.id))
 | 
					                                   str(self.id))
 | 
				
			||||||
        logger.warning('Delete path is: {}'.format(delete_path))
 | 
					 | 
				
			||||||
        while os.path.exists(delete_path):
 | 
					        while os.path.exists(delete_path):
 | 
				
			||||||
            try:
 | 
					            try:
 | 
				
			||||||
                shutil.rmtree(delete_path, ignore_errors=True)
 | 
					                shutil.rmtree(delete_path, ignore_errors=True)
 | 
				
			||||||
                logger.warning('Path does still exist.')
 | 
					 | 
				
			||||||
            except OSError:
 | 
					            except OSError:
 | 
				
			||||||
                pass
 | 
					                pass
 | 
				
			||||||
        db.session.delete(self)
 | 
					        db.session.delete(self)
 | 
				
			||||||
@@ -412,15 +405,12 @@ class CorpusFile(db.Model):
 | 
				
			|||||||
    corpus_id = db.Column(db.Integer, db.ForeignKey('corpora.id'))
 | 
					    corpus_id = db.Column(db.Integer, db.ForeignKey('corpora.id'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def delete(self):
 | 
					    def delete(self):
 | 
				
			||||||
        logger = logging.getLogger(__name__)
 | 
					 | 
				
			||||||
        logger.warning('Called CorpusFile.delete')
 | 
					 | 
				
			||||||
        path = os.path.join(current_app.config['OPAQUE_STORAGE_DIRECTORY'],
 | 
					        path = os.path.join(current_app.config['OPAQUE_STORAGE_DIRECTORY'],
 | 
				
			||||||
                            self.dir,
 | 
					                            self.dir,
 | 
				
			||||||
                            self.filename)
 | 
					                            self.filename)
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            os.remove(path)
 | 
					            os.remove(path)
 | 
				
			||||||
        except:
 | 
					        except:
 | 
				
			||||||
            logger.warning('[ERROR] CorpusFile.delete')
 | 
					 | 
				
			||||||
            return
 | 
					            return
 | 
				
			||||||
        self.corpus.status = 'unprepared'
 | 
					        self.corpus.status = 'unprepared'
 | 
				
			||||||
        db.session.delete(self)
 | 
					        db.session.delete(self)
 | 
				
			||||||
@@ -474,24 +464,15 @@ class Corpus(db.Model):
 | 
				
			|||||||
                'user_id': self.user_id}
 | 
					                'user_id': self.user_id}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def delete(self):
 | 
					    def delete(self):
 | 
				
			||||||
        logger = logging.getLogger(__name__)
 | 
					 | 
				
			||||||
        logger.warning('Called Corpus.delete')
 | 
					 | 
				
			||||||
        for corpus_file in self.files:
 | 
					        for corpus_file in self.files:
 | 
				
			||||||
            corpus_file.delete()
 | 
					            corpus_file.delete()
 | 
				
			||||||
        logger.warning('bis hierhin und nicht weiter')
 | 
					 | 
				
			||||||
        logger.warning('base_dir: {}'.format(current_app.config['OPAQUE_STORAGE_DIRECTORY']))
 | 
					 | 
				
			||||||
        logger.warning('user_id: {}'.format(self.user_id))
 | 
					 | 
				
			||||||
        logger.warning('id: {}'.format(self.id))
 | 
					 | 
				
			||||||
        path = os.path.join(current_app.config['OPAQUE_STORAGE_DIRECTORY'],
 | 
					        path = os.path.join(current_app.config['OPAQUE_STORAGE_DIRECTORY'],
 | 
				
			||||||
                            str(self.user_id),
 | 
					                            str(self.user_id),
 | 
				
			||||||
                            'corpora',
 | 
					                            'corpora',
 | 
				
			||||||
                            str(self.id))
 | 
					                            str(self.id))
 | 
				
			||||||
        logger.warning(path)
 | 
					 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            logger.warning('Try to remove {}'.format(path))
 | 
					 | 
				
			||||||
            shutil.rmtree(path)
 | 
					            shutil.rmtree(path)
 | 
				
			||||||
        except:
 | 
					        except:
 | 
				
			||||||
            logger.warning('[ERROR] Corpus.delete')
 | 
					 | 
				
			||||||
            return
 | 
					            return
 | 
				
			||||||
        db.session.delete(self)
 | 
					        db.session.delete(self)
 | 
				
			||||||
        db.session.commit()
 | 
					        db.session.commit()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,11 @@
 | 
				
			|||||||
{% extends "full_width.html.j2" %}
 | 
					{% extends "full_width.html.j2" %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% block page_content %}
 | 
					{% block page_content %}
 | 
				
			||||||
 | 
					<script>
 | 
				
			||||||
 | 
					socket.emit('init_corpus_analysis', {{ corpus_id }});
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<div class="col s12 m3 l3 sticky">
 | 
					<div class="col s12 m3 l3 sticky">
 | 
				
			||||||
  <a class="waves-effect waves-light btn" href="{{ url_for('corpora.corpus', corpus_id=corpus_id) }}"><i class="material-icons left">arrow_back</i>Back to corpus overview</a>
 | 
					  <a class="waves-effect waves-light btn" href="{{ url_for('corpora.corpus', corpus_id=corpus_id) }}"><i class="material-icons left">arrow_back</i>Back to corpus overview</a>
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user