from . import results from . import tasks from .. import db from ..corpora.forms import DisplayOptionsForm from ..models import Result, ResultFile, User from .forms import ImportResultsForm from datetime import datetime from flask import (abort, render_template, current_app, request, redirect, flash, url_for, make_response, send_from_directory) from flask_login import current_user, login_required import json import os from .. import logger from jsonschema import validate @results.route('/import_results', methods=['GET', 'POST']) @login_required def import_results(): ''' View to import one json result file. Uses the ImportReultFileForm. ''' import_results_form = ImportResultsForm(prefix='add-result-file-form') if import_results_form.is_submitted(): if not import_results_form.validate(): return make_response(import_results_form.errors, 400) # Save the file # result creation only happens on file save to avoid creating a result # object in the db everytime by just visiting the import_results page result = Result(user_id=current_user.id) db.session.add(result) db.session.commit() if not (result.creator == current_user or current_user.is_administrator()): abort(403) # create paths to save the uploaded json file dir = os.path.join(str(result.user_id), 'results', 'corpus_analysis_results', str(result.id)) abs_dir = os.path.join(current_app.config['NOPAQUE_STORAGE'], dir) abs_file_path = os.path.join(abs_dir, import_results_form.file.data.filename) os.makedirs(abs_dir) # save the json file import_results_form.file.data.save(abs_file_path) # Create ResultFile db entry result_file = ResultFile(result_id=result.id, dir=dir, filename=import_results_form.file.data.filename) # noqa db.session.add(result_file) db.session.commit() # reads uploaded json file with open(abs_file_path, 'r') as f: corpus_metadata = json.load(f) try: # open json schema to validate against it with open('app/static/json_schema/nopaque_cqi_py_results_schema.json', # noqa 'r') as s: schema = json.load(s) # validate if imported json is actually a json result file validate(instance=corpus_metadata, schema=schema) # if validated continue # delete matches and cpos_lookup from read json file del corpus_metadata['matches'] del corpus_metadata['cpos_lookup'] # save metadate directly as json into one field result.corpus_metadata = corpus_metadata flash('Result file added!', 'result') db.session.commit() return make_response( {'redirect_url': url_for('results.results_overview')}, 201) except Exception as e: # this runs if validation fails flash('Uploaded file was not a valid result JSON!', 'result') # deletes before created Result and ResultFile db entries tasks.delete_result(result.id) return make_response( {'redirect_url': url_for('results.import_results')}, 201) return render_template('results/import_results.html.j2', import_results_form=import_results_form, title='Add corpus file') @results.route('/') @login_required def results_overview(): ''' Shows an overview of imported results. ''' # get all results of current user results = User.query.get(current_user.id).results def __p_time(time_str): # helper to convert the datetime into a nice readable string return datetime.strptime(time_str, '%Y-%m-%dT%H:%M:%S.%f') # convert results into a list of dicts to add the measier to list.js in # the template results = [dict(query=r.corpus_metadata['query'], match_count=r.corpus_metadata['match_count'], corpus_name=r.corpus_metadata['corpus_name'], corpus_creation_date=__p_time(r.corpus_metadata['corpus_creation_date']), # noqa corpus_analysis_date=__p_time(r.corpus_metadata['corpus_analysis_date']), # noqa corpus_type=r.corpus_metadata['corpus_type'], file_id=r.file[0].id, id=r.id) for r in results] return render_template('results/results.html.j2', title='Imported Results', # table=table, results=results) @results.route('//details') @login_required def result_details(result_id): ''' View to show metadate and details about on imported result file. ''' result = Result.query.get_or_404(result_id) if not (result.creator == current_user or current_user.is_administrator()): abort(403) return render_template('results/result_details.html.j2', result=result, title='Result Details') @results.route('//inspect') @login_required def result_inspect(result_id): ''' View to inspect one importe result file in a corpus analysis like interface ''' display_options_form = DisplayOptionsForm( prefix='display-options-form', result_context=request.args.get('context', 20), results_per_page=request.args.get('results_per_page', 30)) result = Result.query.get_or_404(result_id) result_file_path = os.path.join(current_app.config['NOPAQUE_STORAGE'], result.file[0].dir, result.file[0].filename) with open(result_file_path, 'r') as result_json: result_json = json.load(result_json) if not (result.creator == current_user or current_user.is_administrator()): abort(403) return render_template('results/result_inspect.html.j2', display_options_form=display_options_form, result=result, result_json=result_json, title='Result Insepct') @results.route('//delete') @login_required def result_delete(result_id): result = Result.query.get_or_404(result_id) if not result.id == result_id: abort(404) if not (result.creator == current_user or current_user.is_administrator()): abort(403) tasks.delete_result(result_id) flash('Result deleted!') return redirect(url_for('results.results_overview')) @results.route('//file//download') @login_required def result_download(result_id, result_file_id): result_file = ResultFile.query.get_or_404(result_file_id) if not result_file.result_id == result_id: abort(404) if not (result_file.result.creator == current_user or current_user.is_administrator()): abort(403) dir = os.path.join(current_app.config['NOPAQUE_STORAGE'], result_file.dir) return send_from_directory(as_attachment=True, directory=dir, filename=result_file.filename)