Merge branch 'profile-page' into development

This commit is contained in:
Inga Kirschnick 2022-12-19 12:51:06 +01:00
commit c0d015acd8
8 changed files with 133 additions and 13 deletions

View File

@ -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')

View File

@ -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

View File

@ -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(

View File

@ -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;
}
}
}
}

View File

@ -10,6 +10,8 @@ class RessourceList {
JobList.autoInit();
JobInputList.autoInit();
JobResultList.autoInit();
PublicCorporaList.autoInit();
PublicUserList.autoInit();
SpaCyNLPPipelineModelList.autoInit();
TesseractOCRPipelineModelList.autoInit();
UserList.autoInit();

View File

@ -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',

View File

@ -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 %}

View File

@ -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 %}