diff --git a/web/app/corpora/views.py b/web/app/corpora/views.py index 6d78c8b4..3f1bb8d8 100644 --- a/web/app/corpora/views.py +++ b/web/app/corpora/views.py @@ -44,7 +44,17 @@ def corpus(corpus_id): corpus = Corpus.query.get_or_404(corpus_id) if not (corpus.creator == current_user or current_user.is_administrator()): abort(403) - return render_template('corpora/corpus.html.j2', corpus=corpus, + corpus_files = [dict(filename=corpus_file.filename, + author=corpus_file.author, + title=corpus_file.title, + publishing_year=corpus_file.publishing_year, + corpus_id=corpus.id, + id=corpus_file.id + ) + for corpus_file in corpus.files] + return render_template('corpora/corpus.html.j2', + corpus=corpus, + corpus_files=corpus_files, title='Corpus') @@ -216,7 +226,7 @@ def prepare_corpus(corpus_id): abort(403) if corpus.files.all(): tasks.build_corpus(corpus_id) - flash('Corpus gets build now.', 'corpus') + flash('Building Corpus...', 'corpus') else: flash('Can not build corpus, please add corpus file(s).', 'corpus') return redirect(url_for('corpora.corpus', corpus_id=corpus_id)) diff --git a/web/app/results/views.py b/web/app/results/views.py index 4b591122..1ea64407 100644 --- a/web/app/results/views.py +++ b/web/app/results/views.py @@ -6,10 +6,11 @@ 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) + flash, url_for, make_response, send_from_directory) from flask_login import current_user, login_required import json import os +from .. import logger @results.route('/import_results', methods=['GET', 'POST']) @@ -69,10 +70,12 @@ def results_overview(): ''' # get all results of current user results = User.query.get(current_user.id).results + logger.warning(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'], @@ -81,6 +84,7 @@ def results_overview(): 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', @@ -140,3 +144,19 @@ def result_delete(result_id): 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) diff --git a/web/app/static/js/nopaque.lists.js b/web/app/static/js/nopaque.lists.js index a2584e71..8c464263 100644 --- a/web/app/static/js/nopaque.lists.js +++ b/web/app/static/js/nopaque.lists.js @@ -1,6 +1,7 @@ class RessourceList extends List { constructor(idOrElement, subscriberList, type, options={}) { - if (!["corpus", "job", "result", "user", "job_input"].includes(type)) { + if (!["corpus", "job", "result", "user", "job_input", + "corpus_file"].includes(type)) { console.error("Unknown Type!"); return; } @@ -78,7 +79,17 @@ RessourceList.dataMapper = { "analyse-link": ["analysing", "prepared", "start analysis"].includes(corpus.status) ? `/corpora/${corpus.id}/analyse` : "", "edit-link": `/corpora/${corpus.id}`, status: corpus.status, - title: corpus.title}), + title: corpus.title + }), + // Mapping for corpus file entities shown in the corpus overview + corpus_file: corpus_file => ({filename: corpus_file.filename, + author: corpus_file.author, + title: corpus_file.title, + publishing_year: corpus_file.publishing_year, + "edit-link": `${corpus_file.corpus_id}/files/${corpus_file.id}/edit`, + "download-link": `${corpus_file.corpus_id}/files/${corpus_file.id}/download`, + "delete-modal": `delete-corpus-file-${corpus_file.id}-modal` + }), // Mapping for job entities shown in the dashboard table. job: job => ({creation_date: job.creation_date, description: job.description, @@ -86,11 +97,13 @@ RessourceList.dataMapper = { link: `/jobs/${job.id}`, service: job.service, status: job.status, - title: job.title}), + title: job.title + }), // Mapping for job input files shown in table on every job page job_input: job_input => ({filename: job_input.filename, id: job_input.job_id, - "download-link": `${job_input.job_id}/inputs/${job_input.id}/download`}), + "download-link": `${job_input.job_id}/inputs/${job_input.id}/download` + }), // Mapping for imported result entities from corpus analysis. // Shown in imported results table result: result => ({ query: result.query, @@ -101,14 +114,17 @@ RessourceList.dataMapper = { corpus_type : result.corpus_type, "details-link": `${result.id}/details`, "inspect-link": `${result.id}/inspect`, - "delete-modal": `delete-result-${result.id}-modal`}), + "download-link": `${result.id}/file/${result.file_id}/download`, + "delete-modal": `delete-result-${result.id}-modal` + }), // Mapping for user entities shown in admin table user: user => ({username: user.username, email: user.email, role_id: user.role_id, confirmed: user.confirmed, id: user.id, - "profile-link": `user/${user.id}`}) + "profile-link": `user/${user.id}` + }) }; @@ -146,12 +162,12 @@ RessourceList.options = { - - + + edit - search + search `, @@ -165,6 +181,42 @@ RessourceList.options = { {name: "edit-link", attr: "href"}, {name: "status", attr: "data-status"}] }, + // Corpus file entity blueprint setting html strucuture per entity per row + // Link classes have to correspond with Links defined in the Mapping process + corpus_file: {item: ` + + + + + + + edit + + + file_download + + + delete + + + `, + valueNames: ["filename", + "author", + "title", + "publishing_year", + {name: "edit-link", attr: "href"}, + {name: "download-link", attr: "href"}, + {name: "delete-modal", attr: "data-target"}] + }, // Job entity blueprint setting html strucuture per entity per row // Link classes have to correspond with Links defined in the Mapping process job: {item: ` @@ -180,9 +232,9 @@ RessourceList.options = { - + - send + send `, @@ -198,8 +250,12 @@ RessourceList.options = { }, job_input: {item : ` - - file_download + + + file_download `, @@ -217,12 +273,30 @@ RessourceList.options = { - - info_outline + + + info_outline - search + + search - delete + + file_download + + + delete `, @@ -236,6 +310,7 @@ RessourceList.options = { "corpus_type", {name: "details-link", attr: "href"}, {name: "inspect-link", attr: "href"}, + {name: "download-link", attr: "href"}, {name: "delete-modal", attr: "data-target"}] }, // User entity blueprint setting html strucuture per entity per row @@ -246,8 +321,12 @@ RessourceList.options = { - - edit + + + edit `, diff --git a/web/app/templates/corpora/corpus.html.j2 b/web/app/templates/corpora/corpus.html.j2 index 0a0a8c76..fdbe2b8b 100644 --- a/web/app/templates/corpora/corpus.html.j2 +++ b/web/app/templates/corpora/corpus.html.j2 @@ -59,41 +59,34 @@
-
+
Files - +
+ search + + +
+
    - - - - - + + + + + - + - {% for file in corpus.files %} - - - - - - - - {% endfor %}
    FilenameAuthorTitlePublishing yearFilenameAuthorTitlePublishing year{# Actions #}
    bookNothing here...

    Corpus is empty. Add texts using the option below.

    {{ file.filename }}{{ file.author }}{{ file.title }}{{ file.publishing_year }} - edit - file_download - delete -
    +
      addAdd corpus file @@ -129,6 +122,11 @@