Remove public share mechanisms until legal matters are clarified

This commit is contained in:
Patrick Jentsch 2023-02-15 10:56:54 +01:00
parent df1862b0a4
commit 3e8bc5214c
6 changed files with 223 additions and 257 deletions

View File

@ -78,9 +78,6 @@ class UpdateCorpusFileForm(CorpusFileBaseForm):
kwargs['prefix'] = 'update-corpus-file-form' kwargs['prefix'] = 'update-corpus-file-form'
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
class ChangeCorpusSettingsForm(FlaskForm):
is_public = BooleanField('Public Corpus')
submit = SubmitField()
class ImportCorpusForm(FlaskForm): class ImportCorpusForm(FlaskForm):
pass pass

View File

@ -1,4 +1,4 @@
from datetime import datetime, timedelta from datetime import datetime
from flask import ( from flask import (
abort, abort,
current_app, current_app,
@ -15,19 +15,121 @@ from threading import Thread
import jwt import jwt
import os import os
from app import db, hashids from app import db, hashids
from app.models import Corpus, CorpusFile, CorpusStatus, CorpusFollowerAssociation, User from app.models import Corpus, CorpusFile, CorpusStatus, User
from . import bp from . import bp
from .forms import ChangeCorpusSettingsForm, CreateCorpusFileForm, CreateCorpusForm, UpdateCorpusFileForm from .forms import (
CreateCorpusFileForm,
CreateCorpusForm,
UpdateCorpusFileForm
)
@bp.route('') # @bp.route('/share/<token>', methods=['GET', 'POST'])
# def share_corpus(token):
# try:
# payload = jwt.decode(
# token,
# current_app.config['SECRET_KEY'],
# algorithms=['HS256'],
# issuer=current_app.config['SERVER_NAME'],
# options={'require': ['iat', 'iss', 'sub']}
# )
# except jwt.PyJWTError:
# return False
# corpus_hashid = payload.get('sub')
# corpus_id = hashids.decode(corpus_hashid)
# return redirect(url_for('.corpus', corpus_id=corpus_id))
@bp.route('/<hashid:corpus_id>/enable_is_public', methods=['POST'])
@login_required @login_required
def corpora(): def enable_corpus_is_public(corpus_id):
query = Corpus.query.filter( corpus = Corpus.query.get_or_404(corpus_id)
(Corpus.user_id == current_user.id) | (Corpus.is_public == True) if not (corpus.user == current_user or current_user.is_administrator()):
abort(403)
corpus.is_public = True
db.session.commit()
return '', 204
@bp.route('/<hashid:corpus_id>/disable_is_public', methods=['POST'])
@login_required
def disable_corpus_is_public(corpus_id):
corpus = Corpus.query.get_or_404(corpus_id)
if not (corpus.user == current_user or current_user.is_administrator()):
abort(403)
corpus.is_public = False
db.session.commit()
return '', 204
# @bp.route('/<hashid:corpus_id>/follow', methods=['GET', 'POST'])
# @login_required
# def follow_corpus(corpus_id):
# corpus = Corpus.query.get_or_404(corpus_id)
# user_hashid = request.args.get('user_id')
# if user_hashid is None:
# user = current_user
# else:
# if not current_user.is_administrator():
# abort(403)
# else:
# user_id = hashids.decode(user_hashid)
# user = User.query.get_or_404(user_id)
# if not user.is_following_corpus(corpus):
# user.follow_corpus(corpus)
# db.session.commit()
# flash(f'You are following {corpus.title} now', category='corpus')
# return {}, 202
@bp.route('/<hashid:corpus_id>/unfollow', methods=['GET', 'POST'])
@login_required
def unfollow_corpus(corpus_id):
corpus = Corpus.query.get_or_404(corpus_id)
user_hashid = request.args.get('user_id')
if user_hashid is None:
user = current_user
elif current_user.is_administrator():
user_id = hashids.decode(user_hashid)
user = User.query.get_or_404(user_id)
else:
abort(403)
if user.is_following_corpus(corpus):
user.unfollow_corpus(corpus)
db.session.commit()
flash(f'You are not following {corpus.title} anymore', category='corpus')
return {}, 202
# @bp.route('/add_permission/<hashid:corpus_id>/<hashid:user_id>/<int:permission>')
# def add_permission(corpus_id, user_id, permission):
# a = CorpusFollowerAssociation.query.filter_by(followed_corpus_id=corpus_id, following_user_id=user_id).first_or_404()
# a.add_permission(permission)
# db.session.commit()
# return 'ok'
# @bp.route('/remove_permission/<hashid:corpus_id>/<hashid:user_id>/<int:permission>')
# def remove_permission(corpus_id, user_id, permission):
# a = CorpusFollowerAssociation.query.filter_by(followed_corpus_id=corpus_id, following_user_id=user_id).first_or_404()
# a.remove_permission(permission)
# db.session.commit()
# return 'ok'
@bp.route('/public')
@login_required
def public_corpora():
corpora = [
c.to_json_serializeable()
for c in Corpus.query.filter(Corpus.is_public == True).all()
]
return render_template(
'corpora/public_corpora.html.j2',
corpora=corpora,
title='Corpora'
) )
corpora = [c.to_json_serializeable() for c in query.all()]
return render_template('corpora/corpora.html.j2', corpora=corpora, title='Corpora')
@bp.route('/create', methods=['GET', 'POST']) @bp.route('/create', methods=['GET', 'POST'])
@ -60,83 +162,33 @@ def create_corpus():
@login_required @login_required
def corpus(corpus_id): def corpus(corpus_id):
corpus = Corpus.query.get_or_404(corpus_id) corpus = Corpus.query.get_or_404(corpus_id)
if not (corpus.user == current_user if corpus.user == current_user or current_user.is_administrator():
or current_user.is_administrator() # now = datetime.utcnow()
or current_user.is_following_corpus(corpus) # payload = {
or corpus.is_public): # 'iat': now,
abort(403) # 'iss': current_app.config['SERVER_NAME'],
corpus_settings_form = ChangeCorpusSettingsForm( # 'sub': corpus.hashid
data=corpus.to_json_serializeable(), # }
prefix='corpus-settings-form' # token = jwt.encode(
) # payload,
if corpus_settings_form.validate_on_submit(): # current_app.config['SECRET_KEY'],
corpus.is_public = corpus_settings_form.is_public.data # algorithm='HS256'
db.session.commit() # )
flash('Your changes have been saved')
return redirect(url_for('.corpus', corpus_id=corpus.id))
now = datetime.utcnow()
payload = {
'iat': now,
'iss': current_app.config['SERVER_NAME'],
'sub': corpus.hashid
}
token = jwt.encode(
payload,
current_app.config['SECRET_KEY'],
algorithm='HS256'
)
if corpus.user == current_user:
return render_template( return render_template(
'corpora/corpus.html.j2', 'corpora/corpus.html.j2',
corpus=corpus, corpus=corpus,
token=token, # token=token,
title='Corpus' title='Corpus'
) )
else: if current_user.is_following_corpus(corpus) or corpus.is_public:
corpus_files = [x.to_json_serializeable() for x in corpus.files] corpus_files = [x.to_json_serializeable() for x in corpus.files]
return render_template( return render_template(
'corpora/corpus_public.html.j2', 'corpora/public_corpus.html.j2',
corpus=corpus, corpus=corpus,
corpus_files=corpus_files, corpus_files=corpus_files,
title='Corpus' title='Corpus'
) )
abort(403)
@bp.route('/share/<token>', methods=['GET', 'POST'])
def share_corpus(token):
try:
payload = jwt.decode(
token,
current_app.config['SECRET_KEY'],
algorithms=['HS256'],
issuer=current_app.config['SERVER_NAME'],
options={'require': ['iat', 'iss', 'sub']}
)
except jwt.PyJWTError:
return False
corpus_hashid = payload.get('sub')
corpus_id = hashids.decode(corpus_hashid)
return redirect(url_for('.corpus', corpus_id=corpus_id))
@bp.route('/<hashid:corpus_id>/enable_is_public', methods=['POST'])
@login_required
def enable_corpus_is_public(corpus_id):
corpus = Corpus.query.get_or_404(corpus_id)
if not (corpus.user == current_user or current_user.is_administrator()):
abort(403)
corpus.is_public = True
db.session.commit()
return '', 204
@bp.route('/<hashid:corpus_id>/disable_is_public', methods=['POST'])
@login_required
def disable_corpus_is_public(corpus_id):
corpus = Corpus.query.get_or_404(corpus_id)
if not (corpus.user == current_user or current_user.is_administrator()):
abort(403)
corpus.is_public = False
db.session.commit()
return '', 204
@bp.route('/<hashid:corpus_id>', methods=['DELETE']) @bp.route('/<hashid:corpus_id>', methods=['DELETE'])
@ -165,8 +217,7 @@ def analyse_corpus(corpus_id):
corpus = Corpus.query.get_or_404(corpus_id) corpus = Corpus.query.get_or_404(corpus_id)
if not (corpus.user == current_user if not (corpus.user == current_user
or current_user.is_administrator() or current_user.is_administrator()
or current_user.is_following_corpus(corpus) or current_user.is_following_corpus(corpus)):
or corpus.is_public):
abort(403) abort(403)
return render_template( return render_template(
'corpora/analyse_corpus.html.j2', 'corpora/analyse_corpus.html.j2',
@ -315,57 +366,3 @@ def import_corpus():
@login_required @login_required
def export_corpus(corpus_id): def export_corpus(corpus_id):
abort(503) abort(503)
@bp.route('/<hashid:corpus_id>/follow', methods=['GET', 'POST'])
@login_required
def follow_corpus(corpus_id):
corpus = Corpus.query.get_or_404(corpus_id)
user_hashid = request.args.get('user_id')
if user_hashid is None:
user = current_user
else:
if not current_user.is_administrator():
abort(403)
else:
user_id = hashids.decode(user_hashid)
user = User.query.get_or_404(user_id)
if not user.is_following_corpus(corpus):
user.follow_corpus(corpus)
db.session.commit()
flash(f'You are following {corpus.title} now', category='corpus')
return {}, 202
@bp.route('/<hashid:corpus_id>/unfollow', methods=['GET', 'POST'])
@login_required
def unfollow_corpus(corpus_id):
corpus = Corpus.query.get_or_404(corpus_id)
user_hashid = request.args.get('user_id')
if user_hashid is None:
user = current_user
else:
if not current_user.is_administrator():
abort(403)
else:
user_id = hashids.decode(user_hashid)
user = User.query.get_or_404(user_id)
if user.is_following_corpus(corpus):
user.unfollow_corpus(corpus)
db.session.commit()
flash(f'You are not following {corpus.title} anymore', category='corpus')
return {}, 202
@bp.route('/add_permission/<hashid:corpus_id>/<hashid:user_id>/<int:permission>')
def add_permission(corpus_id, user_id, permission):
a = CorpusFollowerAssociation.query.filter_by(followed_corpus_id=corpus_id, following_user_id=user_id).first_or_404()
a.add_permission(permission)
db.session.commit()
return 'ok'
@bp.route('/remove_permission/<hashid:corpus_id>/<hashid:user_id>/<int:permission>')
def remove_permission(corpus_id, user_id, permission):
a = CorpusFollowerAssociation.query.filter_by(followed_corpus_id=corpus_id, following_user_id=user_id).first_or_404()
a.remove_permission(permission)
db.session.commit()
return 'ok'

View File

@ -58,16 +58,6 @@
</div> </div>
</div> </div>
<div class="card-action"> <div class="card-action">
<div class="left-align">
<div class="action-switch switch center-align" data-action="toggle-is-public">
<span class="share"></span>
<label>
<input class="corpus-is-public" {% if corpus.is_public %}checked{% endif %} type="checkbox">
<span class="lever"></span>
public
</label>
</div>
</div>
<div class="right-align"> <div class="right-align">
<a class="btn corpus-analyse-trigger disabled waves-effect waves-light" href="{{ url_for('corpora.analyse_corpus', corpus_id=corpus.id) }}"><i class="material-icons left">search</i>Analyze</a> <a class="btn corpus-analyse-trigger disabled waves-effect waves-light" href="{{ url_for('corpora.analyse_corpus', corpus_id=corpus.id) }}"><i class="material-icons left">search</i>Analyze</a>
<a class="action-button btn disabled waves-effect waves-light" data-action="build-request"><i class="nopaque-icons left">K</i>Build</a> <a class="action-button btn disabled waves-effect waves-light" data-action="build-request"><i class="nopaque-icons left">K</i>Build</a>
@ -89,17 +79,25 @@
</div> </div>
</div> </div>
</div> </div>
{% if current_user.can(Permission.ADMINISTRATE) or current_user.hashid == corpus.user.hashid %}
<div class="col s12"> {# <div class="col s12">
<div class="card"> <div class="card">
<div class="card-content"> <div class="card-content">
<div class="action-switch switch center-align" data-action="toggle-is-public">
<span class="share"></span>
<label>
<input class="corpus-is-public" {% if corpus.is_public %}checked{% endif %} type="checkbox">
<span class="lever"></span>
public
</label>
</div>
<a class="action-button btn waves-effect waves-light" id="generate-share-link-button">Generate Share Link</a> <a class="action-button btn waves-effect waves-light" id="generate-share-link-button">Generate Share Link</a>
<div id="share-link"></div> <div id="share-link"></div>
<a class="action-button btn-small waves-effect waves-light hide" id="copy-share-link-button">Copy</a> <a class="action-button btn-small waves-effect waves-light hide" id="copy-share-link-button">Copy</a>
</div> </div>
</div> </div>
</div> </div>
{% endif %}
<div class="col s12"> <div class="col s12">
<div class="card"> <div class="card">
@ -108,7 +106,7 @@
<div class="user-list no-autoinit"></div> <div class="user-list no-autoinit"></div>
</div> </div>
</div> </div>
</div> </div> #}
</div> </div>
</div> </div>
{% endblock page_content %} {% endblock page_content %}
@ -117,6 +115,8 @@
{{ super() }} {{ super() }}
<script> <script>
let corpusDisplay = new CorpusDisplay(document.querySelector('#corpus-display')); let corpusDisplay = new CorpusDisplay(document.querySelector('#corpus-display'));
</script>
{# <script>
let generateShareLinkButton = document.querySelector('#generate-share-link-button'); let generateShareLinkButton = document.querySelector('#generate-share-link-button');
let copyShareLinkButton = document.querySelector('#copy-share-link-button'); let copyShareLinkButton = document.querySelector('#copy-share-link-button');
let shareLink = document.querySelector('#share-link'); let shareLink = document.querySelector('#share-link');
@ -136,5 +136,5 @@
document.execCommand('copy'); document.execCommand('copy');
app.flash(`Copied!`, 'success'); app.flash(`Copied!`, 'success');
}); });
</script> </script> #}
{% endblock scripts %} {% endblock scripts %}

View File

@ -1,108 +0,0 @@
{% extends "base.html.j2" %}
{% import "materialize/wtf.html.j2" as wtf %}
{% block main_attribs %} class="service-scheme" data-service="corpus-analysis"{% endblock main_attribs %}
{% block page_content %}
<div class="container">
<div class="row">
<div class="col s12">
<h1>{{ corpus.title }} </h1>
<div class="row">
<div class="col s8 m9 l10">
<a class="btn waves-effect waves-light" id="follow-corpus-request">
{% if current_user.is_following_corpus(corpus) %}
<i class="material-icons left">add</i>Unfollow Corpus
{% else %}
<i class="material-icons left">add</i>Follow Corpus
{% endif %}
</a>
{% if corpus.status.name in ['BUILT', 'STARTING_ANALYSIS_SESSION', 'RUNNING_ANALYSIS_SESSION', 'CANCELING_ANALYSIS_SESSION'] and current_user.is_following_corpus(corpus) %}
<a class="btn waves-effect waves-light" href="{{ url_for('corpora.analyse_corpus', corpus_id=corpus.id) }}">Analyse</a>
{% endif %}
</div>
</div>
<div class="card service-color-border border-darken" data-service="corpus-analysis" style="border-top: 10px solid">
<div class="card-content">
<div class="row">
<div class="col s12">
<p><b>Status:</b> <span class="chip corpus-status-text corpus-status-color white-text" data-status="{{ corpus.status.name }}"></span></p>
<p></p>
<br>
</div>
<div class="col s12">
<p><b>Description:</b> {{ corpus.description }}</p>
<br>
<p></p>
</div>
<div class="col s6">
<p><b>Creation date:</b> {{ corpus.creation_date }}</p>
</div>
<div class="col s6">
<p><b>Number of tokens used:</b> {{ corpus.num_tokens }}</p>
</div>
</div>
</div>
</div>
<div class="card">
<div class="card-content">
<span class="card-title" id="files">Corpus files</span>
<div class="corpus-file-list no-autoinit" data-user-id="{{ corpus.user.hashid }}" data-corpus-id="{{ corpus.hashid }}"></div>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock page_content %}
{% block scripts %}
{{ super() }}
<script>
let corpusFileList = new PublicCorpusFileList(document.querySelector('.corpus-file-list'));
corpusFileList.add({{ corpus_files|tojson }});
let corpusFollowingRequest = document.querySelector('#follow-corpus-request');
{# let followingUserList = new UserList(document.querySelector('.user-list'));
followingUserList.add({{ following_users|tojson }}); #}
corpusFollowingRequest.addEventListener('click', () => {
if ({{ current_user.is_following_corpus(corpus)|tojson }}) {
return new Promise((resolve, reject) => {
fetch(`/corpora/{{ corpus.hashid }}/unfollow`, {method: 'POST', headers: {Accept: 'application/json'}})
.then(
(response) => {
if (response.status === 403) {app.flash('Forbidden', 'error'); reject(response);}
if (response.status === 404) {app.flash('Not Found', 'error'); reject(response);}
{# app.flash(`You are not following "{{ corpus.title }}" anymore`, 'corpus'); #}
resolve(response);
window.location.href = '{{ url_for("corpora.corpus", corpus_id=corpus.id) }}';
},
(response) => {
app.flash('Something went wrong', 'error');
reject(response);
}
);
});
} else {
return new Promise((resolve, reject) => {
fetch(`/corpora/{{ corpus.hashid }}/follow`, {method: 'POST', headers: {Accept: 'application/json'}})
.then(
(response) => {
if (response.status === 403) {app.flash('Forbidden', 'error'); reject(response);}
if (response.status === 404) {app.flash('Not Found', 'error'); reject(response);}
{# app.flash(`You follow "{{ corpus.title }}" now`, 'corpus'); #}
window.location.href = '{{ url_for("corpora.corpus", corpus_id=corpus.id) }}';
resolve(response);
},
(response) => {
app.flash('Something went wrong', 'error');
reject(response);
}
);
});
}
});
</script>
{% endblock scripts %}

View File

@ -0,0 +1,80 @@
{% extends "base.html.j2" %}
{% import "materialize/wtf.html.j2" as wtf %}
{% block main_attribs %} class="service-scheme" data-service="corpus-analysis"{% endblock main_attribs %}
{% block page_content %}
<div class="container">
<div class="row">
<div class="col s12">
<h1>{{ corpus.title }} </h1>
<div class="row">
<div class="col s8 m9 l10">
{% if current_user.is_following_corpus(corpus) %}
<a class="action-button btn waves-effect waves-light" data-action="unfollow-request"><i class="material-icons left">add</i>Unfollow Corpus</a>
{% endif %}
{% if corpus.status.name in ['BUILT', 'STARTING_ANALYSIS_SESSION', 'RUNNING_ANALYSIS_SESSION', 'CANCELING_ANALYSIS_SESSION'] and current_user.is_following_corpus(corpus) %}
<a class="btn waves-effect waves-light" href="{{ url_for('corpora.analyse_corpus', corpus_id=corpus.id) }}">Analyse</a>
{% endif %}
</div>
</div>
<div class="card service-color-border border-darken" data-service="corpus-analysis" style="border-top: 10px solid">
<div class="card-content">
<div class="row">
<div class="col s12">
<p><b>Status:</b> <span class="chip corpus-status-text corpus-status-color white-text" data-status="{{ corpus.status.name }}"></span></p>
<p></p>
<br>
</div>
<div class="col s12">
<p><b>Description:</b> {{ corpus.description }}</p>
<br>
<p></p>
</div>
<div class="col s6">
<p><b>Creation date:</b> {{ corpus.creation_date }}</p>
</div>
<div class="col s6">
<p><b>Number of tokens used:</b> {{ corpus.num_tokens }}</p>
</div>
</div>
</div>
</div>
<div class="card">
<div class="card-content">
<span class="card-title" id="files">Corpus files</span>
<div class="corpus-file-list no-autoinit" data-user-id="{{ corpus.user.hashid }}" data-corpus-id="{{ corpus.hashid }}"></div>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock page_content %}
{% block scripts %}
{{ super() }}
<script>
let corpusFileList = new PublicCorpusFileList(document.querySelector('.corpus-file-list'));
corpusFileList.add({{ corpus_files|tojson }});
let unfollowRequestElement = document.querySelector('.action-button[data-action="unfollow-request"]');
unfollowRequestElement.addEventListener('click', () => {
return new Promise((resolve, reject) => {
fetch('{{ url_for("corpora.unfollow_corpus", corpus_id=corpus.id) }}', {method: 'POST', headers: {Accept: 'application/json'}})
.then(
(response) => {
if (response.status === 403) {app.flash('Forbidden', 'error'); reject(response);}
if (response.status === 404) {app.flash('Not Found', 'error'); reject(response);}
resolve(response);
window.location.href = '{{ url_for("corpora.corpus", corpus_id=corpus.id) }}';
},
(response) => {
app.flash('Something went wrong', 'error');
reject(response);
}
);
});
});
</script>
{% endblock scripts %}