mirror of
https://gitlab.ub.uni-bielefeld.de/sfb1288inf/nopaque.git
synced 2024-11-15 01:05:42 +00:00
Merge branch 'public-corpus' into development
This commit is contained in:
commit
112d1ec020
@ -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
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
from datetime import datetime
|
||||||
from flask import (
|
from flask import (
|
||||||
abort,
|
abort,
|
||||||
current_app,
|
current_app,
|
||||||
@ -11,21 +12,124 @@ from flask import (
|
|||||||
)
|
)
|
||||||
from flask_login import current_user, login_required
|
from flask_login import current_user, login_required
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
|
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'])
|
||||||
@ -58,48 +162,34 @@ 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
|
|
||||||
or current_user.is_administrator()
|
|
||||||
or current_user.is_following_corpus(corpus)
|
|
||||||
or corpus.is_public):
|
|
||||||
abort(403)
|
|
||||||
corpus_settings_form = ChangeCorpusSettingsForm(
|
|
||||||
data=corpus.to_json_serializeable(),
|
|
||||||
prefix='corpus-settings-form'
|
|
||||||
)
|
|
||||||
if corpus_settings_form.validate_on_submit():
|
|
||||||
corpus.is_public = corpus_settings_form.is_public.data
|
|
||||||
db.session.commit()
|
|
||||||
flash('Your changes have been saved')
|
|
||||||
return redirect(url_for('.corpus', corpus_id=corpus.id))
|
|
||||||
if corpus.user == current_user or current_user.is_administrator():
|
if corpus.user == current_user or current_user.is_administrator():
|
||||||
|
# now = datetime.utcnow()
|
||||||
|
# payload = {
|
||||||
|
# 'exp': now + timedelta(weeks=1),
|
||||||
|
# 'iat': now,
|
||||||
|
# 'iss': current_app.config['SERVER_NAME'],
|
||||||
|
# 'sub': corpus.hashid
|
||||||
|
# }
|
||||||
|
# token = jwt.encode(
|
||||||
|
# payload,
|
||||||
|
# current_app.config['SECRET_KEY'],
|
||||||
|
# algorithm='HS256'
|
||||||
|
# )
|
||||||
return render_template(
|
return render_template(
|
||||||
'corpora/corpus.html.j2',
|
'corpora/corpus.html.j2',
|
||||||
corpus_settings_form=corpus_settings_form,
|
|
||||||
corpus=corpus,
|
corpus=corpus,
|
||||||
|
# token=token,
|
||||||
title='Corpus'
|
title='Corpus'
|
||||||
)
|
)
|
||||||
else:
|
if current_user.is_following_corpus(corpus) or corpus.is_public:
|
||||||
print('public')
|
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,
|
||||||
title='Corpus'
|
title='Corpus'
|
||||||
)
|
)
|
||||||
|
abort(403)
|
||||||
|
|
||||||
|
|
||||||
# @bp.route('/<hashid:corpus_id>/update')
|
|
||||||
# @login_required
|
|
||||||
# def update_corpus(corpus_id):
|
|
||||||
# corpus = Corpus.query.get_or_404(corpus_id)
|
|
||||||
# if not (corpus.user == current_user or current_user.is_administrator()):
|
|
||||||
# abort(403)
|
|
||||||
# return render_template(
|
|
||||||
# 'corpora/update_corpus.html.j2',
|
|
||||||
# corpus=corpus,
|
|
||||||
# title='Corpus'
|
|
||||||
# )
|
|
||||||
|
|
||||||
|
|
||||||
@bp.route('/<hashid:corpus_id>', methods=['DELETE'])
|
@bp.route('/<hashid:corpus_id>', methods=['DELETE'])
|
||||||
@ -128,8 +218,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',
|
||||||
@ -278,55 +367,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()
|
|
||||||
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()
|
|
||||||
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'
|
|
||||||
|
|
||||||
|
@ -27,15 +27,20 @@ def faq():
|
|||||||
@bp.route('/dashboard')
|
@bp.route('/dashboard')
|
||||||
@login_required
|
@login_required
|
||||||
def dashboard():
|
def dashboard():
|
||||||
users = [
|
# users = [
|
||||||
u.to_json_serializeable(filter_by_privacy_settings=True) for u
|
# u.to_json_serializeable(filter_by_privacy_settings=True) for u
|
||||||
in User.query.filter(User.is_public == True, User.id != current_user.id).all()
|
# in User.query.filter(User.is_public == True, User.id != current_user.id).all()
|
||||||
]
|
# ]
|
||||||
corpora = [
|
# corpora = [
|
||||||
c.to_json_serializeable() for c
|
# c.to_json_serializeable() for c
|
||||||
in Corpus.query.filter(Corpus.is_public == True).all()
|
# in Corpus.query.filter(Corpus.is_public == True, Corpus.user != current_user).all()
|
||||||
]
|
# ]
|
||||||
return render_template('main/dashboard.html.j2', title='Dashboard', users=users, corpora=corpora)
|
return render_template(
|
||||||
|
'main/dashboard.html.j2',
|
||||||
|
title='Dashboard',
|
||||||
|
# users=users,
|
||||||
|
# corpora=corpora
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@bp.route('/dashboard2')
|
@bp.route('/dashboard2')
|
||||||
|
@ -11,6 +11,7 @@ class CorpusFileList extends ResourceList {
|
|||||||
this.isInitialized = false;
|
this.isInitialized = false;
|
||||||
this.userId = listContainerElement.dataset.userId;
|
this.userId = listContainerElement.dataset.userId;
|
||||||
this.corpusId = listContainerElement.dataset.corpusId;
|
this.corpusId = listContainerElement.dataset.corpusId;
|
||||||
|
if (this.userId === undefined || this.corpusId === undefined) {return;}
|
||||||
app.subscribeUser(this.userId).then((response) => {
|
app.subscribeUser(this.userId).then((response) => {
|
||||||
app.socket.on('PATCH', (patch) => {
|
app.socket.on('PATCH', (patch) => {
|
||||||
if (this.isInitialized) {this.onPatch(patch);}
|
if (this.isInitialized) {this.onPatch(patch);}
|
||||||
|
@ -8,8 +8,9 @@ class CorpusList extends ResourceList {
|
|||||||
constructor(listContainerElement, options = {}) {
|
constructor(listContainerElement, options = {}) {
|
||||||
super(listContainerElement, options);
|
super(listContainerElement, options);
|
||||||
this.listjs.list.addEventListener('click', (event) => {this.onClick(event)});
|
this.listjs.list.addEventListener('click', (event) => {this.onClick(event)});
|
||||||
this.isInitialized = false;
|
this.isInitialized = false
|
||||||
this.userId = listContainerElement.dataset.userId;
|
this.userId = listContainerElement.dataset.userId;
|
||||||
|
if (this.userId === undefined) {return;}
|
||||||
app.subscribeUser(this.userId).then((response) => {
|
app.subscribeUser(this.userId).then((response) => {
|
||||||
app.socket.on('PATCH', (patch) => {
|
app.socket.on('PATCH', (patch) => {
|
||||||
if (this.isInitialized) {this.onPatch(patch);}
|
if (this.isInitialized) {this.onPatch(patch);}
|
||||||
|
@ -11,6 +11,7 @@ class JobInputList extends ResourceList {
|
|||||||
this.isInitialized = false;
|
this.isInitialized = false;
|
||||||
this.userId = listContainerElement.dataset.userId;
|
this.userId = listContainerElement.dataset.userId;
|
||||||
this.jobId = listContainerElement.dataset.jobId;
|
this.jobId = listContainerElement.dataset.jobId;
|
||||||
|
if (this.userId === undefined || this.jobId === undefined) {return;}
|
||||||
app.subscribeUser(this.userId).then((response) => {
|
app.subscribeUser(this.userId).then((response) => {
|
||||||
app.socket.on('PATCH', (patch) => {
|
app.socket.on('PATCH', (patch) => {
|
||||||
if (this.isInitialized) {this.onPatch(patch);}
|
if (this.isInitialized) {this.onPatch(patch);}
|
||||||
|
@ -10,6 +10,7 @@ class JobList extends ResourceList {
|
|||||||
this.listjs.list.addEventListener('click', (event) => {this.onClick(event)});
|
this.listjs.list.addEventListener('click', (event) => {this.onClick(event)});
|
||||||
this.isInitialized = false;
|
this.isInitialized = false;
|
||||||
this.userId = listContainerElement.dataset.userId;
|
this.userId = listContainerElement.dataset.userId;
|
||||||
|
if (this.userId === undefined) {return;}
|
||||||
app.subscribeUser(this.userId).then((response) => {
|
app.subscribeUser(this.userId).then((response) => {
|
||||||
app.socket.on('PATCH', (patch) => {
|
app.socket.on('PATCH', (patch) => {
|
||||||
if (this.isInitialized) {this.onPatch(patch);}
|
if (this.isInitialized) {this.onPatch(patch);}
|
||||||
|
@ -11,6 +11,7 @@ class JobResultList extends ResourceList {
|
|||||||
this.isInitialized = false;
|
this.isInitialized = false;
|
||||||
this.userId = listContainerElement.dataset.userId;
|
this.userId = listContainerElement.dataset.userId;
|
||||||
this.jobId = listContainerElement.dataset.jobId;
|
this.jobId = listContainerElement.dataset.jobId;
|
||||||
|
if (this.userId === undefined || this.jobId === undefined) {return;}
|
||||||
app.subscribeUser(this.userId).then((response) => {
|
app.subscribeUser(this.userId).then((response) => {
|
||||||
app.socket.on('PATCH', (patch) => {
|
app.socket.on('PATCH', (patch) => {
|
||||||
if (this.isInitialized) {this.onPatch(patch);}
|
if (this.isInitialized) {this.onPatch(patch);}
|
||||||
|
15
app/static/js/ResourceLists/PublicCorpusFileList.js
Normal file
15
app/static/js/ResourceLists/PublicCorpusFileList.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
class PublicCorpusFileList extends CorpusFileList {
|
||||||
|
get item() {
|
||||||
|
return `
|
||||||
|
<tr class="list-item clickable hoverable">
|
||||||
|
<td><span class="filename"></span></td>
|
||||||
|
<td><span class="author"></span></td>
|
||||||
|
<td><span class="title"></span></td>
|
||||||
|
<td><span class="publishing-year"></span></td>
|
||||||
|
<td class="right-align">
|
||||||
|
<a class="list-action-trigger btn-floating service-color darken waves-effect waves-light" data-list-action="view" data-service="corpus-analysis"><i class="material-icons">send</i></a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
`.trim();
|
||||||
|
}
|
||||||
|
}
|
14
app/static/js/ResourceLists/PublicCorpusList.js
Normal file
14
app/static/js/ResourceLists/PublicCorpusList.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
class PublicCorpusList extends CorpusList {
|
||||||
|
get item() {
|
||||||
|
return `
|
||||||
|
<tr class="list-item clickable hoverable">
|
||||||
|
<td><a class="btn-floating disabled"><i class="material-icons service-color darken" data-service="corpus-analysis">book</i></a></td>
|
||||||
|
<td><b class="title"></b><br><i class="description"></i></td>
|
||||||
|
<td><span class="status badge new corpus-status-color corpus-status-text" data-badge-caption=""></span></td>
|
||||||
|
<td class="right-align">
|
||||||
|
<a class="list-action-trigger btn-floating service-color darken waves-effect waves-light" data-list-action="view" data-service="corpus-analysis"><i class="material-icons">send</i></a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
`.trim();
|
||||||
|
}
|
||||||
|
}
|
@ -11,6 +11,7 @@ class SpaCyNLPPipelineModelList extends ResourceList {
|
|||||||
this.listjs.list.addEventListener('click', (event) => {this.onClick(event)});
|
this.listjs.list.addEventListener('click', (event) => {this.onClick(event)});
|
||||||
this.isInitialized = false;
|
this.isInitialized = false;
|
||||||
this.userId = listContainerElement.dataset.userId;
|
this.userId = listContainerElement.dataset.userId;
|
||||||
|
if (this.userId === undefined) {return;}
|
||||||
app.subscribeUser(this.userId).then((response) => {
|
app.subscribeUser(this.userId).then((response) => {
|
||||||
app.socket.on('PATCH', (patch) => {
|
app.socket.on('PATCH', (patch) => {
|
||||||
if (this.isInitialized) {this.onPatch(patch);}
|
if (this.isInitialized) {this.onPatch(patch);}
|
||||||
|
@ -11,6 +11,7 @@ class TesseractOCRPipelineModelList extends ResourceList {
|
|||||||
this.listjs.list.addEventListener('click', (event) => {this.onClick(event)});
|
this.listjs.list.addEventListener('click', (event) => {this.onClick(event)});
|
||||||
this.isInitialized = false;
|
this.isInitialized = false;
|
||||||
this.userId = listContainerElement.dataset.userId;
|
this.userId = listContainerElement.dataset.userId;
|
||||||
|
if (this.userId === undefined) {return;}
|
||||||
app.subscribeUser(this.userId).then((response) => {
|
app.subscribeUser(this.userId).then((response) => {
|
||||||
app.socket.on('PATCH', (patch) => {
|
app.socket.on('PATCH', (patch) => {
|
||||||
if (this.isInitialized) {this.onPatch(patch);}
|
if (this.isInitialized) {this.onPatch(patch);}
|
||||||
|
@ -12,6 +12,16 @@ class CorpusDisplay extends RessourceDisplay {
|
|||||||
.addEventListener('click', (event) => {
|
.addEventListener('click', (event) => {
|
||||||
Utils.deleteCorpusRequest(this.userId, this.corpusId);
|
Utils.deleteCorpusRequest(this.userId, this.corpusId);
|
||||||
});
|
});
|
||||||
|
this.displayElement
|
||||||
|
.querySelector('.action-switch[data-action="toggle-is-public"]')
|
||||||
|
.addEventListener('click', (event) => {
|
||||||
|
if (event.target.tagName !== 'INPUT') {return;}
|
||||||
|
if (event.target.checked) {
|
||||||
|
Utils.enableCorpusIsPublicRequest(this.userId, this.corpusId);
|
||||||
|
} else {
|
||||||
|
Utils.disableCorpusIsPublicRequest(this.userId, this.corpusId);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
init(user) {
|
init(user) {
|
||||||
|
@ -69,6 +69,88 @@ class Utils {
|
|||||||
return Utils.mergeObjectsDeep(mergedObject, ...objects.slice(2));
|
return Utils.mergeObjectsDeep(mergedObject, ...objects.slice(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static enableCorpusIsPublicRequest(userId, corpusId) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let corpus;
|
||||||
|
try {
|
||||||
|
corpus = app.data.users[userId].corpora[corpusId];
|
||||||
|
} catch (error) {
|
||||||
|
corpus = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
let modalElement = Utils.HTMLToElement(
|
||||||
|
`
|
||||||
|
<div class="modal">
|
||||||
|
<div class="modal-content">
|
||||||
|
<h4>Hier könnte eine Warnung stehen</h4>
|
||||||
|
<p></p>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<a class="action-button btn modal-close waves-effect waves-light" data-action="cancel">Cancel</a>
|
||||||
|
<a class="action-button btn modal-close red waves-effect waves-light" data-action="confirm">Confirm</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
);
|
||||||
|
document.querySelector('#modals').appendChild(modalElement);
|
||||||
|
let modal = M.Modal.init(
|
||||||
|
modalElement,
|
||||||
|
{
|
||||||
|
dismissible: false,
|
||||||
|
onCloseEnd: () => {
|
||||||
|
modal.destroy();
|
||||||
|
modalElement.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
let confirmElement = modalElement.querySelector('.action-button[data-action="confirm"]');
|
||||||
|
confirmElement.addEventListener('click', (event) => {
|
||||||
|
let corpusTitle = corpus?.title;
|
||||||
|
fetch(`/corpora/${corpusId}/enable_is_public`, {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(`Corpus "${corpusTitle}" is public now`, 'corpus');
|
||||||
|
resolve(response);
|
||||||
|
},
|
||||||
|
(response) => {
|
||||||
|
app.flash('Something went wrong', 'error');
|
||||||
|
reject(response);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
modal.open();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static disableCorpusIsPublicRequest(userId, corpusId) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let corpus;
|
||||||
|
try {
|
||||||
|
corpus = app.data.users[userId].corpora[corpusId];
|
||||||
|
} catch (error) {
|
||||||
|
corpus = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
let corpusTitle = corpus?.title;
|
||||||
|
fetch(`/corpora/${corpusId}/disable_is_public`, {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(`Corpus "${corpusTitle}" is private now`, 'corpus');
|
||||||
|
resolve(response);
|
||||||
|
},
|
||||||
|
(response) => {
|
||||||
|
app.flash('Something went wrong', 'error');
|
||||||
|
reject(response);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
static buildCorpusRequest(userId, corpusId) {
|
static buildCorpusRequest(userId, corpusId) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
let corpus;
|
let corpus;
|
||||||
|
@ -20,7 +20,9 @@
|
|||||||
'js/RessourceDisplays/JobDisplay.js',
|
'js/RessourceDisplays/JobDisplay.js',
|
||||||
'js/ResourceLists/ResourceList.js',
|
'js/ResourceLists/ResourceList.js',
|
||||||
'js/ResourceLists/CorpusFileList.js',
|
'js/ResourceLists/CorpusFileList.js',
|
||||||
|
'js/ResourceLists/PublicCorpusFileList.js',
|
||||||
'js/ResourceLists/CorpusList.js',
|
'js/ResourceLists/CorpusList.js',
|
||||||
|
'js/ResourceLists/PublicCorpusList.js',
|
||||||
'js/ResourceLists/JobList.js',
|
'js/ResourceLists/JobList.js',
|
||||||
'js/ResourceLists/JobInputList.js',
|
'js/ResourceLists/JobInputList.js',
|
||||||
'js/ResourceLists/JobResultList.js',
|
'js/ResourceLists/JobResultList.js',
|
||||||
|
@ -10,15 +10,7 @@
|
|||||||
<div class="col s12" data-corpus-id="{{ corpus.hashid }}" data-user-id="{{ corpus.user.hashid }}" id="corpus-display">
|
<div class="col s12" data-corpus-id="{{ corpus.hashid }}" data-user-id="{{ corpus.user.hashid }}" id="corpus-display">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col s8 m9 l10">
|
<div class="col s8 m9 l10">
|
||||||
{# <h1 id="title"><span class="corpus-title"></span></h1> #}
|
<h1 id="title"><span class="corpus-title"></span></h1>
|
||||||
<h1 id="title">{{ corpus.title }}</h1>
|
|
||||||
{% if not corpus.user == current_user %}
|
|
||||||
{% if current_user.is_following_corpus(corpus) %}
|
|
||||||
<a class="btn waves-effect waves-light" id="follow-corpus-request"><i class="material-icons left">add</i>Unfollow Corpus</a>
|
|
||||||
{% elif not current_user.is_following_corpus(corpus) %}
|
|
||||||
<a class="btn waves-effect waves-light" id="follow-corpus-request"><i class="material-icons left">add</i>Follow Corpus</a>
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
<div class="col s4 m3 l2 right-align">
|
<div class="col s4 m3 l2 right-align">
|
||||||
<p> </p>
|
<p> </p>
|
||||||
@ -65,7 +57,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-action right-align">
|
<div class="card-action">
|
||||||
|
<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>
|
||||||
<a class="btn disabled export-corpus-trigger waves-effect waves-light" href="{{ url_for('corpora.export_corpus', corpus_id=corpus.id) }}"><i class="material-icons left">import_export</i>Export</a>
|
<a class="btn disabled export-corpus-trigger waves-effect waves-light" href="{{ url_for('corpora.export_corpus', corpus_id=corpus.id) }}"><i class="material-icons left">import_export</i>Export</a>
|
||||||
@ -73,6 +66,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="col s12">
|
<div class="col s12">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
@ -85,25 +79,26 @@
|
|||||||
</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">
|
||||||
<form method="POST">
|
|
||||||
{{ corpus_settings_form.hidden_tag() }}
|
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<span class="card-title" id="files">Corpus settings</span>
|
<div class="action-switch switch center-align" data-action="toggle-is-public">
|
||||||
<br>
|
<span class="share"></span>
|
||||||
<p></p>
|
<label>
|
||||||
{{ wtf.render_field(corpus_settings_form.is_public) }}
|
<input class="corpus-is-public" {% if corpus.is_public %}checked{% endif %} type="checkbox">
|
||||||
<br>
|
<span class="lever"></span>
|
||||||
|
public
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-action right-align">
|
|
||||||
{{ wtf.render_field(corpus_settings_form.submit, material_icon='send') }}
|
<a class="action-button btn waves-effect waves-light" id="generate-share-link-button">Generate Share Link</a>
|
||||||
|
<div id="share-link"></div>
|
||||||
|
<a class="action-button btn-small waves-effect waves-light hide" id="copy-share-link-button">Copy</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
|
||||||
<div class="col s12">
|
<div class="col s12">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
@ -111,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 %}
|
||||||
@ -121,4 +116,25 @@
|
|||||||
<script>
|
<script>
|
||||||
let corpusDisplay = new CorpusDisplay(document.querySelector('#corpus-display'));
|
let corpusDisplay = new CorpusDisplay(document.querySelector('#corpus-display'));
|
||||||
</script>
|
</script>
|
||||||
|
{# <script>
|
||||||
|
let generateShareLinkButton = document.querySelector('#generate-share-link-button');
|
||||||
|
let copyShareLinkButton = document.querySelector('#copy-share-link-button');
|
||||||
|
let shareLink = document.querySelector('#share-link');
|
||||||
|
let linkValue = '{{ url_for('corpora.share_corpus', token=token, _external=True) }}';
|
||||||
|
|
||||||
|
generateShareLinkButton.addEventListener('click', () => {
|
||||||
|
let shareLinkElement = document.createElement('input');
|
||||||
|
shareLinkElement.value = linkValue;
|
||||||
|
shareLinkElement.setAttribute('readonly', '');
|
||||||
|
shareLink.appendChild(shareLinkElement);
|
||||||
|
copyShareLinkButton.classList.remove('hide');
|
||||||
|
});
|
||||||
|
|
||||||
|
copyShareLinkButton.addEventListener('click', () => {
|
||||||
|
let shareLinkElement = document.querySelector('#share-link input');
|
||||||
|
shareLinkElement.select();
|
||||||
|
document.execCommand('copy');
|
||||||
|
app.flash(`Copied!`, 'success');
|
||||||
|
});
|
||||||
|
</script> #}
|
||||||
{% endblock scripts %}
|
{% endblock scripts %}
|
||||||
|
@ -1,86 +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>{{ title }} </h1>
|
|
||||||
<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>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>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock page_content %}
|
|
||||||
|
|
||||||
{% block scripts %}
|
|
||||||
{{ super() }}
|
|
||||||
<script>
|
|
||||||
let corpusFollowingRequest = document.querySelector('#follow-corpus-request');
|
|
||||||
|
|
||||||
{# let followingUserList = new UserList(document.querySelector('.user-list'));
|
|
||||||
followingUserList.add({{ following_users|tojson }}); #}
|
|
||||||
|
|
||||||
corpusFollowingRequest.addEventListener('click', () => {
|
|
||||||
corpusFollowingRequest.innerHTML = '<i class="material-icons left">add</i>Unfollow Corpus';
|
|
||||||
if ("{{ current_user.is_following_corpus(corpus) }}" === "False") {
|
|
||||||
corpusFollowingRequest.lastChild.textContent = 'Unfollow Corpus';
|
|
||||||
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);}
|
|
||||||
if (response.status === 409) {app.flash('Conflict', '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);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
} else {
|
|
||||||
corpusFollowingRequest.innerHTML = '<i class="material-icons left">add</i>Unfollow Corpus';
|
|
||||||
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);}
|
|
||||||
if (response.status === 409) {app.flash('Conflict', '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);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
{% endblock scripts %}
|
|
80
app/templates/corpora/public_corpus.html.j2
Normal file
80
app/templates/corpora/public_corpus.html.j2
Normal 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) }}">Analyze</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 %}
|
@ -42,7 +42,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col s12" id="social">
|
{# <div class="col s12" id="social">
|
||||||
<h3>Social</h3>
|
<h3>Social</h3>
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
@ -58,7 +58,7 @@
|
|||||||
<div class="public-corpus-list no-autoinit"></div>
|
<div class="public-corpus-list no-autoinit"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div> #}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock page_content %}
|
{% endblock page_content %}
|
||||||
@ -116,11 +116,11 @@
|
|||||||
|
|
||||||
{% block scripts %}
|
{% block scripts %}
|
||||||
{{ super() }}
|
{{ super() }}
|
||||||
<script>
|
{# <script>
|
||||||
let userList = new UserList(document.querySelector('.user-list'));
|
let userList = new UserList(document.querySelector('.user-list'));
|
||||||
userList.add({{ users|tojson }});
|
userList.add({{ users|tojson }});
|
||||||
let publicCorpusList = new CorpusList(document.querySelector('.public-corpus-list'));
|
let publicCorpusList = new PublicCorpusList(document.querySelector('.public-corpus-list'));
|
||||||
publicCorpusList.add({{ corpora|tojson }});
|
publicCorpusList.add({{ corpora|tojson }});
|
||||||
</script>
|
</script> #}
|
||||||
{% endblock scripts %}
|
{% endblock scripts %}
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ eventlet
|
|||||||
Flask==2.1.3
|
Flask==2.1.3
|
||||||
Flask-APScheduler
|
Flask-APScheduler
|
||||||
Flask-Assets
|
Flask-Assets
|
||||||
Flask-Hashids==1.0.0
|
Flask-Hashids==1.0.1
|
||||||
Flask-HTTPAuth
|
Flask-HTTPAuth
|
||||||
Flask-Login
|
Flask-Login
|
||||||
Flask-Mail
|
Flask-Mail
|
||||||
@ -24,6 +24,6 @@ pyScss
|
|||||||
python-dotenv
|
python-dotenv
|
||||||
pyyaml
|
pyyaml
|
||||||
redis
|
redis
|
||||||
SQLAlchemy==1.4.46
|
SQLAlchemy==1.4.45
|
||||||
tqdm
|
tqdm
|
||||||
wtforms[email]
|
wtforms[email]
|
||||||
|
Loading…
Reference in New Issue
Block a user