diff --git a/common/templates/base.html b/common/templates/base.html index 770ca005330baeaff2b69313cab091cfcf21e247..f39de094022127559c84ab1497c5551df13fc62a 100644 --- a/common/templates/base.html +++ b/common/templates/base.html @@ -49,6 +49,7 @@ <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarNav"> + {% if request.user.is_authenticated %} <ul class="navbar-nav mr-auto"> <li class="nav-item" id="nav-entries"> <a class="nav-link text-light" href="{% url 'entries:entries' %}"> @@ -74,6 +75,7 @@ </li> {% endif %} </ul> + {% endif %} </div> <span id="import-status" class="navbar-text text-warning mr-3"></span> {% if request.user.is_authenticated %} diff --git a/dictionary_statistics/views.py b/dictionary_statistics/views.py index e91161ab6ba7b252ae9aad5505c0dde5cb54fbb8..c681d40d2780f4d54d3ea4d93799b69557b42dde 100644 --- a/dictionary_statistics/views.py +++ b/dictionary_statistics/views.py @@ -1,3 +1,4 @@ +from django.contrib.auth.decorators import login_required from django.shortcuts import render from django.utils.translation import gettext as _ @@ -7,6 +8,7 @@ from semantics.models import Frame, FrameOpinion from entries.polish_strings import POS as POS_names, STATUS, SCHEMA_OPINION, FRAME_OPINION +@login_required def dictionary_statistics(request): ALL = _('wszystkie') diff --git a/entries/static/entries/js/components/Entries.js b/entries/static/entries/js/components/Entries.js index 2b92bd810dd3911bfccd977aaae86677741322bd..bc99261cdc6e1f230a9fe6f7f6047888a652649d 100644 --- a/entries/static/entries/js/components/Entries.js +++ b/entries/static/entries/js/components/Entries.js @@ -30,7 +30,6 @@ export default { mounted () { $('#entries-list').length && Split(['#entries-list', '#entry-display'], { sizes: [20, 80], - minSize: 300, gutterSize: 4, elementStyle: (dimension, size, gutterSize) => { return { @@ -45,8 +44,8 @@ export default { }); }, template: ` - <div id="entries-list" class="col h-100 w-100 px-0"> - <div id="entries-list-div" class="col p-0 h-100 w-100 overflow-auto"> + <div id="entries-list" class="col h-100 w-100 px-0 overflow-hidden"> + <div id="entries-list-div" class="col p-0 h-100 w-100 overflow-hidden"> <unification-entries-list :unificationEntriesListRefreshKey="unificationEntriesListRefreshKey" :initialLexicalUnitId="lexicalUnitId" @@ -54,7 +53,7 @@ export default { @lexical-unit-selected="lexicalUnitSelected" /> </div> </div> - <div id="entry-display" class="col h-100 p-0"> + <div id="entry-display" class="col h-100 p-0 overflow-hidden"> <div class="w-100 h-100"> <div id="right-pane" class="col w-100 p-0"> <unification-right-pane diff --git a/entries/static/entries/js/components/LexicalUnitDisplay.js b/entries/static/entries/js/components/LexicalUnitDisplay.js index 183a8103d10f7f2ad49755caec6e952fe5edbb3d..7aae57fade10b4d0e48cdf6d1bc05c56aaed671d 100644 --- a/entries/static/entries/js/components/LexicalUnitDisplay.js +++ b/entries/static/entries/js/components/LexicalUnitDisplay.js @@ -94,7 +94,6 @@ export default { mounted () { Split(['#semantics-frames-pane', '#semantics-schemata-pane'], { sizes: [40, 60], - minSize: 400, gutterSize: 4, elementStyle: (dimension, size, gutterSize) => { return { diff --git a/entries/static/entries/js/components/LexicalUnitEdit.js b/entries/static/entries/js/components/LexicalUnitEdit.js index 9a130e248f422647249905371538761abbc38369..f0442eebb674aa05540eacb9eb7f625513d6a5f4 100644 --- a/entries/static/entries/js/components/LexicalUnitEdit.js +++ b/entries/static/entries/js/components/LexicalUnitEdit.js @@ -816,27 +816,26 @@ Object.assign(LexicalUnitEdit, { changeShowVerifiedFrames (val) { this.showVerifiedFrames = val; }, - getArgumentCSS(argument) { - return (argument.role ? argument.role.str + ' ' : '') + (argument == this.active_unified_frame_argument ? 'active' : ''); - } }, mounted() { this.changeStatusButtonTitleToDefault(); - Split(['#semantics-frames-pane', '#semantics-schemata-pane'], { - sizes: [40, 60], - minSize: 400, - gutterSize: 4, - elementStyle: (dimension, size, gutterSize) => { - return { - 'flex-basis': 'calc(' + size + '% - ' + gutterSize + 'px)' - } - }, - }); - Split(['#semantics-unified-frame-pane', '#semantics-slowal-frames-pane', '#examples'], { - sizes: [40, 40, 20], - direction: 'vertical', - gutterSize: 4, - }); + if(!this.readOnly) { + Split(['#semantics-frames-pane', '#semantics-schemata-pane'], { + sizes: [40, 60], + minSize: 400, + gutterSize: 4, + elementStyle: (dimension, size, gutterSize) => { + return { + 'flex-basis': 'calc(' + size + '% - ' + gutterSize + 'px)' + } + }, + }); + Split(['#semantics-unified-frame-pane', '#semantics-slowal-frames-pane', '#examples'], { + sizes: [40, 40, 20], + direction: 'vertical', + gutterSize: 4, + }); + } if(this.unifiedFrameId) { this.loadFrame(); } @@ -865,37 +864,34 @@ Object.assign(LexicalUnitEdit, { <div align="center"> <div align="left" style="display: table;"> <div class="unifiedFrame mt-3" v-bind:data-frame_id="unified_frame.id" id="lexical-unit" v-html="unified_frame_title"></div> - <table v-if="unified_frame.id" id="unified-frame" class="m-0 table-borderless border border-secondary text-dark frame active"> + <table v-if="unified_frame.id" id="unified-frame" class="m-0 table-borderless border border-secondary text-dark"> <tbody> <tr> <th scope="row" class="py-2 px-1 text-secondary role-header">Role</th> - - <template v-for="argument in unified_frame_arguments"> - <td - class="argument py-2 px-1 border-top border-left border-secondary role-column" - :class="getArgumentCSS(argument)" - @click="unifiedFrameArgumentSelected(argument)" - @mouseover="unifiedFrameArgumentHovered(argument)" - @mouseleave="unifiedFrameArgumentHovered(null)" - > - {{ argument.role_type }} - - <div - v-if="argument.role" - > - [{{ argument.role.str }}] - </div> - <div v-else> - <ul class="ul-role"> - <li v-for="proposed_role in argument.proposed_roles"> - {{ proposed_role.str }} - </li> - </ul> - </div> - </td> - </template> - - + <td + class="argument py-2 px-1 border-top border-left border-secondary role-column" + :class="argument == active_unified_frame_argument && 'active'" + v-for="argument in unified_frame_arguments" + :key="argument.id" + @click="unifiedFrameArgumentSelected(argument)" + @mouseover="unifiedFrameArgumentHovered(argument)" + @mouseleave="unifiedFrameArgumentHovered(null)" + > + {{ argument.role_type }} + + <div + v-if="argument.role" + > + [{{ argument.role.str }}] + </div> + <div v-else> + <ul class="ul-role"> + <li v-for="proposed_role in argument.proposed_roles"> + {{ proposed_role.str }} + </li> + </ul> + </div> + </td> </tr> <tr> <th scope="row" class="py-0 px-1 text-secondary role-header">Selectional preferences</th> @@ -1013,7 +1009,7 @@ Object.assign(LexicalUnitEdit, { </div> </div> </div> - <div class="col w-100 p-0 tab-pane overflow-auto" id="examples"> + <div v-if="!readOnly" class="col w-100 p-0 tab-pane overflow-auto" id="examples"> <table id="semantics-examples" class="table table-sm table-hover"> <thead> <tr> diff --git a/entries/static/entries/js/components/UnificationComponent.js b/entries/static/entries/js/components/UnificationComponent.js index 5ee1ebb5f11c9d66e6b472521ca6691262da383c..79291be97c711867caa72bf2a9fe35fc1229a4e9 100644 --- a/entries/static/entries/js/components/UnificationComponent.js +++ b/entries/static/entries/js/components/UnificationComponent.js @@ -41,7 +41,6 @@ export default { this.unifiedFrameSelected(window.initialUnifiedFrameId); $('#entries-list').length && Split(['#entries-list', '#entry-display'], { sizes: [20, 80], - minSize: 300, gutterSize: 4, elementStyle: (dimension, size, gutterSize) => { return { @@ -51,8 +50,8 @@ export default { }); }, template: ` - <div id="entries-list" class="col h-100 w-100 px-0"> - <div id="entries-list-div" class="col p-0 h-100 w-100 overflow-auto"> + <div id="entries-list" class="col h-100 w-100 px-0 overflow-hidden"> + <div id="entries-list-div" class="col p-0 h-100 w-100 overflow-hidden"> <unification-switchable-list :unificationEntriesListRefreshKey="unificationEntriesListRefreshKey" :initialLexicalUnitId="lexicalUnitId ? lexicalUnitId : initialLexicalUnitId" @@ -62,7 +61,7 @@ export default { /> </div> </div> - <div id="entry-display" class="col h-100 p-0"> + <div id="entry-display" class="col h-100 p-0 overflow-hidden"> <unification-right-pane ref="unificationRightPane" :entryId="entryId" diff --git a/entries/static/entries/js/unification_entries_for_frames_list.js b/entries/static/entries/js/unification_entries_for_frames_list.js index 8221e310bc12b1dc20c922363aeaa98bef06c0cd..0b0d90681498593a0ac40c471c413f7312d5ab10 100644 --- a/entries/static/entries/js/unification_entries_for_frames_list.js +++ b/entries/static/entries/js/unification_entries_for_frames_list.js @@ -1,7 +1,7 @@ function setup_entries_for_frames_list(options) { const can_see_assignees = has_permission("users.view_assignment"); - function is_assigned_to_user_renderer (data) { + function is_assigned_to_user_renderer (_1, _2, data) { return ( data && data.lexical_units @@ -18,7 +18,7 @@ function setup_entries_for_frames_list(options) { columns: [ { data: 'lemma' }, { data: 'POS' }, - { render: data => (data && data.lexical_units && data.lexical_units.some(lu => lu.assignee_username !== null)) ? gettext("nie") : gettext("tak") }, + { render: (_1, _2, data) => (data && data.lexical_units && data.lexical_units.some(lu => lu.assignee_username !== null)) ? gettext("nie") : gettext("tak") }, can_see_assignees ? { data: 'assignee_username' } : { render: is_assigned_to_user_renderer }, ], hidden_columns: can_see_assignees ? [2] : [2,3], diff --git a/entries/static/entries/js/unification_entries_list.js b/entries/static/entries/js/unification_entries_list.js index 24240f3893d2e37181ef191d808702e62ba1f5f9..0db5af2c5162e514f116086864a76359892a6650 100644 --- a/entries/static/entries/js/unification_entries_list.js +++ b/entries/static/entries/js/unification_entries_list.js @@ -1,7 +1,7 @@ function setup_entries_list(options) { const can_see_assignees = has_permission("users.view_assignment"); - function is_assigned_to_user_renderer (data) { + function is_assigned_to_user_renderer (_1, _2, data) { return ( data && data.lexical_units @@ -16,7 +16,7 @@ function setup_entries_list(options) { columns: [ { data: 'lemma' }, { data: 'POS' }, - { render: data => (data && data.lexical_units && data.lexical_units.some(lu => lu.assignee_username !== null)) ? gettext("nie") : gettext("tak") }, + { render: (_1, _2, data) => (data && data.lexical_units && data.lexical_units.some(lu => lu.assignee_username !== null)) ? gettext("nie") : gettext("tak") }, can_see_assignees ? { data: 'assignee_username' } : { render: is_assigned_to_user_renderer }, ], selectEntryId: options.selectEntryId, diff --git a/entries/static/entries/js/unification_frames_list.js b/entries/static/entries/js/unification_frames_list.js index 3efb6c61f579ee761e2c70f29bef6edf761b1e18..63b2fc91270f87bd007102d16cd2eb0ad865a1dc 100644 --- a/entries/static/entries/js/unification_frames_list.js +++ b/entries/static/entries/js/unification_frames_list.js @@ -1,7 +1,7 @@ function setup_frames_list(options) { const can_see_assignees = has_permission("users.view_assignment"); - function is_assigned_to_user_renderer (data) { + function is_assigned_to_user_renderer (_1, _2, data) { return ( data && data.assignee_username === window.USER_USERNAME diff --git a/entries/views.py b/entries/views.py index d69fd47df7de846184a42605632d4446d63c52ad..2a2d2f5875a863e1a799ad69651fa1345644aa47 100644 --- a/entries/views.py +++ b/entries/views.py @@ -7,6 +7,7 @@ from itertools import chain, product import simplejson +from django.contrib.auth.models import User from django.contrib.auth.decorators import login_required from django.db.models import Prefetch, Q from django.http import JsonResponse, QueryDict @@ -24,6 +25,7 @@ from semantics.models import Frame, PredefinedSelectionalPreference, SelectivePr from common.decorators import ajax_required, ajax from unifier.models import UnifiedFrame +from users.models import Assignment from .forms import ( EntryForm, @@ -49,6 +51,7 @@ MAX_LAST_VISITED = 10 #def test(request): # return render(request, 'test.html', {}) +@login_required def entries(request): # TODO make this automatic by subclassing/configuring session object if 'last_visited' not in request.session: @@ -347,6 +350,7 @@ def get_scroller_params(POST_data): #from django.db.models import Count @ajax_required +@login_required def get_entries(request): if request.method == 'POST': errors_dict = dict() @@ -372,9 +376,13 @@ def get_entries(request): linked_ids = set() if request.session['show_linked_entries']: - entries_linked = Entry.objects.filter(subentries__schema_hooks__argument_connections__schema_connections__subentry__entry__in=entries).distinct().exclude(id__in=entries) + entries_linked = Entry.objects.filter(pk__in=( + Entry.objects + .filter(subentries__schema_hooks__argument_connections__schema_connections__subentry__entry__in=entries) + .exclude(id__in=entries) + )).distinct() entries = entries | entries_linked - linked_ids = set(e.id for e in entries_linked) + linked_ids = set(entries_linked.values_list('id', flat=True)) first_index, last_index = scroller_params['start'], scroller_params['start'] + scroller_params['length'] order_field, order_dir = scroller_params['order'] @@ -386,12 +394,39 @@ def get_entries(request): order_field = 'pos__tag' if order_dir == 'desc': order_field = '-' + order_field - entries = entries.order_by(order_field).only('id', 'name', 'status__key', 'pos__tag') + + if restrict_to_user: + # pre-filtering entries for performance reasons + entries = entries.filter(lexical_units__frames__assignments__user=User.objects.get(username=restrict_to_user)) + entries = ( + entries + .order_by(order_field) + .select_related('status', 'pos') + .prefetch_related(Prefetch("assignments", to_attr="_assignments")) + ) if with_lexical_units: - entries = entries.prefetch_related("lexical_units") + entries = entries.prefetch_related( + Prefetch( + "lexical_units", + LexicalUnit.objects.prefetch_related( + Prefetch( + "frames", + Frame.objects + .select_related("slowal_frame_2_unified_frame") + .prefetch_related(Prefetch("assignments", to_attr="_assignments")), + to_attr="_frames", + ) + ) + ) + ) status_names = STATUS() POS_names = POS() - entriesList = list(entries) + + def iter_lexical_units(e): + for lu in e.lexical_units.all(): + lu._frame = lu._frames[0] if lu._frames else None + yield lu + result = { 'draw' : scroller_params['draw'], 'recordsTotal': total, @@ -403,7 +438,7 @@ def get_entries(request): 'status' : status_names[e.status.key], 'POS' : POS_names[e.pos.tag], 'related' : e.id in linked_ids, - 'assignee_username': assignment.user.username if (assignment := e.assignments.first()) else None, + 'assignee_username': e._assignments[0].user.username if e._assignments else None, **( { 'lexical_units': [ @@ -411,16 +446,16 @@ def get_entries(request): 'pk': lu.pk, 'display': str(lu), 'assignee_username': ( - assignment.user.username if (frame := lu.frames.first()) and (assignment := frame.assignments.first()) else None + lu._frame._assignments[0].user.username if lu._frame and lu._frame._assignments else None ), - 'status': frame.status if (frame := lu.frames.first()) else "", - 'unified_frame_id': frame.slowal_frame_2_unified_frame.unified_frame_id if (frame := lu.frames.first()) and hasattr(frame, 'slowal_frame_2_unified_frame') else -1, - } for lu in e.lexical_units.all() + 'status': lu._frame.status if lu._frame else "", + 'unified_frame_id': lu._frame.slowal_frame_2_unified_frame.unified_frame_id if lu._frame and hasattr(lu._frame, 'slowal_frame_2_unified_frame') else -1, + } for lu in iter_lexical_units(e) ] } if with_lexical_units else {} ), - } for e in entriesList[first_index:last_index] + } for e in entries[first_index:last_index] ], } diff --git a/phrase_expansions/views.py b/phrase_expansions/views.py index 58162d367760d4c7f9722760db4cc38a4881682a..4821f6485c9048b516345fb7a88987936f96e9a1 100644 --- a/phrase_expansions/views.py +++ b/phrase_expansions/views.py @@ -1,7 +1,7 @@ from collections import defaultdict +from django.contrib.auth.decorators import login_required from django.shortcuts import render - from django.utils.translation import gettext as _ from phrase_expansions.models import PhraseExpansionType, PhraseExpansion @@ -13,7 +13,8 @@ def EXPANSION_OPINION(): 'unc' : _('wÄ…tpliwe'), 'cer' : _('pewne'), } - + +@login_required def phrase_expansions(request): expansions = defaultdict(list) expansions = [ diff --git a/unifier/views.py b/unifier/views.py index beb6b499b58177486b27f896cbe2591ebd5d4b42..119cac2c73c8c73f689153465e8d274c0a421355 100644 --- a/unifier/views.py +++ b/unifier/views.py @@ -1,5 +1,6 @@ import json import requests +from django.contrib.auth.decorators import login_required from django.db import transaction from django.http import JsonResponse, HttpResponse from django.shortcuts import get_object_or_404 @@ -206,6 +207,7 @@ def get_unified_frame_json(unifiedFrame, request): return { 'unified_frame_id': unifiedFrame.id, 'unified_frame': unifiedFrame_dict, 'subentries': subentries, 'frames' : slowal_frames_dict, 'alternations' : alternations, 'realisation_phrases' : realisation_phrases, 'realisation_descriptions' : realisation_descriptions, 'examples' : examples, 'last_visited' : request.session['last_visited'] } @ajax_required +@login_required def get_unified_frame(request): if request.method == 'POST': #TODO (*)