diff --git a/app/corpora/routes.py b/app/corpora/routes.py index 8d2dd45fc52cab4677ae6d74472aed8a4d5b4ee9..55de99f33566b66ad3d11c0fb12269d9d676b31e 100644 --- a/app/corpora/routes.py +++ b/app/corpora/routes.py @@ -1,4 +1,4 @@ -from datetime import datetime +from datetime import datetime, timedelta from flask import ( abort, current_app, @@ -7,7 +7,8 @@ from flask import ( redirect, render_template, request, - send_from_directory + send_from_directory, + url_for ) from flask_login import current_user, login_required from threading import Thread @@ -52,22 +53,20 @@ def disable_corpus_is_public(corpus_id): return '', 204 -# @bp.route('/<hashid:corpus_id>/follow/<token>') -# @login_required -# def follow_corpus(corpus_id, 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>/follow/<token>') +@login_required +def follow_corpus(corpus_id, 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 + return redirect(url_for('.corpus', corpus_id=corpus_id)) @bp.route('/<hashid:corpus_id>/unfollow', methods=['GET', 'POST']) @@ -157,27 +156,16 @@ def create_corpus(): ) -@bp.route('/<hashid:corpus_id>', methods=['GET', 'POST']) +@bp.route('/<hashid:corpus_id>') @login_required def corpus(corpus_id): corpus = Corpus.query.get_or_404(corpus_id) + exp_date = (datetime.utcnow() + timedelta(days=7)).strftime('%b %d, %Y') 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( 'corpora/corpus.html.j2', corpus=corpus, - # token=token, + exp_date=exp_date, title='Corpus' ) if current_user.is_following_corpus(corpus) or corpus.is_public: @@ -190,6 +178,28 @@ def corpus(corpus_id): ) abort(403) +@bp.route('/<hashid:corpus_id>/generate-corpus-share-link', methods=['GET', 'POST']) +@login_required +def generate_corpus_share_link(corpus_id): + data = request.get_json('data') + permission = data['permission'] + expiration = data['expiration'] + corpus = Corpus.query.get_or_404(corpus_id) + now = datetime.utcnow() + payload = { + 'exp': expiration, + 'iat': now, + 'iss': current_app.config['SERVER_NAME'], + 'sub': permission + } + token = jwt.encode( + payload, + current_app.config['SECRET_KEY'], + algorithm='HS256' + ) + link = url_for('corpora.follow_corpus', corpus_id=corpus_id, token=token, _external=True) + return link + @bp.route('/<hashid:corpus_id>', methods=['DELETE']) @login_required diff --git a/app/static/js/Utils.js b/app/static/js/Utils.js index e2ac84abe9544e4f59e1c8595c1cf00928fd73bb..b3da4ca1a87665fa81050270f8bcf8f0579db44e 100644 --- a/app/static/js/Utils.js +++ b/app/static/js/Utils.js @@ -751,4 +751,34 @@ class Utils { ); }); } + + static generateCorpusShareLinkRequest(corpusId, permission, expiration) { + return new Promise((resolve, reject) => { + const data = {permission: permission, expiration: expiration}; + fetch(`/corpora/${corpusId}/generate-corpus-share-link`, {method: 'POST', headers: {Accept: 'text/plain'}, body: JSON.stringify(data)}) + .then( + (response) => { + if (!response.ok) { + app.flash(`Something went wrong: ${response.status} ${response.statusText}`, 'error'); + reject(response); + return; + } + return response.text(); + }, + (response) => { + // Something went wrong during the HTTP request + app.flash('Something went wrong', 'error'); + reject(response); + } + ) + .then( + (corpusShareLink) => {resolve(corpusShareLink);}, + (error) => { + // Something went wrong during ReadableStream processing + app.flash('Something went wrong', 'error'); + reject(error); + } + ); + }); + } } diff --git a/app/templates/corpora/corpus.html.j2 b/app/templates/corpora/corpus.html.j2 index 34228347187cc93a25d29c617e3d7a7566ec2418..c84d6c0eab36c1a1aa3227e046fb2fb19d6e8aab 100644 --- a/app/templates/corpora/corpus.html.j2 +++ b/app/templates/corpora/corpus.html.j2 @@ -80,10 +80,13 @@ </div> </div> - {# <div class="col s12"> + <div class="col s12"> <div class="card"> <div class="card-content"> - <div class="action-switch switch center-align" data-action="toggle-is-public"> + <span class="card-title">Share your Corpus</span> + <br> + <p></p> + <div class="action-switch switch" data-action="toggle-is-public"> <span class="share"></span> <label> <input class="corpus-is-public" {% if corpus.is_public %}checked{% endif %} type="checkbox"> @@ -91,14 +94,38 @@ public </label> </div> - - <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> + <br> + <p></p> + <div class="row"> + <div class="col s4"> + <div class="input-field"> + <select id="permission-select"> + <option value="view" selected>View</option> + <option value="contribute">Contribute</option> + <option value="administrate">Administrate</option> + </select> + <label>Permission</label> + </div> + </div> + </div> + <div class="row"> + <div class="col s4"> + <div class="input-field"> + <input type="text" class="datepicker" value="{{exp_date}}" id="expiration"> + <label for="expiration-date">Expiration date</label> + </div> + </div> + </div> + <div class="row"> + <div class="col s12"> + <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> </div> - <div class="col s12"> <div class="card"> <div class="card-content"> @@ -106,7 +133,7 @@ <div class="user-list no-autoinit"></div> </div> </div> - </div> #} + </div> </div> </div> {% endblock page_content %} @@ -115,19 +142,23 @@ {{ super() }} <script> let corpusDisplay = new CorpusDisplay(document.querySelector('#corpus-display')); -</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) }}'; + let permissionSelect = document.querySelector('#permission-select'); + let expirationDate = document.querySelector('#expiration'); + generateShareLinkButton.addEventListener('click', () => { - let shareLinkElement = document.createElement('input'); - shareLinkElement.value = linkValue; - shareLinkElement.setAttribute('readonly', ''); - shareLink.appendChild(shareLinkElement); - copyShareLinkButton.classList.remove('hide'); + Utils.generateCorpusShareLinkRequest('{{ corpus.hashid }}', permissionSelect.value, expirationDate.value) + .then((corpusShareLink) => { + console.log(corpusShareLink); + let shareLinkElement = document.createElement('input'); + shareLinkElement.value = corpusShareLink; + shareLinkElement.setAttribute('readonly', ''); + shareLink.appendChild(shareLinkElement); + copyShareLinkButton.classList.remove('hide'); + }); }); copyShareLinkButton.addEventListener('click', () => { @@ -136,5 +167,5 @@ document.execCommand('copy'); app.flash(`Copied!`, 'success'); }); -</script> #} +</script> {% endblock scripts %}