From 3135eb0897972936b7dd75a5bc27808aaf2326d9 Mon Sep 17 00:00:00 2001
From: Patrick Jentsch <p.jentsch@uni-bielefeld.de>
Date: Thu, 31 Oct 2019 10:25:48 +0100
Subject: [PATCH] Move corpora views, and forms in package.

---
 app/__init__.py                               |   3 +
 app/corpora/__init__.py                       |   6 +
 app/{main => corpora}/forms.py                |   2 +-
 app/corpora/views.py                          | 150 ++++++++++++++
 app/main/views.py                             | 186 +-----------------
 .../{main => }/corpora/corpus.html.j2         |  10 +-
 .../corpora/corpus_analysis.html.j2           |   0
 app/templates/main/dashboard.html.j2          |  16 +-
 8 files changed, 179 insertions(+), 194 deletions(-)
 create mode 100644 app/corpora/__init__.py
 rename app/{main => corpora}/forms.py (98%)
 create mode 100644 app/corpora/views.py
 rename app/templates/{main => }/corpora/corpus.html.j2 (88%)
 rename app/templates/{main => }/corpora/corpus_analysis.html.j2 (100%)

diff --git a/app/__init__.py b/app/__init__.py
index dfa0a249..b77e6a1b 100644
--- a/app/__init__.py
+++ b/app/__init__.py
@@ -29,6 +29,9 @@ def create_app(config_name):
     from .auth import auth as auth_blueprint
     app.register_blueprint(auth_blueprint, url_prefix='/auth')
 
+    from .corpora import corpora as corpora_blueprint
+    app.register_blueprint(corpora_blueprint, url_prefix='/corpora')
+
     from .main import main as main_blueprint
     app.register_blueprint(main_blueprint)
 
diff --git a/app/corpora/__init__.py b/app/corpora/__init__.py
new file mode 100644
index 00000000..85739bc7
--- /dev/null
+++ b/app/corpora/__init__.py
@@ -0,0 +1,6 @@
+from flask import Blueprint
+
+corpora = Blueprint('corpora', __name__)
+
+
+from . import views
diff --git a/app/main/forms.py b/app/corpora/forms.py
similarity index 98%
rename from app/main/forms.py
rename to app/corpora/forms.py
index e737a1ea..cf1ed639 100644
--- a/app/main/forms.py
+++ b/app/corpora/forms.py
@@ -18,7 +18,7 @@ class AddCorpusFileForm(FlaskForm):
                                   '.vrt')
 
 
-class CreateCorpusForm(FlaskForm):
+class AddCorpusForm(FlaskForm):
     description = StringField('Description',
                               validators=[DataRequired(), Length(1, 64)])
     submit = SubmitField()
diff --git a/app/corpora/views.py b/app/corpora/views.py
new file mode 100644
index 00000000..8e5da6df
--- /dev/null
+++ b/app/corpora/views.py
@@ -0,0 +1,150 @@
+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 corpora
+from .forms import (AddCorpusFileForm, AddCorpusForm, QueryDownloadForm,
+                    QueryForm)
+from .. import db
+from ..models import Corpus, CorpusFile
+from werkzeug.utils import secure_filename
+import os
+import threading
+import logging
+
+
+@corpora.route('/add', methods=['POST'])
+@login_required
+def add_corpus():
+    add_corpus_form = AddCorpusForm()
+    if not add_corpus_form.validate_on_submit():
+        abort(400)
+    corpus = Corpus(creator=current_user,
+                    description=add_corpus_form.description.data,
+                    title=add_corpus_form.title.data)
+    db.session.add(corpus)
+    db.session.commit()
+    dir = os.path.join(current_app.config['OPAQUE_STORAGE_DIRECTORY'],
+                       str(corpus.user_id), 'corpora', str(corpus.id))
+    try:
+        os.makedirs(dir)
+    except OSError:
+        flash('OSError!')
+        db.session.remove(corpus)
+        db.session.commit()
+    flash('Corpus created!')
+    return redirect(url_for('corpora.corpus', corpus_id=corpus.id))
+
+
+@corpora.route('/<int:corpus_id>')
+@login_required
+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',
+                           add_corpus_file_form=AddCorpusFileForm(),
+                           corpus=corpus, title='Corpus')
+
+
+@corpora.route('/<int:corpus_id>/analysis', methods=['GET', 'POST'])
+@login_required
+def corpus_analysis(corpus_id):
+    logger = logging.getLogger(__name__)
+    corpus = Corpus.query.get_or_404(corpus_id)
+    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():
+        logger = logging.getLogger(__name__)
+        logger.warning('Data has been sent!')
+        logger.warning('Data labels: {data}'.format(data=[data for data in form.data]))
+        logger.warning('Query Second: {q}'.format(q=form.query.data))
+        logger.warning('Hits: {hits}'.format(hits=form.hits_per_page.data))
+        logger.warning('Context: {context}'.format(context=form.context.data))
+        flash('Query has been sent!')
+        query = form.query.data
+        hits_per_page = form.hits_per_page.data
+        context = form.context.data
+        logger.warning('Query Thrid: {sq}'.format(sq=query))
+        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', corpus=corpus,
+                           form=form, dl_form=dl_form,
+                           title='Corpus: {}'.format(corpus.title))
+
+
+@corpora.route('/<int:corpus_id>/delete')
+@login_required
+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)
+    delete_thread = threading.Thread(corpus.delete())
+    delete_thread.start()
+    flash('Corpus deleted!')
+    return redirect(url_for('main.dashboard'))
+
+
+@corpora.route('/<int:corpus_id>/files/add', methods=['POST'])
+@login_required
+def add_corpus_file(corpus_id):
+    corpus = Corpus.query.get_or_404(corpus_id)
+    if not (corpus.creator == current_user or current_user.is_administrator()):
+        abort(403)
+    add_corpus_file_form = AddCorpusFileForm()
+    if not add_corpus_file_form.validate_on_submit():
+        abort(400)
+    file = add_corpus_file_form.file.data
+    filename = secure_filename(file.filename)
+    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))
+    # 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))
+    author = add_corpus_file_form.author.data
+    publishing_year = add_corpus_file_form.publishing_year.data
+    title = add_corpus_file_form.title.data
+    corpus_file = CorpusFile(author=author, corpus=corpus, dir=dir,
+                             filename=filename,
+                             publishing_year=publishing_year, title=title)
+    db.session.add(corpus_file)
+    db.session.commit()
+    flash('Corpus file added!')
+    return redirect(url_for('corpora.corpus', corpus_id=corpus_id))
+
+
+@corpora.route('/<int:corpus_id>/files/<int:corpus_file_id>/delete')
+@login_required
+def delete_corpus_file(corpus_id, corpus_file_id):
+    corpus_file = CorpusFile.query.get_or_404(corpus_file_id)
+    if not corpus_file.corpus_id == corpus_id:
+        abort(404)
+    if not (corpus_file.corpus.creator == current_user
+            or current_user.is_administrator()):
+        abort(403)
+    delete_thread = threading.Thread(corpus_file.delete())
+    delete_thread.start()
+    flash('Corpus file deleted!')
+    return redirect(url_for('corpora.corpus', corpus_id=corpus_id))
+
+
+@corpora.route('/<int:corpus_id>/files/<int:corpus_file_id>/download')
+@login_required
+def download_corpus_file(corpus_id, corpus_file_id):
+    corpus_file = CorpusFile.query.get_or_404(corpus_file_id)
+    if not corpus_file.corpus_id == corpus_id:
+        abort(404)
+    if not (corpus_file.corpus.creator == current_user
+            or current_user.is_administrator()):
+        abort(403)
+    dir = os.path.join(current_app.config['OPAQUE_STORAGE_DIRECTORY'],
+                       corpus_file.dir)
+    return send_from_directory(as_attachment=True, directory=dir,
+                               filename=corpus_file.filename)
diff --git a/app/main/views.py b/app/main/views.py
index 6d51008b..8631c0f7 100644
--- a/app/main/views.py
+++ b/app/main/views.py
@@ -1,15 +1,12 @@
 from app.utils import background_delete_job
-from flask import (abort, current_app, flash, redirect, request,
-                   render_template, url_for, send_from_directory)
+from flask import (abort, current_app, flash, redirect, render_template,
+                   send_from_directory, url_for)
 from flask_login import current_user, login_required
 from . import main
-from .forms import AddCorpusFileForm, CreateCorpusForm, QueryForm, QueryDownloadForm
-from .. import db
-from ..models import Corpus, CorpusFile, Job, JobInput, JobResult
-from werkzeug.utils import secure_filename
+from ..corpora.forms import AddCorpusForm
+from ..models import Job, JobInput, JobResult
 import os
 import threading
-import logging
 
 
 @main.route('/')
@@ -17,182 +14,11 @@ def index():
     return render_template('main/index.html.j2', title='Opaque')
 
 
-@main.route('/corpora/new', methods=['POST'])
-@login_required
-def corpus_new():
-    create_corpus_form = CreateCorpusForm()
-    if create_corpus_form.validate_on_submit():
-        corpus = Corpus(creator=current_user,
-                        description=create_corpus_form.description.data,
-                        title=create_corpus_form.title.data)
-        db.session.add(corpus)
-        db.session.commit()
-        dir = os.path.join(current_app.config['OPAQUE_STORAGE_DIRECTORY'],
-                           str(corpus.user_id),
-                           'corpora',
-                           str(corpus.id))
-        try:
-            os.makedirs(dir)
-        except OSError:
-            flash('OSError!')
-            db.session.remove(corpus)
-            db.session.commit()
-        flash('Corpus created!')
-        return redirect(url_for('main.corpus', corpus_id=corpus.id))
-
-
-@main.route('/corpora/<int:corpus_id>')
-@login_required
-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('main/corpora/corpus.html.j2',
-                           add_corpus_file_form=AddCorpusFileForm(),
-                           corpus=corpus,
-                           title='Corpus')
-
-
-@main.route('/corpora/<int:corpus_id>/analysis', methods=['GET', 'POST'])
-@login_required
-def corpus_analysis(corpus_id):
-    logger = logging.getLogger(__name__)
-    corpus = Corpus.query.get_or_404(corpus_id)
-    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():
-        logger = logging.getLogger(__name__)
-        logger.warning('Data has been sent!')
-        logger.warning('Data labels: {data}'.format(data=[data for data in form.data]))
-        logger.warning('Query Second: {q}'.format(q=form.query.data))
-        logger.warning('Hits: {hits}'.format(hits=form.hits_per_page.data))
-        logger.warning('Context: {context}'.format(context=form.context.data))
-        flash('Query has been sent!')
-        query = form.query.data
-        hits_per_page = form.hits_per_page.data
-        context = form.context.data
-        logger.warning('Query Thrid: {sq}'.format(sq=query))
-        return redirect(url_for('main.corpus_analysis',
-                                corpus_id=corpus_id,
-                                query=query,
-                                hits_per_page=hits_per_page,
-                                context=context))
-    return render_template('main/corpora/corpus_analysis.html.j2',
-                           corpus=corpus,
-                           form=form,
-                           dl_form=dl_form,
-                           title='Corpus: ' + corpus.title)
-
-
-@main.route('/corpora/<int:corpus_id>/delete')
-@login_required
-def corpus_delete(corpus_id):
-    corpus = Corpus.query.get_or_404(corpus_id)
-    if not (corpus.creator == current_user or current_user.is_administrator()):
-        abort(403)
-    delete_thread = threading.Thread(corpus.delete())
-    delete_thread.start()
-    flash('Corpus has been deleted!')
-    return redirect(url_for('main.dashboard'))
-
-
-@main.route('/corpora/<int:corpus_id>/files/new', methods=['POST'])
-@login_required
-def corpus_file_new(corpus_id):
-    corpus = Corpus.query.get_or_404(corpus_id)
-    if not (corpus.creator == current_user or current_user.is_administrator()):
-        abort(403)
-    add_corpus_file_form = AddCorpusFileForm()
-    if not add_corpus_file_form.validate_on_submit():
-        abort(400)
-    file = add_corpus_file_form.file.data
-    filename = secure_filename(file.filename)
-    for corpus_file in corpus.files:
-        if filename == corpus_file.filename:
-            flash('File already registered to this corpus.')
-            return redirect(url_for('main.corpus', corpus_id=corpus_id))
-    # Save the file
-    dir = os.path.join(str(corpus.user_id), 'corpora', str(corpus.id))
-    file_path = os.path.join(
-        current_app.config['OPAQUE_STORAGE_DIRECTORY'], dir, filename
-    )
-    file.save(file_path)
-    # Gather information to create new corpus file database entry
-    author = add_corpus_file_form.author.data
-    publishing_year = add_corpus_file_form.publishing_year.data
-    title = add_corpus_file_form.title.data
-    corpus_file = CorpusFile(author=author,
-                             corpus=corpus,
-                             dir=dir,
-                             filename=filename,
-                             publishing_year=publishing_year,
-                             title=title)
-    db.session.add(corpus_file)
-    db.session.commit()
-    flash('Corpus file added!')
-    return redirect(url_for('main.corpus', corpus_id=corpus_id))
-
-
-@main.route('/corpora/<int:corpus_id>/files/<int:corpus_file_id>/delete')
-@login_required
-def corpus_file_delete(corpus_id, corpus_file_id):
-    corpus_file = CorpusFile.query.get_or_404(corpus_file_id)
-    if not corpus_file.corpus_id == corpus_id:
-        abort(404)
-    if not (corpus_file.corpus.creator == current_user
-            or current_user.is_administrator()):
-        abort(403)
-    delete_thread = threading.Thread(corpus_file.delete())
-    delete_thread.start()
-    flash('Corpus file deleted!')
-    return redirect(url_for('main.corpus', corpus_id=corpus_id))
-
-
-@main.route('/corpora/<int:corpus_id>/files/<int:corpus_file_id>/download')
-@login_required
-def corpus_file_download(corpus_id, corpus_file_id):
-    corpus_file = CorpusFile.query.get_or_404(corpus_file_id)
-    if not corpus_file.corpus_id == corpus_id:
-        abort(404)
-    if not (corpus_file.corpus.creator == current_user
-            or current_user.is_administrator()):
-        abort(403)
-    dir = os.path.join(current_app.config['OPAQUE_STORAGE_DIRECTORY'],
-                       corpus_file.dir)
-    return send_from_directory(as_attachment=True,
-                               directory=dir,
-                               filename=corpus_file.filename)
-
-
-@main.route('/dashboard', methods=['GET', 'POST'])
+@main.route('/dashboard')
 @login_required
 def dashboard():
-    create_corpus_form = CreateCorpusForm()
-    if create_corpus_form.validate_on_submit():
-        corpus = Corpus(creator=current_user._get_current_object(),
-                        description=create_corpus_form.description.data,
-                        title=create_corpus_form.title.data)
-        db.session.add(corpus)
-        db.session.commit()
-        dir = os.path.join(current_app.config['OPAQUE_STORAGE_DIRECTORY'],
-                           str(corpus.user_id),
-                           'corpora',
-                           str(corpus.id))
-        try:
-            os.makedirs(dir)
-        except OSError:
-            flash('OSError!')
-            db.session.remove(corpus)
-            db.session.commit()
-        flash('Corpus created!')
-        return redirect(url_for('main.dashboard'))
     return render_template('main/dashboard.html.j2',
-                           create_corpus_form=create_corpus_form,
-                           title='Dashboard')
+                           add_corpus_form=AddCorpusForm(), title='Dashboard')
 
 
 @main.route('/jobs/<int:job_id>')
diff --git a/app/templates/main/corpora/corpus.html.j2 b/app/templates/corpora/corpus.html.j2
similarity index 88%
rename from app/templates/main/corpora/corpus.html.j2
rename to app/templates/corpora/corpus.html.j2
index 65491341..7118c3ec 100644
--- a/app/templates/main/corpora/corpus.html.j2
+++ b/app/templates/corpora/corpus.html.j2
@@ -32,7 +32,7 @@
         </div>
       </div>
       <span class="card-title">Actions</span>
-      <a href="{{ url_for('main.corpus_analysis', corpus_id=corpus.id) }}" class="waves-effect waves-light btn">
+      <a href="{{ url_for('corpora.corpus_analysis', corpus_id=corpus.id) }}" class="waves-effect waves-light btn">
         <i class="material-icons left">help</i>Analyse
       </a>
       <a data-target="add-corpus-file-modal" class="waves-effect waves-light btn modal-trigger">
@@ -70,8 +70,8 @@
             <td>{{ file.publishing_year }}</td>
             <td class="right-align">
               <a class="waves-effect waves-light btn-small"><i class="material-icons">edit</i></a>
-              <a class="waves-effect waves-light btn-small" href="{{ url_for('main.corpus_file_download', corpus_file_id=file.id, corpus_id=corpus.id) }}"><i class="material-icons">file_download</i></a>
-              <a class="waves-effect waves-light btn-small red" href="{{ url_for('main.corpus_file_delete', corpus_file_id=file.id, corpus_id=corpus.id) }}"><i class="material-icons">delete</i></a>
+              <a class="waves-effect waves-light btn-small" href="{{ url_for('corpora.download_corpus_file', corpus_file_id=file.id, corpus_id=corpus.id) }}"><i class="material-icons">file_download</i></a>
+              <a class="waves-effect waves-light btn-small red" href="{{ url_for('corpora.delete_corpus_file', corpus_file_id=file.id, corpus_id=corpus.id) }}"><i class="material-icons">delete</i></a>
             </td>
           </tr>
           {% endfor %}
@@ -86,7 +86,7 @@
 <div id="add-corpus-file-modal" class="modal">
   <div class="modal-content">
     <h4>Add corpus file</h4>
-    <form action="{{ url_for('main.corpus_file_new', corpus_id=corpus.id) }}" method="POST" enctype="multipart/form-data">
+    <form action="{{ url_for('corpora.add_corpus_file', corpus_id=corpus.id) }}" method="POST" enctype="multipart/form-data">
       {{ add_corpus_file_form.hidden_tag() }}
       <div class="row">
         <div class="col s12 m4">
@@ -148,7 +148,7 @@
       All files will be permanently deleted.</p>
   </div>
   <div class="modal-footer">
-    <a href="{{ url_for('main.corpus_delete', corpus_id=corpus.id) }}" class="modal-close waves-effect waves-green btn red"><i class="material-icons left">delete</i>Delete Corpus</a>
+    <a href="{{ url_for('corpora.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 href="#!" class="modal-close waves-effect waves-green btn cancel">Cancel</a>
   </div>
 </div>
diff --git a/app/templates/main/corpora/corpus_analysis.html.j2 b/app/templates/corpora/corpus_analysis.html.j2
similarity index 100%
rename from app/templates/main/corpora/corpus_analysis.html.j2
rename to app/templates/corpora/corpus_analysis.html.j2
diff --git a/app/templates/main/dashboard.html.j2 b/app/templates/main/dashboard.html.j2
index 02454ec6..eca132ba 100644
--- a/app/templates/main/dashboard.html.j2
+++ b/app/templates/main/dashboard.html.j2
@@ -88,15 +88,15 @@
 <div id="new-corpus-modal" class="modal">
   <div class="modal-content">
     <h4>New corpus</h4>
-    <form action="{{ url_for('main.corpus_new') }}" method="POST">
-      {{ create_corpus_form.hidden_tag() }}
+    <form action="{{ url_for('corpora.add_corpus') }}" method="POST">
+      {{ add_corpus_form.hidden_tag() }}
       <div class="row">
         <div class="col s12 m4">
           <div class="input-field">
             <i class="material-icons prefix">title</i>
-            {{ create_corpus_form.title(data_length='32') }}
-            {{ create_corpus_form.title.label }}
-            {% for error in create_corpus_form.title.errors %}
+            {{ add_corpus_form.title(data_length='32') }}
+            {{ add_corpus_form.title.label }}
+            {% for error in add_corpus_form.title.errors %}
               <span class="helper-text red-text">{{ error }}</span>
             {% endfor %}
           </div>
@@ -104,9 +104,9 @@
         <div class="col s12 m8">
           <div class="input-field">
             <i class="material-icons prefix">description</i>
-            {{ create_corpus_form.description(data_length='255') }}
-            {{ create_corpus_form.description.label }}
-            {% for error in create_corpus_form.description.errors %}
+            {{ add_corpus_form.description(data_length='255') }}
+            {{ add_corpus_form.description.label }}
+            {% for error in add_corpus_form.description.errors %}
               <span class="helper-text red-text">{{ error }}</span>
             {% endfor %}
           </div>
-- 
GitLab