diff --git a/app/profile/routes.py b/app/profile/routes.py index 74d742bee86204f67d58ca53a14472476401355a..4702dcb7ca5d573cfec733bc4c7a2b037d806e9b 100644 --- a/app/profile/routes.py +++ b/app/profile/routes.py @@ -10,7 +10,7 @@ from flask import ( from flask_login import current_user, login_required import os from app import db -from app.models import Avatar +from app.models import Avatar, User from . import bp from .forms import ( EditProfileSettingsForm @@ -22,14 +22,15 @@ def before_request(): pass -@bp.route('') -def profile(): +@bp.route('/<hashid:user_id>') +def profile(user_id): + user = User.query.get_or_404(user_id) return render_template('profile/profile_page.html.j2', - user=current_user) + user=user) -@bp.route('/avatars/<hashid:avatar_id>') -def avatar_download(avatar_id): - avatar_file = Avatar.query.get_or_404(avatar_id) +@bp.route('/<hashid:user_id>/avatars/<hashid:avatar_id>') +def avatar_download(user_id, avatar_id): + avatar_file = Avatar.query.filter_by(user_id = user_id, id = avatar_id).first_or_404() if not (avatar_file and avatar_file.filename): abort(404) return send_from_directory( @@ -40,8 +41,9 @@ def avatar_download(avatar_id): mimetype=avatar_file.mimetype ) -@bp.route('/edit-profile', methods=['GET', 'POST']) -def edit_profile(): +@bp.route('/<hashid:user_id>/edit-profile', methods=['GET', 'POST']) +def edit_profile(user_id): + user = User.query.get_or_404(user_id) edit_profile_settings_form = EditProfileSettingsForm( current_user, data=current_user.to_json_serializeable(), @@ -63,7 +65,8 @@ def edit_profile(): db.session.commit() message = Markup(f'Profile settings updated') flash(message, 'success') - return redirect(url_for('.profile')) + return redirect(url_for('.profile', user_id=user.id)) return render_template('profile/edit_profile.html.j2', edit_profile_settings_form=edit_profile_settings_form, + user=user, title='Edit Profile') diff --git a/app/static/js/RessourceLists/PublicCorporaList.js b/app/static/js/RessourceLists/PublicCorporaList.js new file mode 100644 index 0000000000000000000000000000000000000000..2171396eae562ebecc4aa4de8655560592ed7565 --- /dev/null +++ b/app/static/js/RessourceLists/PublicCorporaList.js @@ -0,0 +1,70 @@ +class PublicCorporaList extends RessourceList { + static instances = []; + + static getInstance(elem) { + return PublicCorporaList.instances.find((instance) => { + return instance.listjs.list === elem; + }); + } + + static autoInit() { + for (let publicCorporaListElement of document.querySelectorAll('.public-corpora-list:not(.no-autoinit)')) { + new PublicCorporaList(publicCorporaListElement); + } + } + + static options = { + initialHtmlGenerator: (id) => { + return ` + <div class="input-field"> + <i class="material-icons prefix">search</i> + <input id="${id}-search" class="search" type="search"></input> + <label for="${id}-search">Search corpus</label> + </div> + <table> + <thead> + <tr> + <th></th> + <th>Title</th> + <th>Description</th> + <th></th> + </tr> + </thead> + <tbody class="list"></tbody> + </table> + <ul class="pagination"></ul> + `.trim(); + }, + item: ` + <tr class="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></td> + <td><i class="description"></i></td> + </tr> + `.trim(), + ressourceMapper: (corpus) => { + return { + 'id': corpus.id, + 'creation-date': corpus.creation_date, + 'description': corpus.description, + 'title': corpus.title + }; + }, + sortArgs: ['creation-date', {order: 'desc'}], + valueNames: [ + {data: ['id']}, + {data: ['creation-date']}, + 'description', + 'title' + ] + }; + + constructor(listElement, options = {}) { + super(listElement, {...PublicCorporaList.options, ...options}); + PublicCorporaList.instances.push(this); + } + + init(user) { + this._init(user.corpora.is_public); + } +} diff --git a/app/static/js/RessourceLists/RessourceList.js b/app/static/js/RessourceLists/RessourceList.js index 871a1e2f89cb6286d860ce559da81fbba43453a5..5af7a2319627d24d1e408d008e44c52d6c485d23 100644 --- a/app/static/js/RessourceLists/RessourceList.js +++ b/app/static/js/RessourceLists/RessourceList.js @@ -10,6 +10,7 @@ class RessourceList { JobList.autoInit(); JobInputList.autoInit(); JobResultList.autoInit(); + PublicCorporaList.autoInit(); SpaCyNLPPipelineModelList.autoInit(); TesseractOCRPipelineModelList.autoInit(); UserList.autoInit(); diff --git a/app/templates/_navbar.html.j2 b/app/templates/_navbar.html.j2 index e2d4db6452116377e4e007a86e0674ea63373b7a..d90118b8548cb41d0fe72ab0681400df7f611b5c 100644 --- a/app/templates/_navbar.html.j2 +++ b/app/templates/_navbar.html.j2 @@ -29,7 +29,8 @@ <ul class="dropdown-content" id="nav-more-dropdown"> <li><a href="{{ url_for('main.user_manual') }}"><i class="material-icons left">help</i>Manual</a></li> {% if current_user.is_authenticated %} - <li><a href="{{ url_for('settings.settings') }}"><i class="material-icons left">settings</i>Settings</a></li> + <li><a href="{{ url_for('settings.settings') }}"><i class="material-icons left">settings</i>General settings</a></li> + <li><a href="{{ url_for('profile.edit_profile', user_id=current_user.id) }}"><i class="material-icons left">contact_page</i>Profile settings</a></li> <li class="divider" tabindex="-1"></li> <li><a href="{{ url_for('auth.logout') }}">Log out</a></li> {% else %} diff --git a/app/templates/_scripts.html.j2 b/app/templates/_scripts.html.j2 index 7cc8a8f80de6738d86e3c86585835fe2a578bf73..8ff90c330be20f1b379d824765a3b8cfb7f6f279 100644 --- a/app/templates/_scripts.html.j2 +++ b/app/templates/_scripts.html.j2 @@ -24,6 +24,7 @@ 'js/RessourceLists/JobList.js', 'js/RessourceLists/JobInputList.js', 'js/RessourceLists/JobResultList.js', + 'js/RessourceLists/PublicCorporaList.js', 'js/RessourceLists/SpacyNLPPipelineModelList.js', 'js/RessourceLists/TesseractOCRPipelineModelList.js', 'js/RessourceLists/UserList.js' diff --git a/app/templates/_sidenav.html.j2 b/app/templates/_sidenav.html.j2 index f87f701eef5280b732ce9bf31be3cbf0ebb9a314..1aff7f8950e34d65b6e4cd3d3d89fce00b637f16 100644 --- a/app/templates/_sidenav.html.j2 +++ b/app/templates/_sidenav.html.j2 @@ -4,7 +4,7 @@ <div class="background primary-color"></div> <div class="row"> <div class="col s2"> - <a href="{{ url_for('profile.profile') }}"> + <a href="{{ url_for('profile.profile', user_id=current_user.id) }}"> <i class="material-icons" style="color:white; font-size:3em; margin-top: 25px; margin-left:-15px;">account_circle</i></div> </a> <div class="col s10"> @@ -14,12 +14,13 @@ </div> </div> </li> - <li><a href="{{ url_for('main.index') }}">nopaque</a></li> + {# <li><a href="{{ url_for('main.index') }}">nopaque</a></li> #} <li><a href="{{ url_for('main.news') }}"><i class="material-icons left">email</i>News</a></li> <li><a href="{{ url_for('main.user_manual') }}"><i class="material-icons">help</i>Manual</a></li> <li><a href="{{ url_for('main.dashboard') }}"><i class="material-icons">dashboard</i>Dashboard</a></li> <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('main.dashboard', _anchor='social') }}" style="padding-left: 47px;"><i class="material-icons">groups</i>Social</a></li> <li><a href="{{ url_for('contributions.contributions') }}"><i class="material-icons">new_label</i>Contribute</a></li> <li><div class="divider"></div></li> <li><a class="subheader">Processes & Services</a></li> diff --git a/app/templates/main/dashboard.html.j2 b/app/templates/main/dashboard.html.j2 index ec03609d0c41a56020d0c0a134793512a8cfd255..e0354ea624eff3230e0a2d392fb2d6a93ca4ba45 100644 --- a/app/templates/main/dashboard.html.j2 +++ b/app/templates/main/dashboard.html.j2 @@ -42,6 +42,25 @@ </div> </div> </div> + <div class="col s12" id="social"> + <h3>Social</h3> + <div class="col s6"> + <div class="card"> + <div class="card-content"> + <span class="card-title">Other users and groups</span> + <p>Find other users and follow them to see their corpora and groups.</p> + </div> + </div> + </div> + <div class="col s6"> + <div class="card"> + <div class="card-content"> + <span class="card-title">Public corpora</span> + <p>Find public corpora</p> + </div> + </div> + </div> + </div> </div> </div> {% endblock page_content %} diff --git a/app/templates/profile/edit_profile.html.j2 b/app/templates/profile/edit_profile.html.j2 index e1a49ef48e96bc427a815c75c56692d9102bb3c0..1f4bd0e7d032c3ae817d2470e1949f28d0c25c87 100644 --- a/app/templates/profile/edit_profile.html.j2 +++ b/app/templates/profile/edit_profile.html.j2 @@ -14,16 +14,24 @@ <div class="card-content"> {{ edit_profile_settings_form.hidden_tag() }} <div class="row"> - <div class="col s1"></div> - <div class="col s3"> - {% if current_user.avatar %} - <img src="{{ url_for('profile.avatar_download', avatar_id=current_user.avatar.id) }}" alt="user-image" class="circle responsive-img"> - {% else %} - <img src="{{ url_for('static', filename='images/user_avatar.png') }}" alt="user-image" class="circle responsive-img"> - {% endif %} - {{wtf.render_field(edit_profile_settings_form.avatar, accept='image/jpeg, image/png, image/gif', class='file-path validate')}} + <div class="col s5"> + <div class="row"> + <div class="col s1"></div> + <div class="col s10"> + {% if current_user.avatar %} + <img src="{{ url_for('profile.avatar_download', user_id=user.id, avatar_id=current_user.avatar.id) }}" alt="user-image" class="circle responsive-img"> + {% else %} + <img src="{{ url_for('static', filename='images/user_avatar.png') }}" alt="user-image" class="circle responsive-img"> + {% endif %} + </div> + <div class="col s1"></div> + </div> + <div class="row"> + <div class="col s12"> + {{wtf.render_field(edit_profile_settings_form.avatar, accept='image/jpeg, image/png, image/gif', placeholder="Choose an image file")}} + </div> + </div> </div> - <div class="col s1"></div> <div class="col s7"> {{ wtf.render_field(edit_profile_settings_form.username, material_icon='person') }} {{ wtf.render_field(edit_profile_settings_form.email, material_icon='email') }} diff --git a/app/templates/profile/profile_page.html.j2 b/app/templates/profile/profile_page.html.j2 index 2845aedd6ffb79b7086201326c3fba838ea0ec85..dbcd78cad576d67d08c65a04203131efbea64bdc 100644 --- a/app/templates/profile/profile_page.html.j2 +++ b/app/templates/profile/profile_page.html.j2 @@ -11,7 +11,7 @@ <div class="col s1"></div> <div class="col s4"> {% if user.avatar %} - <img src="{{ url_for('profile.avatar_download', avatar_id=user.avatar.id) }}" alt="user-image" class="circle responsive-img"> + <img src="{{ url_for('profile.avatar_download', user_id=user.id, avatar_id=user.avatar.id) }}" alt="user-image" class="circle responsive-img"> {% else %} <img src="{{ url_for('static', filename='images/user_avatar.png') }}" alt="user-image" class="circle responsive-img"> {% endif %} @@ -67,12 +67,31 @@ <p><i>Member since: {{ user.member_since.strftime('%Y-%m-%d') }}</i></p> <p></p> <br> - <a class="waves-effect waves-light btn-small" href="{{ url_for('profile.edit_profile') }}">Edit profile</a> + {% if current_user.is_authenticated and current_user.id == user.id %} + <a class="waves-effect waves-light btn-small" href="{{ url_for('profile.edit_profile', user_id=user.id) }}">Edit profile</a> + {% endif %} </div> </div> </div> </div> </div> </div> + <div class="row"> + <div class="col s6"> + <div class="card"> + <div class="card-content"> + <h4>Groups</h4> + </div> + </div> + </div> + <div class="col s6"> + <div class="card"> + <div class="card-content"> + <h4>Public corpora</h4> + <div class="public-corpora-list" data-user-id="{{ user.hashid }}"></div> + </div> + </div> + </div> + </div> </div> {% endblock page_content %}