diff --git a/app/main/routes.py b/app/main/routes.py index 7e42d60b62b8afdf4dc26f73aa84bb8cf7922a40..fd01e5a6d7abbf846147a776e5a38b24f0770dd9 100644 --- a/app/main/routes.py +++ b/app/main/routes.py @@ -1,5 +1,5 @@ from flask import flash, redirect, render_template, url_for -from flask_login import login_required, login_user +from flask_login import current_user, login_required, login_user from app.auth.forms import LoginForm from app.models import User from . import bp @@ -27,7 +27,11 @@ def faq(): @bp.route('/dashboard') @login_required def dashboard(): - return render_template('main/dashboard.html.j2', title='Dashboard') + users = [ + u.to_json_serializeable(filter_by_privacy_settings=True, include_avatar_relationship=True) for u + in User.query.filter(User.is_public == True, User.id != current_user.id).all() + ] + return render_template('main/dashboard.html.j2', title='Dashboard', users=users) @bp.route('/dashboard2') diff --git a/app/models.py b/app/models.py index aa5b2faa720001837b130f2c89162813808df8a3..afa0e40c6ba5de14758965298c3c970646557e4c 100644 --- a/app/models.py +++ b/app/models.py @@ -256,8 +256,7 @@ class Avatar(HashidMixin, FileMixin, db.Model): # Primary key id = db.Column(db.Integer, primary_key=True) # Foreign keys - user_id = db.Column(db.Integer, db.ForeignKey('users.id')) - # Backrefs: user: User + user_id = db.Column(db.Integer, db.ForeignKey('users.id'), unique=True) @property def path(self): @@ -270,7 +269,12 @@ class Avatar(HashidMixin, FileMixin, db.Model): current_app.logger.error(e) db.session.delete(self) - + def to_json_serializeable(self, backrefs=False, relationships=False): + json_serializeable = { + 'id': self.id + } + return json_serializeable + class User(HashidMixin, UserMixin, db.Model): __tablename__ = 'users' # Primary key @@ -536,7 +540,16 @@ class User(HashidMixin, UserMixin, db.Model): self.profile_privacy_settings = 0 #endregion Profile Privacy settings - def to_json_serializeable(self, backrefs=False, relationships=False): + def to_json_serializeable( + self, backrefs=False, + relationships=False, + filter_by_privacy_settings=False, + include_corpus_relationships=False, + include_job_relationships=False, + include_tesseract_ocr_pipeline_model_relationships=False, + include_spacy_nlp_pipeline_model_relationships=False, + include_avatar_relationship=False + ): json_serializeable = { 'id': self.hashid, 'confirmed': self.confirmed, @@ -562,23 +575,39 @@ class User(HashidMixin, UserMixin, db.Model): if backrefs: json_serializeable['role'] = \ self.role.to_json_serializeable(backrefs=True) - if relationships: + if relationships or include_corpus_relationships: json_serializeable['corpora'] = { x.hashid: x.to_json_serializeable(relationships=True) for x in self.corpora } + if relationships or include_job_relationships: json_serializeable['jobs'] = { x.hashid: x.to_json_serializeable(relationships=True) for x in self.jobs } + if relationships or include_tesseract_ocr_pipeline_model_relationships: json_serializeable['tesseract_ocr_pipeline_models'] = { x.hashid: x.to_json_serializeable(relationships=True) for x in self.tesseract_ocr_pipeline_models } + if relationships or include_spacy_nlp_pipeline_model_relationships: json_serializeable['spacy_nlp_pipeline_models'] = { x.hashid: x.to_json_serializeable(relationships=True) for x in self.spacy_nlp_pipeline_models } + if relationships or include_avatar_relationship: + json_serializeable['avatar'] = ( + None if self.avatar is None + else self.avatar.to_json_serializeable(relationships=True) + ) + + if filter_by_privacy_settings: + if not self.has_profile_privacy_setting(ProfilePrivacySettings.SHOW_EMAIL): + json_serializeable.pop('email') + if not self.has_profile_privacy_setting(ProfilePrivacySettings.SHOW_LAST_SEEN): + json_serializeable.pop('last_seen') + if not self.has_profile_privacy_setting(ProfilePrivacySettings.SHOW_MEMBER_SINCE): + json_serializeable.pop('member_since') return json_serializeable diff --git a/app/profile/routes.py b/app/profile/routes.py index b4711aa54c8113066150d738a9502f4995005232..8c1f8e81cbce8c994006305b12817a4e69fd7f92 100644 --- a/app/profile/routes.py +++ b/app/profile/routes.py @@ -54,7 +54,6 @@ def delete_avatar(avatar_id, user_id): def _delete_avatar(app, avatar_id): with app.app_context(): avatar_file = Avatar.query.get(avatar_id) - print(avatar_file) avatar_file.delete() db.session.commit() thread = Thread( diff --git a/app/static/js/RessourceLists/PublicUserList.js b/app/static/js/RessourceLists/PublicUserList.js new file mode 100644 index 0000000000000000000000000000000000000000..4597ed3e2b97b410a5fdd372190b17795343e82f --- /dev/null +++ b/app/static/js/RessourceLists/PublicUserList.js @@ -0,0 +1,79 @@ +class PublicUserList extends RessourceList { + static autoInit() { + for (let publicUserListElement of document.querySelectorAll('.public-user-list:not(.no-autoinit)')) { + new PublicUserList(publicUserListElement); + } + } + + static options = { + initialHtmlGenerator: (id) => { + console.log(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 user</label> + </div> + <table> + <thead> + <tr> + <th style="width:15%;"></th> + <th>Username</th> + <th></th> + </tr> + </thead> + <tbody class="list"></tbody> + </table> + <ul class="pagination"></ul> + `.trim(); + }, + item: ` + <tr class="clickable hoverable"> + <td><img alt="user-image" class="circle responsive-img avatar" style="width:80%"></td> + <td><span class="username"></span></td> + <td class="right-align"> + <a class="action-button btn-floating waves-effect waves-light" data-action="view"><i class="material-icons">send</i></a> + </td> + </tr> + `.trim(), + ressourceMapper: (user) => { + return { + 'id': user.id, + 'member-since': user.member_since, + 'avatar': `/static/images/user_avatar.png`, + 'username': user.username + }; + }, + sortArgs: ['member-since', {order: 'desc'}], + valueNames: [ + {data: ['id']}, + {data: ['member-since']}, + {name: 'avatar', attr: 'src'}, + 'username' + ] + }; + + constructor(listElement, options = {}) { + super(listElement, {...PublicUserList.options, ...options}); + } + + init(users) { + super._init(Object.values(users)); + } + + onClick(event) { + let actionButtonElement = event.target.closest('.action-button'); + let action = actionButtonElement === null ? 'view' : actionButtonElement.dataset.action; + let publicUserElement = event.target.closest('tr'); + let publicUserId = publicUserElement.dataset.id; + switch (action) { + case 'view': { + window.location.href = `/profile/${publicUserId}`; + break; + } + default: { + break; + } + } + } +} diff --git a/app/static/js/RessourceLists/RessourceList.js b/app/static/js/RessourceLists/RessourceList.js index 323f9d0e7b455e83fb04a43da03d919fecda6462..e53367fd2eb4021ea92329dc4a71d30326409703 100644 --- a/app/static/js/RessourceLists/RessourceList.js +++ b/app/static/js/RessourceLists/RessourceList.js @@ -10,6 +10,8 @@ class RessourceList { JobList.autoInit(); JobInputList.autoInit(); JobResultList.autoInit(); + PublicCorporaList.autoInit(); + PublicUserList.autoInit(); SpaCyNLPPipelineModelList.autoInit(); TesseractOCRPipelineModelList.autoInit(); UserList.autoInit(); diff --git a/app/templates/_scripts.html.j2 b/app/templates/_scripts.html.j2 index 24d24d974bc7877efa90c7670149afa29498179b..84b03e6261cf112fe5f8fa1ab52d627829ca377e 100644 --- a/app/templates/_scripts.html.j2 +++ b/app/templates/_scripts.html.j2 @@ -24,6 +24,8 @@ 'js/RessourceLists/JobList.js', 'js/RessourceLists/JobInputList.js', 'js/RessourceLists/JobResultList.js', + 'js/RessourceLists/PublicCorporaList.js', + 'js/RessourceLists/PublicUserList.js', 'js/RessourceLists/SpacyNLPPipelineModelList.js', 'js/RessourceLists/TesseractOCRPipelineModelList.js', 'js/RessourceLists/UserList.js', diff --git a/app/templates/admin/users.html.j2 b/app/templates/admin/users.html.j2 index 75254b0e45a7eac5e6a65264ce4a51b5c36b2a10..55c5dc2d8d77451d3c94528aaacca5933acffbac 100644 --- a/app/templates/admin/users.html.j2 +++ b/app/templates/admin/users.html.j2 @@ -22,11 +22,7 @@ {% block scripts %} {{ super() }} <script> - for (let user of {{ json_users|tojson }}) { - if (user.id in app.data.users) {continue;} - app.data.users[user.id] = user; - } let userList = new UserList(document.querySelector('.user-list')); - userList.init(app.data.users); + userList._init({{ json_users|tojson }}); </script> {% endblock scripts %} diff --git a/app/templates/main/dashboard.html.j2 b/app/templates/main/dashboard.html.j2 index e0354ea624eff3230e0a2d392fb2d6a93ca4ba45..eb504cb3b2082cc56ba0853d380f1ea43043a9e5 100644 --- a/app/templates/main/dashboard.html.j2 +++ b/app/templates/main/dashboard.html.j2 @@ -49,6 +49,7 @@ <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 class="public-user-list no-autoinit"></div> </div> </div> </div> @@ -115,3 +116,11 @@ </div> </div> {% endblock modals %} + +{% block scripts %} +{{ super() }} +<script> + let publicUserList = new PublicUserList(document.querySelector('.public-user-list')); + publicUserList._init({{ users|tojson }}); +</script> +{% endblock scripts %}