submission/revision/review restriction logic

Added a lot logic checks for all the submission/revision/review.
these checks make sure that no one can do anything they shouldn't or view something they shouldn't

removed the splash page since it wasn't being used
This commit is contained in:
Aaron Kimbrell
2019-04-06 21:25:55 -05:00
parent 102c60a07a
commit 6b2e1505fd
12 changed files with 303 additions and 213 deletions
+2 -1
View File
@@ -287,6 +287,7 @@ class CreateRevisionForm(FlaskForm):
class CreateReviewForm(FlaskForm):
id = HiddenField()
revision_id = HiddenField()
comments = TextAreaField('Comments', validators=[Optional()])
check_1 = BooleanField('The Pages in Study needs to be updated on the abstract page.',
validators=[Optional()])
@@ -352,5 +353,5 @@ class CreateReviewForm(FlaskForm):
validators=[Optional()])
check_32 = BooleanField('Missing “Chapter” page __.',
validators=[Optional()])
approve = SubmitField('Approve Submission')
submit = SubmitField('Submit Review')
+12 -40
View File
@@ -1,19 +1,11 @@
from flask import render_template, Blueprint, url_for, redirect, send_from_directory
from flask_user import current_user, login_required, current_app
from app.models import Submission, Revision
import pycountry
main_blueprint = Blueprint('main', __name__)
@main_blueprint.route('/')
def splash():
"""Splash Page"""
return redirect(url_for('user.login'))
# return render_template('main/splash.jinja2')
@main_blueprint.route('/home')
@login_required
def index():
"""Home/Index Page"""
@@ -24,49 +16,25 @@ def index():
@login_required
def dashboard():
"""Dashboard Page"""
user = 'user'
if current_user.has_roles('admin'):
user = 'admin'
else:
if current_user.has_roles('reviewer'):
user = 'reviewer'
return render_template('main/dashboard.jinja2', user=user)
return render_template('main/dashboard.jinja2')
@main_blueprint.route('/profile')
@login_required
def profile():
"""Profile Page"""
if current_user.pref_name == "":
full_name = current_user.first_name + ' ' + current_user.middle_name + ' ' + current_user.last_name
else:
full_name = current_user.first_name + ' "' + current_user.pref_name + '" ' + current_user.middle_name + ' ' + current_user.last_name
info = dict(name=full_name,
department=current_user.department,
email=current_user.email,
net_id=current_user.net_id,
msu_id=current_user.msu_id,
birth_date=current_user.birth_date.strftime('%B %d, %Y'), # Makes human redableS
maiden_name=current_user.maiden_name,
sec_email=current_user.sec_email,
prim_phone=current_user.prim_phone,
sec_phone=current_user.sec_phone,
country=pycountry.countries.get(alpha_2=current_user.country).name,
administrative_area=current_user.administrative_area,
locality=current_user.locality,
postal_code=current_user.postal_code,
thoroughfare=current_user.thoroughfare,
premise=current_user.premise)
return render_template('main/profile.jinja2', data=info)
# do not need to pass data, since we can just access the current_user method in the template
return render_template('main/profile.jinja2')
@main_blueprint.route('/uploads/signatures/<filename>')
@login_required
def uploads_signatures(filename):
query = Submission.get_submission_by_signature(signature_filename=filename)
if current_user.has_roles(['admin', 'viewer', 'reviewer', 'helper']) or query.id == query.user_id:
# if elevated user or submission owner or major professor
if current_user.has_roles(['admin', 'viewer', 'reviewer', 'helper']) or \
current_user.id == query.user_id or \
current_user.net_id == query.professor:
return send_from_directory(current_app.config['SIGNATURE_FOLDER'], query.signature_file)
else:
return redirect(url_for('main.index'))
@@ -76,7 +44,11 @@ def uploads_signatures(filename):
@login_required
def uploads_submissions(filename):
query = Revision.get_revision_by_filename(filename=filename)
if current_user.has_roles(['admin', 'viewer', 'reviewer', 'helper']) or query.id == query.user_id:
submission = Submission.get_submission_by_id(submission_id=query.submission_id)
# if elevated user or submission owner or major professor
if current_user.has_roles(['admin', 'viewer', 'reviewer', 'helper']) or \
current_user.id == submission.user_id or \
current_user.net_id == submission.professor:
return send_from_directory(current_app.config['SUBMISSION_FOLDER'], query.file)
else:
return redirect(url_for('main.index'))
+52 -6
View File
@@ -4,6 +4,7 @@ from flask_migrate import Migrate
from flask_user import UserMixin
from sqlalchemy_utils import ArrowType
import arrow
from flask_user import current_user
db = SQLAlchemy()
migrate = Migrate()
@@ -87,17 +88,15 @@ class Submission(db.Model):
user_id: Column = db.Column(db.Integer(), db.ForeignKey('users.id', ondelete='CASCADE'))
title = db.Column(db.Unicode(), nullable=False, server_default=u'')
abstract = db.Column(db.Unicode(), nullable=False, server_default=u'')
# TODO: Make Enum type for this
type = db.Column(db.Integer, nullable=False)
# TODO: Make Enum type for this
release_type = db.Column(db.Integer, nullable=False)
ww_length = db.Column(db.Integer, nullable=False)
professor = db.Column(db.Unicode(8))
signature_file = db.Column(db.Text)
started = db.Column(ArrowType, default=arrow.utcnow())
professor = db.Column(db.Unicode(8), nullable=False)
signature_file = db.Column(db.Text, nullable=False)
started = db.Column(ArrowType, default=arrow.utcnow(), nullable=False)
state = db.Column(db.Boolean, default=False, nullable=False)
approved_date = db.Column(db.DateTime())
approved_date = db.Column(ArrowType)
def save(self):
db.session.add(self)
@@ -119,10 +118,53 @@ class Submission(db.Model):
submission.save()
return submission.id
@staticmethod
def complete_submission_by_id(*, submission_id=None):
submission = Submission.query.filter(submission_id == Submission.id).first()
submission.state = True
submission.approved_date = arrow.utcnow()
submission.save()
return
@staticmethod
def get_submission_by_id(*, submission_id=None):
return Submission.query.filter(submission_id == Submission.id).first()
@staticmethod
def get_submission_by_user_id(*, user_id=None):
return Submission.query.filter(user_id == Submission.user_id).first()
@staticmethod
def get_all_submissions_by_user_id(*, user_id=None):
# get ones that user owns
own = Submission.query \
.join(User, User.id == Submission.user_id) \
.add_columns(User.id, User.first_name, User.last_name, Submission.id, Submission.title, Submission.started) \
.filter(User.id == Submission.user_id) \
.filter(Submission.user_id == User.id) \
.filter(Submission.user_id == user_id) \
.all()
# get ones that user is listed as professor
professors = Submission.query \
.join(User, User.id == Submission.user_id) \
.add_columns(User.id, User.first_name, User.last_name, Submission.id, Submission.title, Submission.started) \
.filter(User.id == Submission.user_id) \
.filter(Submission.user_id == User.id) \
.filter(Submission.professor == current_user.net_id) \
.all()
return own + professors
@staticmethod
def get_all():
return Submission.query \
.join(User, User.id == Submission.user_id) \
.add_columns(User.id, User.first_name, User.last_name, Submission.id, Submission.title, Submission.started) \
.filter(User.id == Submission.user_id) \
.filter(Submission.user_id == User.id).all()
@staticmethod
def get_submission_by_signature(*, signature_filename=None):
return Submission.query.filter(signature_filename == Submission.signature_file).first()
@@ -253,3 +295,7 @@ class Review(db.Model):
@staticmethod
def get_review_by_revision_id(*, revision_id=None):
return Review.query.filter(Review.revision_id == revision_id).first()
@staticmethod
def get_reviews_by_revision_id(*, revision_id=None):
return Review.query.filter(Review.revision_id == revision_id).first()
+91 -50
View File
@@ -1,12 +1,11 @@
import os
from flask import render_template, Blueprint, redirect, url_for, current_app
from flask_user import current_user, login_required
from flask_user import current_user, login_required, roles_required
from app.forms.forms import CreateRevisionForm, CreateReviewForm
from app.models import Revision, Submission, User, Review
from werkzeug.utils import secure_filename
import datetime
revisions_blueprint = Blueprint('revisions', __name__)
@@ -19,39 +18,63 @@ def index():
@revisions_blueprint.route('/create/<submission_id>', methods=['GET', 'POST'])
@login_required
@roles_required('user')
def create(submission_id):
"""Create revision page"""
# TODO make this nicer....
form = CreateRevisionForm()
# if a post process it
if form.validate_on_submit():
f = form.file.data
fname = secure_filename(f.filename)
fileext = fname.rsplit('.', 1)[1].lower()
filename = current_user.last_name + '_' + current_user.first_name + '_revision_' + \
datetime.datetime.now().strftime("%Y-%m-%d_%H:%M:%S") + '.' + fileext
f.save(os.path.join(current_app.config['SUBMISSION_FOLDER'], filename))
params = {'filename': filename, 'submission_id': submission_id}
revision_id = Revision.create_revision(params=params)
return redirect(url_for('revisions.view', revision_id=revision_id))
revisions = Revision.get_all_revisions_by_submission_id(submission_id=submission_id)
# if a revision exist
if not(revisions is None):
# if has not been reviewed
if Review.get_review_by_revision_id(revision_id=revisions[-1].id) is None:
return redirect(url_for('revisions.view', revision_id=revisions[-1].id))
# if has been reviewed
else:
return render_template('revisions/create.jinja2',
form=form,
submission_id=submission_id)
# if no revision exists
submission = Submission.get_submission_by_id(submission_id=submission_id)
# if current user does not own submission
# or if submission has been approved, they can't create revision
if submission.user_id != current_user.id or submission.state:
return redirect(url_for('submissions.view', submission_id=submission_id))
else:
return render_template('revisions/create.jinja2',
form=form,
submission_id=submission_id)
revisions = Revision.get_all_revisions_by_submission_id(submission_id=submission_id)
# if a revision exist
if revisions:
# if latest revision has not been reviewed
if Review.get_review_by_revision_id(revision_id=revisions[-1].id) is None:
return redirect(url_for('revisions.view', revision_id=revisions[-1].id))
# else latest revision has been reviewed
else:
# if a post process it
if form.validate_on_submit():
f = form.file.data
fname = secure_filename(f.filename)
fileext = fname.rsplit('.', 1)[1].lower()
filename = current_user.last_name + '_' + current_user.first_name + '_revision_' + \
datetime.datetime.now().strftime("%Y-%m-%d_%H:%M:%S") + '.' + fileext
f.save(os.path.join(current_app.config['SUBMISSION_FOLDER'], filename))
params = {'filename': filename, 'submission_id': submission_id}
revision_id = Revision.create_revision(params=params)
return redirect(url_for('revisions.view', revision_id=revision_id))
# else present the create page
else:
return render_template('revisions/create.jinja2',
form=form,
submission_id=submission_id)
# if no revision exists
else:
# if a post process it
if form.validate_on_submit():
f = form.file.data
fname = secure_filename(f.filename)
fileext = fname.rsplit('.', 1)[1].lower()
filename = current_user.last_name + '_' + current_user.first_name + '_revision_' + \
datetime.datetime.now().strftime("%Y-%m-%d_%H:%M:%S") + '.' + fileext
f.save(os.path.join(current_app.config['SUBMISSION_FOLDER'], filename))
params = {'filename': filename, 'submission_id': submission_id}
revision_id = Revision.create_revision(params=params)
return redirect(url_for('revisions.view', revision_id=revision_id))
# else present the create page
else:
return render_template('revisions/create.jinja2',
form=form,
submission_id=submission_id)
@revisions_blueprint.route('/view/<revision_id>')
@@ -60,32 +83,50 @@ def view(revision_id):
"""Revision view page"""
revision = Revision.get_revision_by_id(revision_id=revision_id)
submission = Submission.get_submission_by_id(submission_id=revision.submission_id)
review_data = Review.get_review_by_revision_id(revision_id=revision_id)
user = User.get_user_by_id(user_id=submission.user_id)
return render_template('revisions/view.jinja2',
revision=revision,
submission=submission,
user=user,
review=review_data)
# if elevated user or submission owner or major professor
if current_user.has_roles(['admin', 'viewer', 'reviewer', 'helper']) or \
current_user.id == submission.user_id or \
current_user.net_id == submission.professor:
review_data = Review.get_review_by_revision_id(revision_id=revision_id)
user = User.get_user_by_id(user_id=submission.user_id)
return render_template('revisions/view.jinja2',
revision=revision,
submission=submission,
user=user,
review=review_data)
# else not supposed to view it
else:
return redirect(url_for('submissions.index'))
@revisions_blueprint.route('/review/<revision_id>', methods=['GET', 'POST'])
@login_required
@roles_required('reviewer')
def review(revision_id):
"""Revision view page"""
"""Revision review page"""
# only allow if reviewer
form = CreateReviewForm()
if form.validate_on_submit():
params = {'form_data': form.data, 'revision_id': revision_id, 'reviewer_id': current_user.id}
Review.create_review(params=params)
revision = Revision.get_revision_by_id(revision_id=revision_id)
submission = Submission.get_submission_by_id(submission_id=revision.submission_id)
user = User.get_user_by_id(user_id=submission.user_id)
return render_template('revisions/review.jinja2',
revision=revision,
submission=submission,
user=user,
form=form)
# if has been approved
if submission.state:
return redirect(url_for('revisions.view', revision_id=revision_id))
# if post
if form.validate_on_submit():
# if approved
if form.approve.data:
Submission.complete_submission_by_id(submission_id=revision.submission_id)
return redirect(url_for('submissions.view', submission_id=revision.submission_id))
else:
params = {'form_data': form.data, 'revision_id': revision_id, 'reviewer_id': current_user.id}
Review.create_review(params=params)
return redirect(url_for('revisions.view', revision_id=revision_id))
else:
user = User.get_user_by_id(user_id=submission.user_id)
return render_template('revisions/review.jinja2',
revision=revision,
submission=submission,
user=user,
form=form)
+25 -16
View File
@@ -1,11 +1,10 @@
import os
from flask import render_template, Blueprint, redirect, url_for, current_app
from flask_user import current_user, login_required
from flask_user import current_user, login_required, roles_required
from app.forms.forms import CreateSubmissionForm
from app.models import Submission, User, Revision
from app.models import Submission, User, Revision, Review
from werkzeug.utils import secure_filename
submissions_blueprint = Blueprint('submissions', __name__)
@@ -14,17 +13,17 @@ submissions_blueprint = Blueprint('submissions', __name__)
def index():
"""Catalog of Submissions"""
result = Submission.query \
.join(User, User.id == Submission.user_id) \
.add_columns(User.id, User.first_name, User.last_name, Submission.id, Submission.title, Submission.started) \
.filter(User.id == Submission.user_id) \
.filter(Submission.user_id == User.id)
if current_user.has_roles(['admin', 'viewer', 'reviewer', 'helper']):
results = Submission.get_all()
else:
results = Submission.get_all_submissions_by_user_id(user_id=current_user.id)
return render_template('submissions/index.jinja2', submissions=result)
return render_template('submissions/index.jinja2', submissions=results)
@submissions_blueprint.route('/create', methods=['GET', 'POST'])
@login_required
@roles_required('user')
def create():
"""Create submission page"""
@@ -51,12 +50,22 @@ def view(submission_id):
"""Submission revision view page"""
submission = Submission.get_submission_by_id(submission_id=submission_id)
revisions = Revision.get_all_revisions_by_submission_id(submission_id=submission_id)
review_last = False
if revisions:
# if latest revision has not been reviewed
if Review.get_review_by_revision_id(revision_id=revisions[-1].id):
review_last = True
user = User.get_user_by_id(user_id=submission.user_id)
return render_template('submissions/view.jinja2',
submission=submission,
revisions=revisions,
user=user)
# if elevated user or submission owner or major professor
if current_user.has_roles(['admin', 'viewer', 'reviewer', 'helper']) or \
current_user.id == submission.user_id or \
current_user.net_id == submission.professor:
return render_template('submissions/view.jinja2',
submission=submission,
revisions=revisions,
user=user,
review_last=review_last)
# else not supposed to view it
else:
return redirect(url_for('submissions.index'))
+1 -1
View File
@@ -46,7 +46,7 @@
{% macro render_submit_field(field, label=None, tabindex=None) -%}
{% if not label %}{% set label=field.label.text %}{% endif %}
{#<button type="submit" class="form-control btn btn-default btn-primary">{{label}}</button>#}
<input type="submit" class="btn btn-default btn-primary" value="{{label}}"
<input type="submit" class="btn btn-default btn-primary {{ kwargs.pop('class_', '') }}" value="{{label}}"
{% if tabindex %}tabindex="{{ tabindex }}"{% endif %}
>
{%- endmacro %}
+26 -17
View File
@@ -11,64 +11,73 @@
{# user name / classification #}
<div class='row justify-content-center'>
<span class='h3'>{{ data.name }}</span>
<span class='h3'>
{{ current_user.first_name }}
{% if current_user.pref_name %}
"{{ current_user.pref_name }}"
{% endif %}
{{ current_user.middle_name }} {{ current_user.last_name }}
</span>
</div>
<div class='row justify-content-center'>
<span class='h5'>{{ data.department }}</span>
<span class='h5'> Major: {{ current_user.department }}</span>
</div>
<hr/>
{# user data #}
{# user current_user #}
<p class='text-lg-left'>
<h5>MSU Info</h5>
<b>E-Mail:</b><br/>
{{ data.email }}
{{ current_user.email }}
<br/><br/>
<b>Net ID:</b><br/>
{{ data.net_id }}
{{ current_user.net_id }}
<br/><br/>
<b>MSU ID:</b><br/>
{{ data.msu_id }}
{{ current_user.msu_id }}
<br/><br/>
<hr>
<h5>Personal Info</h5>
{% if data.maiden_name %}
{% if current_user.maiden_name %}
<b>Maiden Name:</b><br/>
{{ data.maiden_name }}
{{ current_user.maiden_name }}
<br/><br/>
{% endif %}
<b>Birth Date:</b><br/>
{{ data.birth_date }}
{{ current_user.birth_date }}
<br/><br/>
{% if data.sec_email %}
{% if current_user.sec_email %}
<b>Personal E-Mail:</b><br/>
{{ data.sec_email }}
{{ current_user.sec_email }}
<br/><br/>
{% endif %}
<b>Primary Phone:</b><br/>
{{ data.prim_phone }}
{{ current_user.prim_phone }}
<br/><br/>
{% if data.sec_phone %}
{% if current_user.sec_phone %}
<b>Secondary Phone:</b><br/>
{{ data.sec_phone }}
{{ current_user.sec_phone }}
<br/><br/>
{% endif %}
<hr>
<h5>Address</h5>
{{ data.thoroughfare }}<br>
{{ data.locality }}, {{ data.administrative_area }} {{ data.postal_code }}<br>
{{ data.country }}
{{ current_user.thoroughfare }}<br>
{% if current_user.premise %}
{{ current_user.premise }}<br>
{% endif %}
{{ current_user.locality }}, {{ current_user.administrative_area }} {{ current_user.postal_code }}<br>
{{ current_user.country }}
<br/><br/>
</p>
<hr/>
-47
View File
@@ -1,47 +0,0 @@
{% extends 'base.jinja2' %}
{% block title %}Splash{% endblock %}
{% block header %}{% endblock %}
{% block css %}
{{ super() }}
{# override the body and html css to force center #}
<style>
html, body {
height: 100%;
background-color: #777777;
}
</style>
{% endblock %}
{% block content_before %}
<div class="container-fluid h-100">
<div class="row h-100 justify-content-center align-items-center">
<div class="mx-auto" style="max-width: 30em;">
{# Splash card #}
<div class="card shadow rounded border-0 h-100">
<div class="card-header bg-primary pt-4 text-center text-white mb-4">
<img class="img-fluid mb-3" src="http://lib.msstate.edu/_assets/img/2015-header-logo-msstate.png"
alt=""/>
<h5>Electronic Thesis and Dissertation System</h5>
</div>
<div class="card-body d-flex flex-column text-center mb-2">
{# TODO: actually add content here #}
<h3>
Welcome!
</h3>
<p class="mb-5">
Please sign in to access this system.
</p>
<a href="{{ url_for("user.login") }}" class="btn btn-primary btn-lg mt-auto align-self-center px-4">
Sign in
</a>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
+3 -1
View File
@@ -34,7 +34,9 @@
<h3 class='card-title'>Review</h3>
<hr/>
<form method="POST">
{{ form.approve(class='btn btn-primary ml-1') }}
<br>
<br>
{# CSRF token #}
{{ form.csrf_token }}
{% for field in form %}
+23 -2
View File
@@ -10,6 +10,16 @@
<span class='lead'>
By {{ user.first_name }} {{ user.last_name }}
<br>
{% if not review %}
{% if submission.state %}
Revision has been Approved
{% else %}
Revision is in the review process
{% endif %}
{% else %}
Revision was denied, check feedback
{% endif %}
<br>
<br>
<a class="btn btn-primary" href="{{ url_for('submissions.view', submission_id=submission.id) }}">View Submission</a>
</span>
@@ -26,7 +36,9 @@
Submitted {{ revision.submitted.humanize() }}
<br>
<br>
<a class="btn btn-primary" href="{{ url_for('main.uploads_submissions', filename=revision.file) }}">View submitted file</a>
<a class="btn btn-primary" href="{{ url_for('main.uploads_submissions', filename=revision.file) }}">
View submitted file
</a>
</p>
</div>
</div>
@@ -205,8 +217,17 @@
</p>
{% endif %}
{% else %}
{% elif not submission.state %}
Revision has not been reviewed
{% if current_user.has_roles('reviewer') %}
<br>
<a class="btn btn-primary" href="{{ url_for('revisions.review', revision_id=revision.id) }}">
Review
</a>
{% endif %}
{% else %}
Revision was approved.<br>
No changes needed
{% endif %}
</p>
</div>
+12 -10
View File
@@ -17,14 +17,17 @@
{% block content %}
<a href="{{ url_for('submissions.create') }}"
class="btn btn-primary"
role="button"
aria-disabled="true">
Create Submission
</a>
{% if current_user.has_roles('users') %}
<a href="{{ url_for('submissions.create') }}"
class="btn btn-primary"
role="button"
aria-disabled="true">
Create Submission
</a>
{% endif %}
<hr/>
{# TODO datatables for all the saerch and pagination functionality #}
{% if submissions %}
<table class="table table-white table-striped table-bordered table-hover">
<thead>
<tr>
@@ -35,8 +38,6 @@
</tr>
</thead>
<tbody>
{% if submissions %}
{% for submission in submissions %}
<tr>
<td>{{ submission.last_name }}, {{ submission.first_name }}</td>
@@ -51,9 +52,10 @@
</td>
</tr>
{% endfor %}
{% endif %}
</tbody>
</table>
{% else %}
No submissions to show
{% endif %}
{% endblock %}
+56 -22
View File
@@ -20,6 +20,12 @@
<h1 class='font-weight-bolder'>{{ submission.title }}</h1>
<span class='lead'>
By {{ user.first_name }} {{ user.last_name }}
<br>
{% if submission.state %}
Submission has been Approved
{% else %}
Submission is in the review process
{% endif %}
</span>
</div>
</div>
@@ -80,7 +86,9 @@
<br>
<br>
<a class="btn btn-primary" href="{{ url_for('main.uploads_signatures', filename=submission.signature_file) }}">View Signature file</a>
<a class="btn btn-primary" href="{{ url_for('main.uploads_signatures', filename=submission.signature_file) }}">
View Signature file
</a>
</p>
</div>
</div>
@@ -89,29 +97,55 @@
<div class='card-body'>
<h3 class='card-title'>Revisions</h3>
<hr/>
{% if revisions %}
<table class='table table-borderless table-striped'>
<tbody>
<table class='table table-borderless table-striped'>
<tbody>
{% if revisions %}
{% for revision in revisions %}
<tr>
<td>Revision ID: {{ revision.id }}</td>
<td>Submitted {{ revision.submitted.humanize() }}</td>
<td></td>
<td><a href="{{ url_for('revisions.view', submission_id=submission.id, revision_id=revision.id) }}"
class="btn btn-primary"
role="button"
aria-disabled="true">View Revision</a>
</td>
</tr>
{% endfor %}
{% for revision in revisions %}
<tr>
{# this feels illegal, but it works
gets the index of the revision in the list and then add one
since array start at zero #}
<td>Revision {{ revisions.index(revision)+1 }}</td>
<td>Submitted {{ revision.submitted.humanize() }}</td>
<td>
{% if revisions[-1].id == revision.id %}
{% if not submission.state %}
{% if review_last %}
Reviewed
{% else %}
Not Reviewed
{% endif %}
{% else %}
Approved
{% endif %}
{% else %}
Reviewed
{% endif %}
</td>
<td>
<a href="{{ url_for('revisions.view',revision_id=revision.id) }}"
class="btn btn-primary"
role="button"
aria-disabled="true">
View Revision
</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
No revisions exist.<br><br>
{% endif %}
{% if not submission.state and current_user.id == user.id %}
{% if review_last or not revisions %}
<a id='tad-revise' href="{{ url_for('revisions.create', submission_id=submission.id) }}" class='btn btn-primary px-4'>
Create revision
</a>
{% endif %}
</tbody>
</table>
{# TODO: Only show if none exist or feedback has been received #}
<a id='tad-revise' href="{{ url_for('revisions.create', submission_id=submission.id) }}" class='btn btn-primary px-4'>
Create revision
</a>
{% endif %}
</div>
</div>