diff --git a/app/admin/forms.py b/app/admin/forms.py index 0bd755dc..0eea3b94 100644 --- a/app/admin/forms.py +++ b/app/admin/forms.py @@ -5,29 +5,22 @@ from wtforms import (BooleanField, SelectField, StringField, SubmitField, from wtforms.validators import DataRequired, Email, Length, Regexp -class EditProfileAdminForm(FlaskForm): +class EditUserForm(FlaskForm): email = StringField('Email', validators=[DataRequired(), Length(1, 64), Email()]) - username = StringField( - 'Username', - validators=[ - DataRequired(), - Length(1, 64), - Regexp( - '^[A-Za-z][A-Za-z0-9_.]*$', - 0, - 'Usernames must have only letters, numbers, dots or ' - 'underscores' - ) - ] - ) + username = StringField('Username', + validators=[DataRequired(), Length(1, 64), + Regexp('^[A-Za-z][A-Za-z0-9_.]*$', 0, + 'Usernames must have only ' + 'letters, numbers, dots or ' + 'underscores')]) confirmed = BooleanField('Confirmed') role = SelectField('Role', coerce=int) name = StringField('Real name', validators=[Length(0, 64)]) submit = SubmitField('Update Profile') def __init__(self, user, *args, **kwargs): - super(EditProfileAdminForm, self).__init__(*args, **kwargs) + super(EditUserForm, self).__init__(*args, **kwargs) self.role.choices = [(role.id, role.name) for role in Role.query.order_by(Role.name).all()] self.user = user diff --git a/app/tables.py b/app/admin/tables.py similarity index 96% rename from app/tables.py rename to app/admin/tables.py index fac611d1..f393ac89 100644 --- a/app/tables.py +++ b/app/admin/tables.py @@ -21,7 +21,7 @@ class AdminUserTable(Table): id = Col('User Id', column_html_attrs={'class': 'id'}, th_html_attrs={'class': 'sort', 'data-sort': 'id'}) - url = LinkCol('Profile', 'admin.admin_user_page', + url = LinkCol('Profile', 'admin.user', url_kwargs=dict(user_id='id'), anchor_attrs={'class': 'waves-effect waves-light btn-small'}) diff --git a/app/admin/views.py b/app/admin/views.py index 566fbac9..ea4936c6 100644 --- a/app/admin/views.py +++ b/app/admin/views.py @@ -1,88 +1,66 @@ from app import db from app.decorators import admin_required from app.models import Role, User -from app.tables import AdminUserItem, AdminUserTable -from app.background_functions import delete_user_ +from app.profile.background_functions import delete_user_ from flask import current_app, flash, redirect, render_template, url_for from flask_login import login_required +from threading import Thread from . import admin -from .forms import EditProfileAdminForm -import threading +from .forms import EditUserForm +from .tables import AdminUserItem, AdminUserTable -@admin.route('/overview', methods=['GET', 'POST']) +@admin.route('/') @login_required @admin_required -def for_admins_only(): - users = User.query.order_by(User.username).all() +def index(): + users = User.query.all() items = [AdminUserItem(u.username, u.email, u.role_id, u.confirmed, u.id) for u in users] # Convert table object to html string table = AdminUserTable(items).__html__() # Add class "list" to tbody element. Needed for "List.js" table = table.replace('tbody', 'tbody class="list"', 1) - return render_template('admin/admin.html.j2', - table=table, + return render_template('admin/index.html.j2', table=table, title='Administration tools') -@admin.route('/overview/admin_user_page/', - methods=['GET', 'POST']) +@admin.route('/user/') @login_required @admin_required -def admin_user_page(user_id): - selected_user = User.query.filter_by(id=user_id).first() - title = 'Administration of user {} with ID: {}'.format( - selected_user.username, - selected_user.id - ) - registration_date = selected_user.registration_date.strftime( - '%A, %e %B %H:%M' - ) - return render_template('admin/admin_user_page.html.j2', - registration_date=registration_date, - selected_user=selected_user, - title=title) - - -@admin.route('/overview/admin_user_page/delete/', - methods=['GET', 'POST']) -@login_required -@admin_required -def admin_delete_user(user_id): - delete_thread = threading.Thread(target=delete_user_, - args=(current_app._get_current_object(), - user_id)) - delete_thread.start() - flash('User {} has been deleted!'.format(user_id)) - return redirect(url_for('admin.for_admins_only')) - - -@admin.route('/overview/admin_user_page/edit_profile_admin/', - methods=['GET', 'POST']) -@login_required -@admin_required -def edit_profile_admin(user_id): +def user(user_id): user = User.query.get_or_404(user_id) - form = EditProfileAdminForm(user=user) - if form.validate_on_submit(): - user.email = form.email.data - user.username = form.username.data - user.confirmed = form.confirmed.data - user.role = Role.query.get(form.role.data) + return render_template('admin/user.html.j2', title='Administration: User', + user=user) + + +@admin.route('/user//delete') +@login_required +@admin_required +def delete_user(user_id): + user = User.query.get_or_404(user_id) + thread = Thread(target=delete_user_, + args=(current_app._get_current_object(), user.id)) + thread.start() + flash('User has been deleted!') + return redirect(url_for('admin.index')) + + +@admin.route('/user//edit', methods=['GET', 'POST']) +@login_required +@admin_required +def edit_user(user_id): + user = User.query.get_or_404(user_id) + edit_user_form = EditUserForm(user=user) + if edit_user_form.validate_on_submit(): + user.email = edit_user_form.email.data + user.username = edit_user_form.username.data + user.confirmed = edit_user_form.confirmed.data + user.role = Role.query.get(edit_user_form.role.data) db.session.add(user) db.session.commit() flash('The profile has been updated.') - return redirect(url_for('admin.edit_profile_admin', user_id=user.id)) - form.email.data = user.email - form.username.data = user.username - form.confirmed.data = user.confirmed - form.role.data = user.role_id - title = 'Edit profile of user {} with ID {}'.format( - user.username, - user.id - ) - return render_template('admin/edit_profile_admin.html.j2', - form=form, - title=title, - user=user) + return redirect(url_for('admin.edit_user', user_id=user.id)) + return render_template('admin/edit_user.html.j2', + edit_user_form=edit_user_form, + title='Administration: Edit user', user=user) diff --git a/app/auth/views.py b/app/auth/views.py index 146294f3..74afc490 100644 --- a/app/auth/views.py +++ b/app/auth/views.py @@ -41,15 +41,15 @@ def logout(): def register(): if not current_user.is_anonymous: return redirect(url_for('main.dashboard')) - form = RegistrationForm() - if form.validate_on_submit(): - user = User(email=form.email.data.lower(), - password=form.password.data, - username=form.username.data) + registration_form = RegistrationForm() + if registration_form.validate_on_submit(): + user = User(email=registration_form.email.data.lower(), + password=registration_form.password.data, + username=registration_form.username.data) db.session.add(user) db.session.commit() dir = os.path.join(current_app.config['OPAQUE_STORAGE_DIRECTORY'], - str(job.user_id), 'jobs', str(job.id)) + str(user.id)) try: os.makedirs(dir) except OSError: @@ -57,15 +57,11 @@ def register(): user.delete() else: token = user.generate_confirmation_token() - send_email(user.email, - 'Confirm Your Account', - 'auth/email/confirm', - token=token, - user=user) + send_email(user.email, 'Confirm Your Account', + 'auth/email/confirm', token=token, user=user) flash('A confirmation email has been sent to you by email.') return redirect(url_for('auth.login')) - return render_template('auth/register.html.j2', - form=form, + return render_template('auth/register.html.j2', form=registration_form, title='Register') diff --git a/app/background_functions.py b/app/background_functions.py deleted file mode 100644 index b98b3bd1..00000000 --- a/app/background_functions.py +++ /dev/null @@ -1,25 +0,0 @@ -from .models import Corpus, Job, User - - -def delete_corpus_(app, corpus_id): - with app.app_context(): - corpus = Corpus.query.filter_by(id=corpus_id).first() - if corpus is None: - raise Exception('Corpus {} not found!'.format(corpus_id)) - corpus.delete() - - -def delete_job_(app, job_id): - with app.app_context(): - job = Job.query.filter_by(id=job_id).first() - if job is None: - raise Exception('Job {} not found!'.format(job_id)) - job.delete() - - -def delete_user_(app, user_id): - with app.app_context(): - user = User.query.filter_by(id=user_id).first() - if user is None: - raise Exception('User {} not found!'.format(user_id)) - user.delete() diff --git a/app/corpora/background_functions.py b/app/corpora/background_functions.py index e12cf51c..442b9424 100644 --- a/app/corpora/background_functions.py +++ b/app/corpora/background_functions.py @@ -3,7 +3,7 @@ from app.models import Corpus, CorpusFile def delete_corpus_(app, corpus_id): with app.app_context(): - corpus = Corpus.query.filter_by(id=corpus_id).first() + corpus = Corpus.query.get(corpus_id) if corpus is None: raise Exception('Corpus {} not found!'.format(corpus_id)) corpus.delete() @@ -11,7 +11,7 @@ def delete_corpus_(app, corpus_id): def delete_corpus_file_(app, corpus_file_id): with app.app_context(): - corpus_file = CorpusFile.query.filter_by(id=corpus_file_id).first() + corpus_file = CorpusFile.query.get(corpus_file_id) if corpus_file is None: raise Exception('Corpus file {} not found!'.format(corpus_file_id)) corpus_file.delete() @@ -19,7 +19,7 @@ def delete_corpus_file_(app, corpus_file_id): def edit_corpus_file_(app, corpus_file_id): with app.app_context(): - corpus_file = CorpusFile.query.filter_by(id=corpus_file_id).first() + corpus_file = CorpusFile.query.get(corpus_file_id) if corpus_file is None: raise Exception('Corpus file {} not found!'.format(corpus_file_id)) corpus_file.insert_metadata() diff --git a/app/corpora/events.py b/app/corpora/events.py index f2e9f141..6edd7a2f 100644 --- a/app/corpora/events.py +++ b/app/corpora/events.py @@ -21,68 +21,90 @@ analysis_clients = {} @socketio.on('init_corpus_analysis') @login_required def init_corpus_analysis(corpus_id): - corpus = Corpus.query.filter_by(id=corpus_id).first() + corpus = Corpus.query.get(corpus_id) if corpus is None: socketio.emit('init_corpus_analysis', '[ERROR 404]: Not Found', room=request.sid) - if not (corpus.creator == current_user or current_user.is_administrator()): + elif not (corpus.creator == current_user + or current_user.is_administrator()): socketio.emit('init_corpus_analysis', '[ERROR 403]: Forbidden', room=request.sid) - if str(corpus_id) not in analysis_sessions: - analysis_sessions[str(corpus_id)] = [request.sid] - socketio.start_background_task(observe_corpus_analysis_connection, - current_app._get_current_object(), - corpus_id, request.sid) + else: + if corpus_id not in analysis_sessions: + analysis_sessions[corpus_id] = [request.sid] + else: + analysis_sessions[corpus_id].append(request.sid) + while corpus.status != 'analysing': + db.session.refresh(corpus) + socketio.sleep(3) + analysis_clients[request.sid] = CQiClient( + host='{}_analysis_container{}'.format(corpus.creator.username, + corpus.id)) + analysis_clients[request.sid].ctrl_connect('opaque', 'opaque') + socketio.emit('init_corpus_analysis', 'Ready', room=request.sid) + socketio.start_background_task(observe_corpus_analysis_connection, + current_app._get_current_object(), + corpus_id, request.sid) -@socketio.on('query_event') +@socketio.on('query') @login_required def recv_query(message): - logger.warning(message) - analysis_client = analysis_clients[request.sid] - analysis_client.connect() + analysis_client = analysis_clients.get(request.sid) + if analysis_client is None: + socketio.emit('query', '[ERROR 424]: Failed Dependency', + room=request.sid) + return """ Prepare and execute a query """ corpus_name = 'CORPUS' query = message['query'] - result_subcorpus_name = 'Results' - analysis_client.set_corpus_name(corpus_name) - logger.warning('Corpus name has been set.') - analysis_client.create_attribute_strings() - logger.warning('Attribute Strings have been created.') - analysis_client.query_subcorpus(result_subcorpus_name, query) - logger.warning('Subcorpus from query has been created.') - subcorpora = analysis_client.show_subcorpora() - logger.warning('Known subcorpora: {}'.format(subcorpora)) - matches = analysis_client.show_results(result_start_count=1, - result_max_count=3) - logger.warning('Match data: {}'.format(matches)) - socketio.emit('query_results', matches, room=request.sid) + query_subcorpus = 'Results' + analysis_client.cqp_query(corpus, query_subcorpus, query) + """ Evaluate query results """ + match_corpus = '{}:{}'.format(corpus, query_subcorpus) + match_num = min(int(message['hits_per_page']) - 1, + analysis_client.cqp_subcorpus_size(match_corpus)) + if match_num == 0: + print('No matches found.') + exit() + if not analysis_client.cqp_subcorpus_has_field(match_corpus, CONST_FIELD_MATCH): + print('Error.') + exit() + if not analysis_client.cqp_subcorpus_has_field(match_corpus, CONST_FIELD_MATCHEND): + print('Error') + exit() + match_boundaries = zip(analysis_client.cqp_dump_subcorpus(match_corpus, CONST_FIELD_MATCH, 0, match_num - 1), + analysis_client.cqp_dump_subcorpus(match_corpus, CONST_FIELD_MATCHEND, 0, match_num - 1)) + matches = [] + for match_start, match_end in match_boundaries: + matches.append({'cpos_list': list(range(match_start, match_end + 1))}) + cpos_list = [] + for match in matches: + cpos_list = cpos_list + match['cpos_list'] + cpos_list = list(set(cpos_list)) + pos_list = analysis_client.cl_cpos2str('{}.pos'.format(corpus), cpos_list) + word_list = analysis_client.cl_cpos2str('{}.word'.format(corpus), cpos_list) + foo = {} + for cpos, pos, word in zip(cpos_list, pos_list, word_list): + foo[cpos] = {'pos': pos, 'word': word} + for match in matches: + match['pos_list'] = [foo[cpos]['pos'] for cpos in match['cpos_list']] + match['word_list'] = [foo[cpos]['word'] for cpos in match['cpos_list']] + match.pop('cpos_list', None) + logger.warning(matches) + socketio.emit('query', matches, room=request.sid) def observe_corpus_analysis_connection(app, corpus_id, session_id): with app.app_context(): - corpus = Corpus.query.filter_by(id=corpus_id).first() - while corpus.status != 'analysing': - db.session.refresh(corpus) - socketio.sleep(3) - analysis_client = CQiWrapper(host='{}_analysis_container{}'.format(corpus.creator.username, corpus.id), port=4877, password='opaque', username='opaque') - analysis_clients[session_id] = analysis_client - socketio.emit('init_corpus_analysis', 'Ready', room=session_id) while session_id in connected_sessions: - ''' - try: - analysis_client.ctrl_ping() - except Exception as err: - logger.warning('[Exception]: {}'.format(err)) - break - else: - socketio.sleep(3) - ''' socketio.sleep(3) - analysis_client.disconnect() - analysis_clients.pop(session_id, None) - analysis_sessions[str(corpus_id)].remove(session_id) - if not analysis_sessions[str(corpus_id)]: - analysis_sessions.pop(str(corpus_id), None) + analysis_client = analysis_clients.pop(session_id, None) + if analysis_client is not None: + analysis_client.ctrl_bye() + analysis_sessions[corpus_id].remove(session_id) + if not analysis_sessions[corpus_id]: + analysis_sessions.pop(corpus_id, None) + corpus = Corpus.query.get(corpus_id) corpus.status = 'stop analysis' db.session.commit() diff --git a/app/corpora/views.py b/app/corpora/views.py index c91b8783..5f07173b 100644 --- a/app/corpora/views.py +++ b/app/corpora/views.py @@ -1,16 +1,16 @@ -from app import db, logger +from app import db from app.models import Corpus, CorpusFile 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 threading import Thread from werkzeug.utils import secure_filename from . import corpora from .background_functions import (delete_corpus_, delete_corpus_file_, - edit_corpus_file_) + edit_corpus_file_) from .forms import (AddCorpusFileForm, AddCorpusForm, EditCorpusFileForm, QueryDownloadForm, QueryForm) import os -import threading @corpora.route('/add', methods=['GET', 'POST']) @@ -48,31 +48,21 @@ def corpus(corpus_id): title='Corpus') -@corpora.route('//analysis', methods=['GET', 'POST']) +@corpora.route('//analyse') @login_required -def corpus_analysis(corpus_id): +def analyse_corpus(corpus_id): corpus = Corpus.query.get_or_404(corpus_id) if corpus.status == 'prepared': corpus.status = 'start analysis' db.session.commit() - query = request.args.get('query') - logger.warning('Query first: {}'.format(query)) - hits_per_page = request.args.get('hits_per_page', 30) - context = request.args.get('context', 10) - dl_form = QueryDownloadForm() - form = QueryForm(hits_per_page=hits_per_page, context=context, query=query) - if form.validate_on_submit(): - flash('Query has been sent!') - query = form.query.data - hits_per_page = form.hits_per_page.data - context = form.context.data - return redirect(url_for('corpora.corpus_analysis', corpus_id=corpus_id, - query=query, hits_per_page=hits_per_page, - context=context)) - return render_template('corpora/corpus_analysis.html.j2', + query_download_form = QueryDownloadForm() + query_form = QueryForm(context=request.args.get('context', 10), + hits_per_page=request.args.get('hits_per_page', 30), + query=request.args.get('query')) + return render_template('corpora/analyse_corpus.html.j2', corpus_id=corpus_id, - form=form, dl_form=dl_form, - title='Corpus: {}'.format(corpus.title)) + query_download_form=query_download_form, + query_form=query_form, title='Analyse Corpus') @corpora.route('//delete') @@ -81,9 +71,8 @@ def delete_corpus(corpus_id): corpus = Corpus.query.get_or_404(corpus_id) if not (corpus.creator == current_user or current_user.is_administrator()): abort(403) - thread = threading.Thread(target=delete_corpus_, - args=(current_app._get_current_object(), - corpus.id)) + thread = Thread(target=delete_corpus_, + args=(current_app._get_current_object(), corpus.id)) thread.start() flash('Corpus deleted!') return redirect(url_for('main.dashboard')) @@ -102,23 +91,21 @@ def add_corpus_file(corpus_id): for corpus_file in corpus.files: if filename == corpus_file.filename: flash('File already registered to this corpus.') - return redirect(url_for('corpora.corpus', corpus_id=corpus_id)) + return redirect(url_for('corpora.add_corpus_file', + corpus_id=corpus_id)) # Save the file dir = os.path.join(str(corpus.user_id), 'corpora', str(corpus.id)) file.save(os.path.join(current_app.config['OPAQUE_STORAGE_DIRECTORY'], dir, filename)) - corpus_file = CorpusFile(author=add_corpus_file_form.author.data, - corpus=corpus, - dir=dir, - filename=filename, + corpus=corpus, dir=dir, filename=filename, publishing_year=add_corpus_file_form.publishing_year.data, title=add_corpus_file_form.title.data) db.session.add(corpus_file) db.session.commit() - thread = threading.Thread(target=edit_corpus_file_, - args=(current_app._get_current_object(), - corpus_file.id)) + thread = Thread(target=edit_corpus_file_, + args=(current_app._get_current_object(), + corpus_file.id)) thread.start() flash('Corpus file added!') return redirect(url_for('corpora.corpus', corpus_id=corpus_id)) @@ -136,9 +123,8 @@ def delete_corpus_file(corpus_id, corpus_file_id): if not (corpus_file.corpus.creator == current_user or current_user.is_administrator()): abort(403) - thread = threading.Thread(target=delete_corpus_file_, - args=(current_app._get_current_object(), - corpus_file.id)) + thread = Thread(target=delete_corpus_file_, + args=(current_app._get_current_object(), corpus_file.id)) thread.start() flash('Corpus file deleted!') return redirect(url_for('corpora.corpus', corpus_id=corpus_id)) @@ -175,9 +161,9 @@ def edit_corpus_file(corpus_id, corpus_file_id): corpus_file.publishing_year = edit_corpus_file_form.publishing_year.data corpus_file.title = edit_corpus_file_form.title.data db.session.commit() - thread = threading.Thread(target=edit_corpus_file_, - args=(current_app._get_current_object(), - corpus_file.id)) + thread = Thread(target=edit_corpus_file_, + args=(current_app._get_current_object(), + corpus_file.id)) thread.start() flash('Corpus file edited!') return redirect(url_for('corpora.corpus', corpus_id=corpus_id)) diff --git a/app/email.py b/app/email.py index 072b7bc3..fa516327 100644 --- a/app/email.py +++ b/app/email.py @@ -13,7 +13,7 @@ def send_email(to, subject, template, **kwargs): msg = Message('[Opaque] {}'.format(subject), recipients=[to]) msg.body = render_template(template + '.txt.j2', **kwargs) msg.html = render_template(template + '.html.j2', **kwargs) - thr = Thread(target=send_async_email, - args=[current_app._get_current_object(), msg]) - thr.start() - return thr + thread = Thread(target=send_async_email, + args=(current_app._get_current_object(), msg)) + thread.start() + return thread diff --git a/app/events.py b/app/events.py index 73022cc5..c05ea980 100644 --- a/app/events.py +++ b/app/events.py @@ -72,7 +72,10 @@ def user_ressource_subscription_handler(app, user_id, session_id, else 'update-jobs'} with app.app_context(): # Gather current values from database. - user = User.query.filter_by(id=user_id).first() + user = User.query.get(user_id) + if user is None: + ''' TODO: Handle this ''' + return corpora = {corpus.id: corpus.to_dict() for corpus in user.corpora} jobs = {job.id: job.to_dict() for job in user.jobs} # Send initial values to the user. diff --git a/app/jobs/background_functions.py b/app/jobs/background_functions.py new file mode 100644 index 00000000..f90c2daa --- /dev/null +++ b/app/jobs/background_functions.py @@ -0,0 +1,9 @@ +from app.models import Job + + +def delete_job_(app, job_id): + with app.app_context(): + job = Job.query.get(job_id) + if job is None: + raise Exception('Job {} not found!'.format(job_id)) + job.delete() diff --git a/app/jobs/views.py b/app/jobs/views.py index 20b86a23..37a81a21 100644 --- a/app/jobs/views.py +++ b/app/jobs/views.py @@ -1,11 +1,11 @@ from app.models import Job, JobInput, JobResult -from app.background_functions import delete_job_ from flask import (abort, current_app, flash, redirect, render_template, send_from_directory, url_for) from flask_login import current_user, login_required +from threading import Thread from . import jobs +from .background_functions import delete_job_ import os -import threading @jobs.route('/') @@ -23,10 +23,9 @@ def delete_job(job_id): job = Job.query.get_or_404(job_id) if not (job.creator == current_user or current_user.is_administrator()): abort(403) - delete_thread = threading.Thread(target=delete_job_, - args=(current_app._get_current_object(), - job_id)) - delete_thread.start() + thread = Thread(target=delete_job_, + args=(current_app._get_current_object(), job_id)) + thread.start() flash('Job has been deleted!') return redirect(url_for('main.dashboard')) diff --git a/app/profile/background_functions.py b/app/profile/background_functions.py new file mode 100644 index 00000000..62be9b6f --- /dev/null +++ b/app/profile/background_functions.py @@ -0,0 +1,9 @@ +from app.models import User + + +def delete_user_(app, user_id): + with app.app_context(): + user = User.query.get(user_id) + if user is None: + raise Exception('User {} not found!'.format(user_id)) + user.delete() diff --git a/app/profile/views.py b/app/profile/views.py index 2eaa1b02..fd83917b 100644 --- a/app/profile/views.py +++ b/app/profile/views.py @@ -1,10 +1,10 @@ from app import db, logger -from app.background_functions import delete_user_ from flask import abort, current_app, flash, redirect, render_template, url_for from flask_login import current_user, login_required, logout_user +from threading import Thread from . import profile +from .background_functions import delete_user_ from .forms import ChangePasswordForm, EditProfileForm, EditUserSettingsForm -import threading @profile.route('/', methods=['GET', 'POST']) @@ -94,10 +94,9 @@ def delete_self(): """ View to delete yourslef and all associated data. """ - delete_thread = threading.Thread(target=delete_user_, - args=(current_app._get_current_object(), - current_user.id)) - delete_thread.start() + thread = Thread(target=delete_user_, + args=(current_app._get_current_object(), current_user.id)) + thread.start() logout_user() flash('Your account has been deleted!') return redirect(url_for('main.index')) diff --git a/app/services/views.py b/app/services/views.py index 9744b450..81d4781d 100644 --- a/app/services/views.py +++ b/app/services/views.py @@ -1,7 +1,8 @@ -from app import db +from app import db, logger from app.jobs.forms import AddNLPJobForm, AddOCRJobForm from app.models import Job, JobInput -from flask import abort, current_app, flash, redirect, render_template, url_for +from flask import (abort, current_app, flash, make_response, render_template, + request, url_for) from flask_login import current_user, login_required from werkzeug.utils import secure_filename from . import services @@ -23,7 +24,9 @@ def service(service): if service not in SERVICES: abort(404) add_job_form = SERVICES[service]['add_job_form']() - if add_job_form.validate_on_submit(): + if add_job_form.is_submitted(): + if not add_job_form.validate(): + return make_response(add_job_form.errors, 400) service_args = [] if service == 'nlp': service_args.append('-l {}'.format(add_job_form.language.data)) @@ -46,8 +49,11 @@ def service(service): try: os.makedirs(absolut_dir) except OSError: - flash('[ERROR]: Could not add job!') job.delete() + flash('Internal Server Error') + return make_response( + {'redirect_url': url_for('services.service', service='ocr')}, + 500) else: for file in add_job_form.files.data: filename = secure_filename(file.filename) @@ -58,7 +64,8 @@ def service(service): job.status = 'submitted' db.session.commit() flash('Job added!') - return redirect(url_for('jobs.job', job_id=job.id)) + return make_response( + {'redirect_url': url_for('jobs.job', job_id=job.id)}, 201) return render_template('services/{}.html.j2'.format(service), title=SERVICES[service]['name'], add_job_form=add_job_form) diff --git a/app/static/js/JobList.js b/app/static/js/JobList.js index e3533171..7320b912 100644 --- a/app/static/js/JobList.js +++ b/app/static/js/JobList.js @@ -24,8 +24,7 @@ class JobList extends List { pathArray = operation.path.split("/").slice(1); switch(operation.op) { case "add": - console.log(pathArray); - if (pathArray[1].includes("results")) {break;} + if (pathArray.includes("results")) {break;} this.addJob(operation.value); this.update(); List.updatePagination(this); @@ -80,12 +79,8 @@ class JobList extends List { serviceIcon = JobList.SERVICE_ICONS[job.service] || JobList.SERVICE_ICONS['default']; jobServiceElement = document.createElement("i"); - jobServiceElement.classList.add( - "circle", - "material-icons", - "service-icon", - serviceColor - ); + jobServiceElement.classList.add("circle", "material-icons", "service-icon", + serviceColor); jobServiceElement.innerText = serviceIcon; statusColor = JobList.STATUS_COLORS[job.status] || JobList.STATUS_COLORS['default']; diff --git a/app/static/js/add_job.js b/app/static/js/add_job.js index f77ae78f..f0338044 100644 --- a/app/static/js/add_job.js +++ b/app/static/js/add_job.js @@ -14,9 +14,15 @@ function SubmitAddJobForm(newJobFormElement, progressModalElement, request) { progressModalElement.querySelector(".determinate").style.width = progressInPercent; }); request.addEventListener("load", function(event) { - console.log(request.response); - newJobFormElement.reset(); - location.reload(); + if (request.status === 201) { + window.location.href = JSON.parse(this.responseText)['redirect_url']; + } + if (request.status === 400) { + console.log(JSON.parse(this.responseText)); + } + if (request.status === 500) { + location.reload(); + } }); request.addEventListener("abort", function(event) { progressModalElement.querySelector(".progress-in-percent").innerHTML = "0%"; diff --git a/app/templates/admin/admin.html.j2 b/app/templates/admin/admin.html.j2 deleted file mode 100644 index 8fbb368c..00000000 --- a/app/templates/admin/admin.html.j2 +++ /dev/null @@ -1,28 +0,0 @@ -{% extends "full_width.html.j2" %} - -{% block page_content %} -
-
-
- User list -
-
- search - - -
- {{ table }} -
    -
    -
    -
    -
    - -{% endblock %} diff --git a/app/templates/admin/admin_user_page.html.j2 b/app/templates/admin/admin_user_page.html.j2 deleted file mode 100644 index e1ad5fdd..00000000 --- a/app/templates/admin/admin_user_page.html.j2 +++ /dev/null @@ -1,104 +0,0 @@ -{% extends "limited_width.html.j2" %} - -{% block page_content %} -
    -
    -
    - User information -
      -
    • Username: {{selected_user.username}}
    • -
    • Email: {{selected_user.email}}
    • -
    • ID: {{selected_user.id}}
    • -
    • Registration date: {{registration_date}}
    • -
    • Confirmed status: {{selected_user.confirmed}}
    • -
    • Role ID: {{selected_user.role_id}}
    • -
    • Permissions as Int: {{selected_user.role.permissions}}
    • -
    • Role name: {{selected_user.role.name}}
    • -
    -
    - editEdit user - deleteDelete User - - -
    -
    -
    -
    - -
    -
    -
    -
    - User Jobs -
    -
    -
    - search - - -
    -
    -
    -
      -
      -
      -
      -
      -
      -
      -
      - -
      -
      -
      -
      - User Corpora -
      -
      -
      - search - - -
      -
      -
      -
        -
        -
        -
        -
        -
        -
        -
        - -{% endblock %} diff --git a/app/templates/admin/edit_profile_admin.html.j2 b/app/templates/admin/edit_profile_admin.html.j2 deleted file mode 100644 index f96aabc6..00000000 --- a/app/templates/admin/edit_profile_admin.html.j2 +++ /dev/null @@ -1,59 +0,0 @@ -{% extends "limited_width.html.j2" %} - -{% block page_content %} -
        -
        -
        -
        - {{ form.hidden_tag() }} -
        - account_circle - {{ form.username() }} - {{ form.username.label }} - {% for error in form.username.errors %} - {{ error }} - {% endfor %} -
        -
        - mail - {{ form.email() }} - {{ form.email.label }} - {% for error in form.email.errors %} - {{ error }} - {% endfor %} -
        -
        - swap_vert - {{ form.role() }} - {{ form.role.label }} - {% for error in form.role.errors %} - {{ error }} - {% endfor %} -
        -
        - check - - {% for error in form.confirmed.errors %} - {{ error }} - {% endfor %} -
        -
        -
        - {{ form.submit(class='btn') }} -
        -
        - -
        - - -{% endblock %} diff --git a/app/templates/admin/edit_user.html.j2 b/app/templates/admin/edit_user.html.j2 new file mode 100644 index 00000000..055882a5 --- /dev/null +++ b/app/templates/admin/edit_user.html.j2 @@ -0,0 +1,64 @@ +{% extends "limited_width.html.j2" %} + +{% block page_content %} +
        +

        {{ user.username }}

        +

        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,

        + arrow_backBack to user administration +
        + +
        +
        +
        +
        + {{ edit_user_form.hidden_tag() }} +
        + account_circle + {{ edit_user_form.username() }} + {{ edit_user_form.username.label }} + {% for error in edit_user_form.username.errors %} + {{ error }} + {% endfor %} +
        +
        + mail + {{ edit_user_form.email() }} + {{ edit_user_form.email.label }} + {% for error in edit_user_form.email.errors %} + {{ error }} + {% endfor %} +
        +
        + swap_vert + {{ edit_user_form.role() }} + {{ edit_user_form.role.label }} + {% for error in edit_user_form.role.errors %} + {{ error }} + {% endfor %} +
        +
        + check + + {% for error in edit_user_form.confirmed.errors %} + {{ error }} + {% endfor %} +
        +
        +
        + +
        +
        +
        +
        + +{% endblock %} diff --git a/app/templates/admin/index.html.j2 b/app/templates/admin/index.html.j2 new file mode 100644 index 00000000..efc07a09 --- /dev/null +++ b/app/templates/admin/index.html.j2 @@ -0,0 +1,26 @@ +{% extends "full_width.html.j2" %} + +{% block page_content %} +
        +
        +
        +
        + User list +
        + search + + +
        + {{ table }} +
          +
          +
          +
          +
          + + +{% endblock %} diff --git a/app/templates/admin/user.html.j2 b/app/templates/admin/user.html.j2 new file mode 100644 index 00000000..e420493c --- /dev/null +++ b/app/templates/admin/user.html.j2 @@ -0,0 +1,115 @@ +{% extends "limited_width.html.j2" %} + +{% block page_content %} +
          +

          {{ user.username }}

          +

          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,

          + arrow_backBack to admin board +
          + +
          +
          +
          + User information +
            +
          • Username: {{ user.username }}
          • +
          • Email: {{ user.email }}
          • +
          • ID: {{ user.id }}
          • +
          • Registration date: {{ user.registration_date.strftime('%m/%d/%Y, %H:%M:%S %p') }}
          • +
          • Confirmed status: {{ user.confirmed }}
          • +
          • Role ID: {{ user.role_id }}
          • +
          • Permissions as Int: {{ user.role.permissions }}
          • +
          • Role name: {{ user.role.name }}
          • +
          +
          + +
          +
          + +
          + +
          +
          +
          +
          + Corpora +
          +
          +
          + search + + +
          +
          +
          +
            +
            +
            +
            +
            +
            +
            +
            + +
            +
            +
            +
            + Jobs +
            +
            +
            + search + + +
            +
            +
            +
              +
              +
              +
              +
              +
              +
              +
              + + + + + + + +{% endblock %} diff --git a/app/templates/base.html.j2 b/app/templates/base.html.j2 index a73b7d37..a6d4c559 100644 --- a/app/templates/base.html.j2 +++ b/app/templates/base.html.j2 @@ -37,7 +37,6 @@ var jobsSubscribers = []; var socket = io(); - socket.emit('subscribe_user_ressources'); socket.on('init-corpora', function(msg) { corpora = JSON.parse(msg); for (let subscriber of corporaSubscribers) {subscriber._init(corpora);} @@ -141,7 +140,7 @@ {% if current_user.is_administrator() %}
            • Administration
            • -
            • buildAdministration tools
            • +
            • buildAdministration tools
            • {% endif %}
            • @@ -170,28 +169,31 @@
              - + + diff --git a/app/templates/corpora/analyse_corpus.html.j2 b/app/templates/corpora/analyse_corpus.html.j2 new file mode 100644 index 00000000..71760f32 --- /dev/null +++ b/app/templates/corpora/analyse_corpus.html.j2 @@ -0,0 +1,125 @@ +{% extends "full_width.html.j2" %} + +{% block page_content %} +
              +
              +
              +
              + {{ query_form.hidden_tag() }} + Query and analysis +
              + {{ query_form.query(class='materialize-textarea') }} + {{ query_form.query.label }} + {% for error in query_form.query.errors %} + {{ error }} + {% endfor %} +
              + +

               

              + Help +

              CQP Query Language Tutorial

              +

               

              + Options +
              + format_list_numbered + {{ query_form.hits_per_page() }} + {{ query_form.hits_per_page.label }} + {% for error in query_form.hits_per_page.errors %} + {{ error }} + {% endfor %} +
              +
              + short_text + {{ query_form.context() }} + {{ query_form.context.label }} + {% for error in query_form.context.errors %} + {{ error }} + {% endfor %} +
              +
              +
              +
              + +
              +
              +
              + {{ query_download_form.hidden_tag() }} + Download Results +

              Downlaod all results of the current query as csv, excel or json file.

              +
              + insert_drive_file + {{ query_download_form.file_type() }} + {{ query_download_form.file_type.label }} + {% for error in query_download_form.file_type.errors %} + {{ error }} + {% endfor %} +
              + +
              +
              +
              +
              + +
              +
              +
              + Query Results +
              +
              +
              +
              + + + + +{% endblock %} diff --git a/app/templates/corpora/corpus.html.j2 b/app/templates/corpora/corpus.html.j2 index 98e1f81e..30c5d060 100644 --- a/app/templates/corpora/corpus.html.j2 +++ b/app/templates/corpora/corpus.html.j2 @@ -1,83 +1,6 @@ {% extends "limited_width.html.j2" %} {% block page_content %} - -

              {{ corpus.title }}

              {{ corpus.description }}

              @@ -98,7 +21,7 @@
              - helpAnalyse + helpAnalyse {% if corpus.files[0] is defined %} whatshotPrepare {% endif %} @@ -146,11 +69,12 @@
              + + + + {% endfor %} {% endblock %} diff --git a/app/templates/jobs/job.html.j2 b/app/templates/jobs/job.html.j2 index 6536e32e..bdc9599e 100644 --- a/app/templates/jobs/job.html.j2 +++ b/app/templates/jobs/job.html.j2 @@ -1,114 +1,6 @@ {% extends "limited_width.html.j2" %} {% block page_content %} - -

              {{ job.title }}

              {{ job.description }}

              @@ -210,6 +102,7 @@
              + + + + {% endblock %}