mirror of
https://gitlab.ub.uni-bielefeld.de/sfb1288inf/nopaque.git
synced 2024-12-24 02:24:20 +00:00
social-area page and profile page update
This commit is contained in:
parent
ec6d0a6477
commit
b1586b3679
@ -3,27 +3,24 @@ from flask_login import current_user
|
||||
from functools import wraps
|
||||
from app.models import Corpus, CorpusFollowerAssociation
|
||||
|
||||
def corpus_follower_permission_required(permissions):
|
||||
def corpus_follower_permission_required(*permissions):
|
||||
def decorator(f):
|
||||
@wraps(f)
|
||||
def decorated_function(*args, **kwargs):
|
||||
corpus_id = kwargs.get('corpus_id')
|
||||
corpus = Corpus.query.get_or_404(corpus_id)
|
||||
if current_user == corpus.user or current_user.is_administrator():
|
||||
print('user or admin')
|
||||
return f(*args, **kwargs)
|
||||
if not current_user.is_following_corpus(corpus):
|
||||
print('not following corpus')
|
||||
abort(403)
|
||||
corpus_follower_association = CorpusFollowerAssociation.query.filter_by(corpus_id=corpus_id, follower_id=current_user.id).first_or_404()
|
||||
for permission in permissions:
|
||||
if not corpus_follower_association.role.has_permission(permission):
|
||||
abort(403)
|
||||
if not all([corpus_follower_association.role.has_permission(p) for p in permissions]):
|
||||
abort(403)
|
||||
return f(*args, **kwargs)
|
||||
return decorated_function
|
||||
return decorator
|
||||
|
||||
def owner_or_admin_required():
|
||||
def corpus_owner_or_admin_required():
|
||||
def decorator(f):
|
||||
@wraps(f)
|
||||
def decorated_function(*args, **kwargs):
|
||||
|
@ -15,7 +15,7 @@ from flask_login import current_user, login_required
|
||||
from threading import Thread
|
||||
import jwt
|
||||
import os
|
||||
from .decorators import corpus_follower_permission_required, owner_or_admin_required
|
||||
from .decorators import corpus_follower_permission_required, corpus_owner_or_admin_required
|
||||
from app import db, hashids
|
||||
from app.models import (
|
||||
Corpus,
|
||||
@ -33,12 +33,6 @@ from .forms import (
|
||||
UpdateCorpusFileForm
|
||||
)
|
||||
|
||||
@bp.route('/<hashid:corpus_id>/test')
|
||||
@login_required
|
||||
@corpus_follower_permission_required(['VIEW', 'ADD_CORPUS_FILE'])
|
||||
def test(corpus_id):
|
||||
return 'ok'
|
||||
|
||||
@bp.route('/fake-add')
|
||||
@login_required
|
||||
def fake_add():
|
||||
@ -51,7 +45,7 @@ def fake_add():
|
||||
|
||||
@bp.route('/<hashid:corpus_id>/is_public/enable', methods=['POST'])
|
||||
@login_required
|
||||
@owner_or_admin_required()
|
||||
@corpus_owner_or_admin_required()
|
||||
def enable_corpus_is_public(corpus_id):
|
||||
corpus = Corpus.query.get_or_404(corpus_id)
|
||||
corpus.is_public = True
|
||||
@ -61,7 +55,7 @@ def enable_corpus_is_public(corpus_id):
|
||||
|
||||
@bp.route('/<hashid:corpus_id>/is_public/disable', methods=['POST'])
|
||||
@login_required
|
||||
@owner_or_admin_required()
|
||||
@corpus_owner_or_admin_required()
|
||||
def disable_corpus_is_public(corpus_id):
|
||||
corpus = Corpus.query.get_or_404(corpus_id)
|
||||
corpus.is_public = False
|
||||
@ -111,7 +105,7 @@ def current_user_unfollow_corpus(corpus_id):
|
||||
|
||||
|
||||
@bp.route('/<hashid:corpus_id>/followers/<hashid:follower_id>/role', methods=['POST'])
|
||||
@corpus_follower_permission_required(['REMOVE_FOLLOWER', 'UPDATE_FOLLOWER'])
|
||||
@corpus_follower_permission_required('REMOVE_FOLLOWER', 'UPDATE_FOLLOWER')
|
||||
def add_permission(corpus_id, follower_id):
|
||||
corpus_follower_association = CorpusFollowerAssociation.query.filter_by(corpus_id=corpus_id, follower_id=follower_id).first_or_404()
|
||||
if not (corpus_follower_association.corpus.user == current_user or current_user.is_administrator()):
|
||||
@ -206,6 +200,7 @@ def generate_corpus_share_link(corpus_id):
|
||||
|
||||
@bp.route('/<hashid:corpus_id>', methods=['DELETE'])
|
||||
@login_required
|
||||
@corpus_owner_or_admin_required()
|
||||
def delete_corpus(corpus_id):
|
||||
def _delete_corpus(app, corpus_id):
|
||||
with app.app_context():
|
||||
@ -214,8 +209,6 @@ def delete_corpus(corpus_id):
|
||||
db.session.commit()
|
||||
|
||||
corpus = Corpus.query.get_or_404(corpus_id)
|
||||
if not (corpus.user == current_user or current_user.is_administrator()):
|
||||
abort(403)
|
||||
thread = Thread(
|
||||
target=_delete_corpus,
|
||||
args=(current_app._get_current_object(), corpus_id)
|
||||
|
@ -27,20 +27,7 @@ def faq():
|
||||
@bp.route('/dashboard')
|
||||
@login_required
|
||||
def dashboard():
|
||||
# users = [
|
||||
# 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()
|
||||
# ]
|
||||
# corpora = [
|
||||
# c.to_json_serializeable() for c
|
||||
# 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')
|
||||
|
||||
|
||||
@bp.route('/dashboard2')
|
||||
@ -67,3 +54,20 @@ def privacy_policy():
|
||||
@bp.route('/terms_of_use')
|
||||
def terms_of_use():
|
||||
return render_template('main/terms_of_use.html.j2', title='Terms of Use')
|
||||
|
||||
@bp.route('/social-area')
|
||||
def social_area():
|
||||
users = [
|
||||
u.to_json_serializeable(relationships=True, filter_by_privacy_settings=True,) for u
|
||||
in User.query.filter(User.is_public == True, User.id != current_user.id).all()
|
||||
]
|
||||
corpora = [
|
||||
c.to_json_serializeable() for c
|
||||
in Corpus.query.filter(Corpus.is_public == True, Corpus.user != current_user).all()
|
||||
]
|
||||
return render_template(
|
||||
'main/social_area.html.j2',
|
||||
users=users,
|
||||
corpora=corpora,
|
||||
title='Social Area'
|
||||
)
|
||||
|
14
app/static/js/ResourceLists/FollowedCorpusList.js
Normal file
14
app/static/js/ResourceLists/FollowedCorpusList.js
Normal file
@ -0,0 +1,14 @@
|
||||
class FollowedCorpusList 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();
|
||||
}
|
||||
}
|
@ -13,14 +13,14 @@ class UserList extends ResourceList {
|
||||
get item() {
|
||||
return `
|
||||
<tr class="list-item clickable hoverable">
|
||||
<td><img alt="user-image" class="circle responsive-img avatar" style="width:50%"></td>
|
||||
<td><img alt="user-image" class="circle responsive-img avatar" style="width:25%"></td>
|
||||
<td><b><span class="username"></span><b></td>
|
||||
<td><span class="full-name"></span></td>
|
||||
<td><span class="location"></span></td>
|
||||
<td><span class="organization"></span></td>
|
||||
<td><span class="corpora-online"></span></td>
|
||||
<td class="right-align">
|
||||
<a class="list-action-trigger btn-floating waves-effect waves-light" data-list-action="view"><i class="material-icons">send</i></a>
|
||||
<a class="list-action-trigger btn-floating waves-effect waves-light" data-list-action="view" style="background-color:#D9A36D"><i class="material-icons">send</i></a>
|
||||
</td>
|
||||
</tr>
|
||||
`.trim();
|
||||
@ -77,7 +77,7 @@ class UserList extends ResourceList {
|
||||
'full-name': user.full_name ? user.full_name : '',
|
||||
'location': user.location ? user.location : '',
|
||||
'organization': user.organization ? user.organization : '',
|
||||
'corpora-online': '-'
|
||||
'corpora-online': Object.values(user.corpora).filter((corpus) => corpus.is_public).length
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -22,6 +22,7 @@
|
||||
'js/ResourceLists/CorpusFileList.js',
|
||||
'js/ResourceLists/PublicCorpusFileList.js',
|
||||
'js/ResourceLists/CorpusList.js',
|
||||
'js/ResourceLists/FollowedCorpusList.js',
|
||||
'js/ResourceLists/PublicCorpusList.js',
|
||||
'js/ResourceLists/JobList.js',
|
||||
'js/ResourceLists/JobInputList.js',
|
||||
|
@ -6,11 +6,10 @@
|
||||
<div class="col s4">
|
||||
<a href="{{ url_for('users.user', user_id=current_user.id) }}">
|
||||
{% if current_user.avatar %}
|
||||
<img src="{{ url_for('users.profile_avatar', user_id=current_user.id) }}" alt="user-image" class="circle responsive-img" style="height:80%; margin-top: 20px; margin-left:-15px;">
|
||||
<img src="{{ url_for('users.profile_avatar', user_id=current_user.id) }}" alt="user-image" class="circle responsive-img" style="height:80%; margin-top: 13px; margin-left:-15px;">
|
||||
{% else %}
|
||||
<img src="{{ url_for('static', filename='images/user_avatar.png') }}" alt="user-image" class="circle responsive-img" style="height:80%; margin-top: 20px; margin-left:-15px;">
|
||||
<img src="{{ url_for('static', filename='images/user_avatar.png') }}" alt="user-image" class="circle responsive-img" style="height:80%; margin-top: 13px; margin-left:-15px;">
|
||||
{% endif %}
|
||||
{# <i class="material-icons" style="color:white; font-size:3em; margin-top: 25px; margin-left:-15px;">account_circle</i></div> #}
|
||||
</a>
|
||||
</div>
|
||||
<div class="col s8">
|
||||
@ -27,6 +26,7 @@
|
||||
<li><a href="{{ url_for('main.dashboard', _anchor='corpora') }}" style="padding-left: 47px;"><i class="nopaque-icons">I</i>My Corpora</a></li>
|
||||
<li><a href="{{ url_for('main.dashboard', _anchor='jobs') }}" style="padding-left: 47px;"><i class="nopaque-icons">J</i>My Jobs</a></li>
|
||||
<li><a href="{{ url_for('contributions.contributions') }}"><i class="material-icons">new_label</i>Contribute</a></li>
|
||||
<li><a href="{{ url_for('main.social_area') }}"><i class="material-icons">group</i>Social Area</a></li>
|
||||
<li><div class="divider"></div></li>
|
||||
<li><a class="subheader">Processes & Services</a></li>
|
||||
<li class="service-color service-color-border border-darken" data-service="file-setup-pipeline" style="border-left: 10px solid; margin-top: 5px;"><a href="{{ url_for('services.file_setup_pipeline') }}"><i class="nopaque-icons service-icons" data-service="file-setup-pipeline"></i>File setup</a></li>
|
||||
|
70
app/templates/main/social_area.html.j2
Normal file
70
app/templates/main/social_area.html.j2
Normal file
@ -0,0 +1,70 @@
|
||||
{% extends "base.html.j2" %}
|
||||
{% import "materialize/wtf.html.j2" as wtf %}
|
||||
|
||||
{% block main_attribs %} style="background-color:#d8c9ba86" {% endblock main_attribs %}
|
||||
|
||||
{% block page_content %}
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col s12">
|
||||
<h1 id="title">{{ title }}</h1>
|
||||
</div>
|
||||
|
||||
<div class="col s12 m3 push-m9">
|
||||
<div class="center-align">
|
||||
<p class="hide-on-small-only"> </p>
|
||||
<p class="hide-on-small-only"> </p>
|
||||
<a class="btn-floating btn-large btn-scale-x2 waves-effect waves-light" style="background-color:#D9A36D">
|
||||
<i class="left material-icons">group</i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col s12 m9 pull-m3">
|
||||
<div class="card" style="border-top: 10px solid #D9A36D;">
|
||||
<div class="card-content">
|
||||
<div class="row">
|
||||
<div class="col s12">
|
||||
<div class="card-panel z-depth-0">
|
||||
<span class="card-title"><i class="left material-icons">layers</i>Your social area</span>
|
||||
<p>Here you can network with your team and other users. You can find corpora that are public and request them or just see what other users are working on.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col s12">
|
||||
<h3>Other Users</h3>
|
||||
<p>Find other users and see what corpora they have made public.</p>
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<div class="user-list no-autoinit"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col s12">
|
||||
<h3>Public Corpora</h3>
|
||||
<p>Find public corpora.</p>
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<span class="card-title">Public Corpora</span>
|
||||
<div class="public-corpus-list no-autoinit"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock page_content %}
|
||||
|
||||
{% block scripts %}
|
||||
{{ super() }}
|
||||
<script>
|
||||
let userList = new UserList(document.querySelector('.user-list'));
|
||||
userList.add({{ users|tojson }});
|
||||
let publicCorpusList = new PublicCorpusList(document.querySelector('.public-corpus-list'));
|
||||
publicCorpusList.add({{ corpora|tojson }});
|
||||
</script>
|
||||
{% endblock scripts %}
|
@ -26,7 +26,7 @@
|
||||
</div>
|
||||
<div class="col 12">
|
||||
{% if user.show_last_seen %}
|
||||
<div class="chip">Last seen: {{ user.last_seen }}</div>
|
||||
<div class="chip">Last seen: {{ last_seen }}</div>
|
||||
{% endif %}
|
||||
{% if user.location %}
|
||||
<p><span class="material-icons" style="margin-right:20px; margin-top:20px;">location_on</span><i>{{ user.location }}</i></p>
|
||||
@ -76,7 +76,7 @@
|
||||
</table>
|
||||
<br>
|
||||
{% if user.show_member_since %}
|
||||
<p><i>Member since: {{ user.member_since }}</i></p>
|
||||
<p><i>Member since: {{ member_since }}</i></p>
|
||||
{% endif %}
|
||||
<p></p>
|
||||
<br>
|
||||
@ -93,7 +93,8 @@
|
||||
<div class="col s6">
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<h4>Groups</h4>
|
||||
<h4>Followed corpora</h4>
|
||||
<div class="followed-corpus-list no-autoinit"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -101,7 +102,7 @@
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<h4>Public corpora</h4>
|
||||
<div class="public-corpora-list" data-user-id="{{ user.hashid }}"></div>
|
||||
<div class="public-corpus-list no-autoinit"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -127,6 +128,11 @@ if ("{{ user.id }}" == "{{ current_user.hashid }}") {
|
||||
} else {
|
||||
publicInformationBadge.remove();
|
||||
}
|
||||
|
||||
let followedCorpusList = new FollowedCorpusList(document.querySelector('.followed-corpus-list'));
|
||||
followedCorpusList.add({{ followed_corpora|tojson }});
|
||||
let publicCorpusList = new PublicCorpusList(document.querySelector('.public-corpus-list'));
|
||||
publicCorpusList.add({{ own_public_corpora|tojson }});
|
||||
</script>
|
||||
{% endblock scripts %}
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
from datetime import datetime
|
||||
from flask import (
|
||||
abort,
|
||||
current_app,
|
||||
@ -12,7 +13,7 @@ from flask_login import current_user, login_required
|
||||
from threading import Thread
|
||||
import os
|
||||
from app import db
|
||||
from app.models import Avatar, ProfilePrivacySettings, User
|
||||
from app.models import Avatar, Corpus, ProfilePrivacySettings, User
|
||||
from . import bp
|
||||
from .forms import (
|
||||
EditPrivacySettingsForm,
|
||||
@ -29,10 +30,23 @@ def before_request():
|
||||
@login_required
|
||||
def user(user_id):
|
||||
user = User.query.get_or_404(user_id)
|
||||
last_seen = user.last_seen.strftime('%Y-%m-%d %H:%M')
|
||||
member_since = user.member_since.strftime('%Y-%m-%d')
|
||||
followed_corpora = [
|
||||
c.to_json_serializeable() for c in user.followed_corpora
|
||||
]
|
||||
own_public_corpora = [
|
||||
c.to_json_serializeable() for c
|
||||
in Corpus.query.filter_by(is_public = True, user = user).all()
|
||||
]
|
||||
if not user.is_public and user != current_user:
|
||||
abort(403)
|
||||
return render_template(
|
||||
'users/profile.html.j2',
|
||||
'users/profile.html.j2',
|
||||
followed_corpora=followed_corpora,
|
||||
last_seen=last_seen,
|
||||
member_since=member_since,
|
||||
own_public_corpora=own_public_corpora,
|
||||
user=user.to_json_serializeable(),
|
||||
user_id=user_id
|
||||
)
|
||||
@ -56,18 +70,6 @@ def delete_user(user_id):
|
||||
thread.start()
|
||||
return {}, 202
|
||||
|
||||
@bp.route('/<hashid:user_id>')
|
||||
def profile(user_id):
|
||||
user = User.query.get_or_404(user_id)
|
||||
if not user.is_public and user != current_user:
|
||||
abort(403)
|
||||
return render_template(
|
||||
'users/profile.html.j2',
|
||||
user=user.to_json_serializeable(),
|
||||
user_id=user_id
|
||||
)
|
||||
|
||||
|
||||
@bp.route('/<hashid:user_id>/avatar')
|
||||
def profile_avatar(user_id):
|
||||
user = User.query.get_or_404(user_id)
|
||||
@ -91,7 +93,6 @@ def delete_profile_avatar(user_id):
|
||||
avatar = Avatar.query.get(avatar_id)
|
||||
avatar.delete()
|
||||
db.session.commit()
|
||||
|
||||
user = User.query.get_or_404(user_id)
|
||||
if user.avatar is None:
|
||||
abort(404)
|
||||
|
Loading…
Reference in New Issue
Block a user