Compare commits

...

6 Commits

7 changed files with 86 additions and 102 deletions

View File

@ -38,7 +38,7 @@ def cqi_corpora_corpus_query(cqi_client: cqi.CQiClient, corpus_name: str, subcor
@cqi_over_socketio @cqi_over_socketio
def cqi_corpora_corpus_update_db(cqi_client: cqi.CQiClient, corpus_name: str): def cqi_corpora_corpus_update_db(cqi_client: cqi.CQiClient, corpus_name: str):
corpus = Corpus.query.get(session['d']['corpus_id']) corpus = Corpus.query.get(session['d']['corpus_id'])
corpus.num_tokens = cqi_client.corpora.get('CORPUS').attrs['size'] corpus.num_tokens = cqi_client.corpora.get(corpus_name).attrs['size']
db.session.commit() db.session.commit()

View File

@ -54,7 +54,6 @@ def corpus(corpus_id):
# TODO: Better solution for filtering admin # TODO: Better solution for filtering admin
users = User.query.filter(User.is_public == True, User.id != current_user.id, User.id != corpus.user.id, User.role_id < 4).all() users = User.query.filter(User.is_public == True, User.id != current_user.id, User.id != corpus.user.id, User.role_id < 4).all()
cfa = CorpusFollowerAssociation.query.filter_by(corpus_id=corpus_id, follower_id=current_user.id).first() cfa = CorpusFollowerAssociation.query.filter_by(corpus_id=corpus_id, follower_id=current_user.id).first()
cfas = CorpusFollowerAssociation.query.filter_by(corpus_id=corpus_id).all()
if cfa is None: if cfa is None:
if corpus.user == current_user or current_user.is_administrator(): if corpus.user == current_user or current_user.is_administrator():
cfr = CorpusFollowerRole.query.filter_by(name='Administrator').first() cfr = CorpusFollowerRole.query.filter_by(name='Administrator').first()
@ -72,7 +71,7 @@ def corpus(corpus_id):
users = users users = users
) )
if (current_user.is_following_corpus(corpus) or corpus.is_public): if (current_user.is_following_corpus(corpus) or corpus.is_public):
cfas = CorpusFollowerAssociation.query.filter_by(corpus_id=corpus_id).all() cfas = CorpusFollowerAssociation.query.filter(Corpus.id == corpus_id, CorpusFollowerAssociation.follower_id != current_user.id, CorpusFollowerAssociation. follower_id != corpus.user.id).all()
return render_template( return render_template(
'corpora/public_corpus.html.j2', 'corpora/public_corpus.html.j2',
title=corpus.title, title=corpus.title,
@ -80,7 +79,6 @@ def corpus(corpus_id):
cfrs=cfrs, cfrs=cfrs,
cfr=cfr, cfr=cfr,
cfas=cfas, cfas=cfas,
cfa=cfa,
users = users users = users
) )
abort(403) abort(403)

View File

@ -12,7 +12,7 @@ class CorpusFileList extends ResourceList {
element.addEventListener('click', (event) => {this.onSelectionAction(event)}); element.addEventListener('click', (event) => {this.onSelectionAction(event)});
}); });
this.isInitialized = false; this.isInitialized = false;
this.selectedItemIds = []; this.selectedItemIds = new Set();
this.userId = listContainerElement.dataset.userId; this.userId = listContainerElement.dataset.userId;
this.corpusId = listContainerElement.dataset.corpusId; this.corpusId = listContainerElement.dataset.corpusId;
this.hasPermissionView = listContainerElement.dataset?.hasPermissionView == 'true' || false; this.hasPermissionView = listContainerElement.dataset?.hasPermissionView == 'true' || false;
@ -35,7 +35,7 @@ class CorpusFileList extends ResourceList {
<tr class="list-item"> <tr class="list-item">
<td> <td>
<label class="list-action-trigger ${this.hasPermissionView ? '' : 'hide'}" data-list-action="select"> <label class="list-action-trigger ${this.hasPermissionView ? '' : 'hide'}" data-list-action="select">
<input type="checkbox"> <input class="select-checkbox" type="checkbox">
<span class="disable-on-click"></span> <span class="disable-on-click"></span>
</label> </label>
</td> </td>
@ -80,7 +80,7 @@ class CorpusFileList extends ResourceList {
<tr> <tr>
<th> <th>
<label class="selection-action-trigger ${this.listContainerElement.dataset?.hasPermissionView == 'true' ? '' : 'hide'}" data-selection-action="select-all"> <label class="selection-action-trigger ${this.listContainerElement.dataset?.hasPermissionView == 'true' ? '' : 'hide'}" data-selection-action="select-all">
<input type="checkbox"> <input class="select-all-checkbox" type="checkbox">
<span></span> <span></span>
</label> </label>
</th> </th>
@ -152,7 +152,14 @@ class CorpusFileList extends ResourceList {
); );
let confirmElement = modalElement.querySelector('.action-button[data-action="confirm"]'); let confirmElement = modalElement.querySelector('.action-button[data-action="confirm"]');
confirmElement.addEventListener('click', (event) => { confirmElement.addEventListener('click', (event) => {
Requests.corpora.entity.files.ent.delete(this.corpusId, itemId); if (currentUserId != this.userId) {
Requests.corpora.entity.files.ent.delete(this.corpusId, itemId)
.then(() => {
window.location.reload();
});
} else {
Requests.corpora.entity.followers.entity.delete(this.corpusId, itemId);
}
}); });
modal.open(); modal.open();
break; break;
@ -166,13 +173,11 @@ class CorpusFileList extends ResourceList {
break; break;
} }
case 'select': { case 'select': {
if (event.target.checked) { if (event.target.checked) {
this.selectedItemIds.push(itemId); this.selectedItemIds.add(itemId);
} else { } else {
let index = this.selectedItemIds.indexOf(itemId); this.selectedItemIds.delete(itemId);
if (index > -1) {
this.selectedItemIds.splice(index, 1);
}
} }
this.renderingItemSelection(); this.renderingItemSelection();
} }
@ -188,18 +193,19 @@ class CorpusFileList extends ResourceList {
let items = this.listjs.items; let items = this.listjs.items;
let selectableItems = Array.from(items) let selectableItems = Array.from(items)
.filter(item => item.elm) .filter(item => item.elm)
.map(item => item.elm.querySelector('input[type="checkbox"]')); .map(item => item.elm.querySelector('.select-checkbox[type="checkbox"]'));
switch (selectionAction) { switch (selectionAction) {
case 'select-all': { case 'select-all': {
let selectedIds = Array.from(items) let selectedIds = new Set(Array.from(items)
.map(item => item.values().id); .map(item => item.values().id))
if (event.target.checked) { if (event.target.checked) {
selectableItems.forEach(selectableItem => selectableItem.checked = true); selectableItems.forEach(selectableItem => selectableItem.checked = true);
this.selectedItemIds = selectedIds; this.selectedItemIds = selectedIds;
} else { } else {
selectableItems.forEach(checkbox => checkbox.checked = false); selectableItems.forEach(checkbox => checkbox.checked = false);
this.selectedItemIds = this.selectedItemIds.filter(id => !selectedIds.includes(id)); this.selectedItemIds = new Set([...this.selectedItemIds].filter(id => !selectedIds.has(id)));
} }
this.renderingItemSelection(); this.renderingItemSelection();
break; break;
@ -242,9 +248,16 @@ class CorpusFileList extends ResourceList {
let confirmElement = modalElement.querySelector('.action-button[data-action="confirm"]'); let confirmElement = modalElement.querySelector('.action-button[data-action="confirm"]');
confirmElement.addEventListener('click', (event) => { confirmElement.addEventListener('click', (event) => {
this.selectedItemIds.forEach(selectedItemId => { this.selectedItemIds.forEach(selectedItemId => {
Requests.corpora.entity.files.ent.delete(this.corpusId, selectedItemId); if (currentUserId != this.userId) {
Requests.corpora.entity.files.ent.delete(this.corpusId, selectedItemId)
.then(() => {
window.location.reload();
});
} else {
Requests.corpora.entity.files.ent.delete(this.corpusId, selectedItemId);
}
}); });
this.selectedItemIds = []; this.selectedItemIds.clear();
this.renderingItemSelection(); this.renderingItemSelection();
}); });
modal.open(); modal.open();
@ -258,7 +271,7 @@ class CorpusFileList extends ResourceList {
downloadLink.click(); downloadLink.click();
}); });
selectableItems.forEach(checkbox => checkbox.checked = false); selectableItems.forEach(checkbox => checkbox.checked = false);
this.selectedItemIds = []; this.selectedItemIds.clear();
this.renderingItemSelection(); this.renderingItemSelection();
break; break;
} }
@ -280,7 +293,7 @@ class CorpusFileList extends ResourceList {
Object.values(selectableItems).forEach(selectableItem => { Object.values(selectableItems).forEach(selectableItem => {
if (selectableItem.elm) { if (selectableItem.elm) {
let checkbox = selectableItem.elm.querySelector('input[type="checkbox"]'); let checkbox = selectableItem.elm.querySelector('.select-checkbox[type="checkbox"]');
if (checkbox.checked) { if (checkbox.checked) {
selectableItem.elm.classList.add('grey', 'lighten-3'); selectableItem.elm.classList.add('grey', 'lighten-3');
} else { } else {
@ -298,7 +311,7 @@ class CorpusFileList extends ResourceList {
} }
}); });
// Hide item action buttons if > 0 item is selected and show selection action buttons // Hide item action buttons if > 0 item is selected and show selection action buttons
if (this.selectedItemIds.length > 0) { if (this.selectedItemIds.size > 0) {
selectionActionButtons.forEach(selectionActionButton => { selectionActionButtons.forEach(selectionActionButton => {
selectionActionButton.classList.remove('hide'); selectionActionButton.classList.remove('hide');
}); });

View File

@ -142,7 +142,14 @@ class CorpusFollowerList extends ResourceList {
switch (listAction) { switch (listAction) {
case 'unfollow-request': { case 'unfollow-request': {
let followerId = listItemElement.dataset.followerId; let followerId = listItemElement.dataset.followerId;
Requests.corpora.entity.followers.entity.delete(this.corpusId, followerId); if (currentUserId != this.userId) {
Requests.corpora.entity.followers.entity.delete(this.corpusId, followerId)
.then(() => {
window.location.reload();
});
} else {
Requests.corpora.entity.followers.entity.delete(this.corpusId, followerId);
}
break; break;
} }
case 'view': { case 'view': {

View File

@ -1,30 +0,0 @@
{% set owner_admin %}
<div class="col s12 l6" style="padding: 0 2.5px;">
<a class="action-button btn disabled waves-effect waves-light" data-action="build-request" style="width: 100%;"><i class="nopaque-icons left">K</i>Build</a>
</div>
<div class="col s12 l6" style="padding: 0 2.5px;">
<a class="action-button btn disabled waves-effect waves-light" data-action="analyze" href="{{ url_for('corpora.analysis', corpus_id=corpus.id) }}" style="width: 100%;"><i class="material-icons left">search</i>Analyze</a>
</div>
<div class="col s12 l6" style="padding: 5px 2.5px 0 2.5px;">
<a class="btn waves-effect waves-light modal-trigger" href="#publishing-modal" style="width: 100%;"><i class="material-icons left">publish</i>Publishing</a>
</div>
<div class="col s12 l6" style="padding: 5px 2.5px 0 2.5px;">
<a class="btn red waves-effect waves-light modal-trigger" href="#delete-modal" style="width: 100%;"><i class="material-icons left">delete</i>Delete</a>
</div>
{% endset %}
{% set follower %}
{% if cfr.has_permission('MANAGE_FILES') %}
<div class="col s12 l6" style="padding: 0 2.5px;">
<a class="action-button btn disabled waves-effect waves-light" data-action="build-request" style="width: 100%;"><i class="nopaque-icons left">K</i>Build</a>
</div>
<div class="col s12 l6" style="padding: 0 2.5px;">
<a class="action-button btn disabled waves-effect waves-light" data-action="analyze" href="{{ url_for('corpora.analysis', corpus_id=corpus.id) }}" style="width: 100%;"><i class="material-icons left">search</i>Analyze</a>
</div>
{% endif %}
{% if current_user.is_following_corpus(corpus) %}
<div class="col s12 l6" style="padding: 5px 2.5px 0 2.5px;">
<a class="action-button btn red waves-effect waves-light" data-action="unfollow-request" style="width: 100%;"><i class="material-icons left outlined">close</i>Unfollow Corpus</a>
</div>
{% endif %}
{% endset %}

View File

@ -1,6 +1,5 @@
{% extends "base.html.j2" %} {% extends "base.html.j2" %}
{% import "materialize/wtf.html.j2" as wtf %} {% import "materialize/wtf.html.j2" as wtf %}
{% import "corpora/_corpus/action_buttons.html.j2" as action_buttons with context %}
{% block main_attribs %} class="service-scheme" data-service="corpus-analysis"{% endblock main_attribs %} {% block main_attribs %} class="service-scheme" data-service="corpus-analysis"{% endblock main_attribs %}
@ -60,11 +59,18 @@
<div class="card-content"> <div class="card-content">
<span class="card-title">Actions</span> <span class="card-title">Actions</span>
<div class="row"> <div class="row">
{% if current_user == corpus.user or current_user.is_administrator() %} <div class="col s12 l6" style="padding: 0 2.5px;">
{{ action_buttons.owner_admin }} <a class="action-button btn disabled waves-effect waves-light" data-action="build-request" style="width: 100%;"><i class="nopaque-icons left">K</i>Build</a>
{% else %} </div>
{{ action_buttons.follower }} <div class="col s12 l6" style="padding: 0 2.5px;">
{% endif %} <a class="action-button btn disabled waves-effect waves-light" data-action="analyze" href="{{ url_for('corpora.analysis', corpus_id=corpus.id) }}" style="width: 100%;"><i class="material-icons left">search</i>Analyze</a>
</div>
<div class="col s12 l6" style="padding: 5px 2.5px 0 2.5px;">
<a class="btn waves-effect waves-light modal-trigger" href="#publishing-modal" style="width: 100%;"><i class="material-icons left">publish</i>Publishing</a>
</div>
<div class="col s12 l6" style="padding: 5px 2.5px 0 2.5px;">
<a class="btn red waves-effect waves-light modal-trigger" href="#delete-modal" style="width: 100%;"><i class="material-icons left">delete</i>Delete</a>
</div>
</div> </div>
{% if cfr.has_permission('MANAGE_FOLLOWERS') %} {% if cfr.has_permission('MANAGE_FOLLOWERS') %}
<span class="card-title">Social</span> <span class="card-title">Social</span>
@ -82,45 +88,6 @@
</div> </div>
{% endif %} {% endif %}
{% if current_user != corpus.user %}
<div class="col s12">
<div class="card">
<div class="card-content">
<span class="card-title" id="files">Corpus Owner</span>
<div class="row">
<div class="col s12">
<table>
<tr>
<td style="width:10%; margin-top:25px;">
<img src="{{ url_for('users.user_avatar', user_id=corpus.user.id) }}" alt="user-image" class="circle responsive-img">
</td>
<td></td>
<td>
<ul>
<li><b>{{ corpus.user.username }}</b></li>
{% if corpus.user.full_name %}
<li>{{ corpus.user.full_name }}</li>
{% endif %}
{% if corpus.user.show_email %}
<li></li><a href="mailto:{{ corpus.user.email }}">{{ corpus.user.email }}</a></li>
{% endif %}
</ul>
</td>
</tr>
</table>
<br>
<p></p>
{% if not current_user.is_following_corpus(corpus) and corpus.user.has_profile_privacy_setting('SHOW_EMAIL') %}
<a class="waves-effect waves-light btn-small" href="mailto:{{ corpus.user.email }}">Request Corpus</a>
{% endif %}
<a class="waves-effect waves-light btn-small" href="{{ url_for('users.user', user_id=corpus.user.id) }}">View profile</a>
</div>
</div>
</div>
</div>
</div>
{% endif %}
<div class="col s12"> <div class="col s12">
<div class="card"> <div class="card">
<div class="card-content"> <div class="card-content">

View File

@ -12,7 +12,10 @@
<div class="col s12 l7"> <div class="col s12 l7">
<div class="card service-color-border border-darken" data-service="corpus-analysis" style="border-top: 10px solid"> <div class="card service-color-border border-darken" data-service="corpus-analysis" style="border-top: 10px solid">
<div class="card-content"> <div class="card-content">
<span class="chip corpus-status-text corpus-status-color white-text" data-status="{{ corpus.status.name }}"></span></p> {% if corpus.status.name in ['SUBMITTED', 'QUEUED', 'BUILDING'] %}
<a class="btn-floating btn-small waves-effect waves-light" id="refresh-button"><i class="material-icons">refresh</i></a>
{% endif %}
<span class="chip corpus-status-text corpus-status-color white-text" data-status="{{ corpus.status.name }}"></span>
<div class="row"> <div class="row">
<div class="col s12"> <div class="col s12">
@ -48,7 +51,11 @@
<div class="row"> <div class="row">
{% if cfr.has_permission('MANAGE_FILES') %} {% if cfr.has_permission('MANAGE_FILES') %}
<div class="col s12 l6" style="padding: 0 2.5px;"> <div class="col s12 l6" style="padding: 0 2.5px;">
<a class="action-button btn disabled waves-effect waves-light" data-action="build-request" style="width: 100%;"><i class="nopaque-icons left">K</i>Build</a> {% if corpus.status.name in ['UNPREPARED', 'FAILED'] %}
<a class="btn waves-effect waves-light" id="follower-build-request" style="width: 100%;"><i class="nopaque-icons left">K</i>Build</a>
{% else %}
<a class="btn disabled waves-effect waves-light" id="follower-build-request" style="width: 100%;"><i class="nopaque-icons left">K</i>Build</a>
{% endif %}
</div> </div>
<div class="col s12 l6" style="padding: 0 2.5px;"> <div class="col s12 l6" style="padding: 0 2.5px;">
{% if corpus.status.name in ['BUILT', 'STARTING_ANALYSIS_SESSION', 'RUNNING_ANALYSIS_SESSION', 'CANCELING_ANALYSIS_SESSION'] and current_user.is_following_corpus(corpus) %} {% if corpus.status.name in ['BUILT', 'STARTING_ANALYSIS_SESSION', 'RUNNING_ANALYSIS_SESSION', 'CANCELING_ANALYSIS_SESSION'] and current_user.is_following_corpus(corpus) %}
@ -136,7 +143,7 @@
<div class="card"> <div class="card">
<div class="card-content"> <div class="card-content">
<span class="card-title" id="corpus-followers">Corpus followers</span> <span class="card-title" id="corpus-followers">Corpus followers</span>
<div class="corpus-follower-list no-autoinit"></div> <div class="corpus-follower-list no-autoinit" data-user-id="{{ corpus.user }}" data-corpus-id="{{ corpus.hashid }}"></div>
</div> </div>
</div> </div>
</div> </div>
@ -244,6 +251,13 @@ publicCorpusFileList.add(
] ]
); );
{% if corpus.status.name in ['SUBMITTED', 'QUEUED', 'BUILDING'] %}
let refreshButton = document.querySelector('#refresh-button');
refreshButton.addEventListener('click', () => {
window.location.reload();
});
{% endif %}
{% if cfr.has_permission('MANAGE_FOLLOWERS') %} {% if cfr.has_permission('MANAGE_FOLLOWERS') %}
let publicCorpusFollowerList = new CorpusFollowerList(document.querySelector('.corpus-follower-list')); let publicCorpusFollowerList = new CorpusFollowerList(document.querySelector('.corpus-follower-list'));
publicCorpusFollowerList.add( publicCorpusFollowerList.add(
@ -255,6 +269,18 @@ publicCorpusFollowerList.add(
); );
{% endif %} {% endif %}
// #region Build Corpus Request
{% if cfr.has_permission('MANAGE_CORPUS') %}
let followerBuildRequest = document.querySelector('#follower-build-request');
followerBuildRequest.addEventListener('click', () => {
Requests.corpora.entity.build({{ corpus.hashid|tojson }})
.then((response) => {
window.location.reload();
});
});
{% endif %}
// #endregion Build Corpus
// #region Corpus Unfollow Request // #region Corpus Unfollow Request
{% if current_user.is_following_corpus(corpus) %} {% if current_user.is_following_corpus(corpus) %}
let unfollowRequestElement = document.querySelector('.action-button[data-action="unfollow-request"]'); let unfollowRequestElement = document.querySelector('.action-button[data-action="unfollow-request"]');
@ -309,7 +335,10 @@ M.Modal.init(
inviteUserModalInviteButtonElement.addEventListener('click', (event) => { inviteUserModalInviteButtonElement.addEventListener('click', (event) => {
let usernames = inviteUserModalSearch.chipsData.map((chipData) => chipData.tag); let usernames = inviteUserModalSearch.chipsData.map((chipData) => chipData.tag);
Requests.corpora.entity.followers.add({{ corpus.hashid|tojson }}, usernames); Requests.corpora.entity.followers.add({{ corpus.hashid|tojson }}, usernames)
.then((response) => {
window.location.reload();
});
}); });
// #endregion Invite user // #endregion Invite user