From d672e5a3879e95a770eb463ebefdcba99c4c2501 Mon Sep 17 00:00:00 2001 From: susanodd Date: Sat, 22 Jun 2024 11:01:05 +0200 Subject: [PATCH] #1268: Initial Batch Edit View. --- media/js/glosses_toggle_edit.js | 53 ++ signbank/dictionary/adminviews.py | 123 ++++ signbank/dictionary/batch_edit.py | 71 +++ signbank/dictionary/forms.py | 90 ++- signbank/dictionary/models.py | 4 + .../dictionary/admin_batch_edit_view.html | 556 ++++++++++++++++++ .../annotation_idgloss_translation.py | 11 +- signbank/dictionary/update.py | 32 +- signbank/dictionary/update_glosses.py | 97 +++ signbank/dictionary/urls.py | 6 + signbank/urls.py | 3 +- 11 files changed, 1033 insertions(+), 13 deletions(-) create mode 100644 signbank/dictionary/batch_edit.py create mode 100644 signbank/dictionary/templates/dictionary/admin_batch_edit_view.html diff --git a/media/js/glosses_toggle_edit.js b/media/js/glosses_toggle_edit.js index c4c6d3351..397815586 100644 --- a/media/js/glosses_toggle_edit.js +++ b/media/js/glosses_toggle_edit.js @@ -65,6 +65,30 @@ function toggle_namedentity(data) { neCell.html(cell); } +function toggle_handedness(data) { + if ($.isEmptyObject(data)) { + return; + }; + var glossid = data.glossid; + var handedness = data.handedness; + var hCell = $("#handedness_cell_"+glossid); + $(hCell).empty(); + var cell = ""+handedness+""; + hCell.html(cell); +} + +function toggle_domhndsh(data) { + if ($.isEmptyObject(data)) { + return; + }; + var glossid = data.glossid; + var domhndsh = data.domhndsh; + var hCell = $("#domhndsh_cell_"+glossid); + $(hCell).empty(); + var cell = ""+domhndsh+""; + hCell.html(cell); +} + $(document).ready(function() { // setup required for Ajax POST @@ -137,4 +161,33 @@ $(document).ready(function() { success : toggle_namedentity }); }); + $('.quick_handedness').click(function(e) + { + e.preventDefault(); + console.log('handedness'); + var glossid = $(this).attr('value'); + var handedness = $(this).attr("data-handedness"); + $.ajax({ + url : url + "/dictionary/update/toggle_handedness/" + glossid + "/" + handedness, + type: 'POST', + data: { 'csrfmiddlewaretoken': csrf_token }, + datatype: "json", + success : toggle_handedness + }); + }); + $('.quick_domhndsh').click(function(e) + { + e.preventDefault(); + console.log('domhndsh'); + var glossid = $(this).attr('value'); + var domhndsh = $(this).attr("data-domhndsh"); + $.ajax({ + url : url + "/dictionary/update/toggle_domhndsh/" + glossid + "/" + domhndsh, + type: 'POST', + data: { 'csrfmiddlewaretoken': csrf_token }, + datatype: "json", + success : toggle_domhndsh + }); + }); + }); diff --git a/signbank/dictionary/adminviews.py b/signbank/dictionary/adminviews.py index 948c6d13d..5d102bb88 100755 --- a/signbank/dictionary/adminviews.py +++ b/signbank/dictionary/adminviews.py @@ -6495,6 +6495,129 @@ def get_queryset(self): return glossesXsenses +class BatchEditView(ListView): + + model = Gloss + template_name = 'dictionary/admin_batch_edit_view.html' + paginate_by = 25 + search_type = 'sign' + query_parameters = dict() + + def get(self, request, *args, **kwargs): + return super(BatchEditView, self).get(request, *args, **kwargs) + + def get_context_data(self, **kwargs): + context = super(BatchEditView, self).get_context_data(**kwargs) + + selected_datasets = get_selected_datasets_for_user(self.request.user) + context['selected_datasets'] = selected_datasets + + if not selected_datasets or selected_datasets.count() > 1: + dataset_languages = Language.objects.filter(id=get_default_language_id()) + else: + dataset_languages = get_dataset_languages(selected_datasets).order_by('id') + + context['dataset_languages'] = dataset_languages + + search_form = KeyMappingSearchForm(self.request.GET, languages=dataset_languages) + + context['searchform'] = search_form + + multiple_select_gloss_fields = ['tags'] + context['MULTIPLE_SELECT_GLOSS_FIELDS'] = multiple_select_gloss_fields + + context['available_tags'] = [tag for tag in Tag.objects.all()] + + context['available_semanticfields'] = [semfield for semfield in SemanticField.objects.filter( + machine_value__gt=1).order_by('name')] + + context['available_handedness'] = [h for h in FieldChoice.objects.filter( + field='Handedness', machine_value__gt=1).order_by('name')] + + context['available_handshape'] = [wc for wc in Handshape.objects.filter( + machine_value__gt=1).order_by('name')] + + # data structures to store the query parameters in order to keep them in the form + context['query_parameters'] = json.dumps(self.query_parameters) + query_parameters_keys = list(self.query_parameters.keys()) + context['query_parameters_keys'] = json.dumps(query_parameters_keys) + + context['SHOW_DATASET_INTERFACE_OPTIONS'] = getattr(settings, 'SHOW_DATASET_INTERFACE_OPTIONS', False) + context['USE_REGULAR_EXPRESSIONS'] = getattr(settings, 'USE_REGULAR_EXPRESSIONS', False) + + # construct scroll bar + # the following retrieves language code for English (or DEFAULT LANGUAGE) + # so the sorting of the scroll bar matches the default sorting of the results in Gloss List View + + list_of_objects = self.object_list + + (interface_language, interface_language_code, + default_language, default_language_code) = get_interface_language_and_default_language_codes(self.request) + + dataset_display_languages = [] + for lang in dataset_languages: + dataset_display_languages.append(lang.language_code_2char) + if interface_language_code in dataset_display_languages: + lang_attr_name = interface_language_code + else: + lang_attr_name = default_language_code + + items = construct_scrollbar(list_of_objects, self.search_type, lang_attr_name) + self.request.session['search_results'] = items + + return context + + def get_queryset(self): + # this is a ListView for a complicated data structure + + selected_datasets = get_selected_datasets_for_user(self.request.user) + + if not selected_datasets or selected_datasets.count() > 1: + feedback_message = _('Please select a single dataset to use Batch Edit.') + messages.add_message(self.request, messages.ERROR, feedback_message) + # the query set is a list of tuples (gloss, keyword_translations, senses_groups) + return [] + + get = self.request.GET + + # multilingual + # this needs to be sorted for jquery purposes + dataset_languages = get_dataset_languages(selected_datasets).order_by('id') + + if get: + glosses_of_datasets = Gloss.none_morpheme_objects().filter(lemma__dataset__in=selected_datasets) + else: + recently_added_signs_since_date = DT.datetime.now(tz=get_current_timezone()) - RECENTLY_ADDED_SIGNS_PERIOD + glosses_of_datasets = Gloss.objects.filter(morpheme=None, lemma__dataset__in=selected_datasets).filter( + creationDate__range=[recently_added_signs_since_date, DT.datetime.now(tz=get_current_timezone())]).order_by( + 'creationDate') + + # data structure to store the query parameters in order to keep them in the form + query_parameters = dict() + + if 'tags[]' in get: + vals = get.getlist('tags[]') + if vals: + query_parameters['tags[]'] = vals + glosses_with_tag = list( + TaggedItem.objects.filter(tag__id__in=vals).values_list('object_id', flat=True)) + glosses_of_datasets = glosses_of_datasets.filter(id__in=glosses_with_tag) + if 'createdBy' in get and get['createdBy']: + get_value = get['createdBy'] + query_parameters['createdBy'] = get_value.strip() + created_by_search_string = ' '.join(get_value.strip().split()) # remove redundant spaces + glosses_of_datasets = glosses_of_datasets.annotate( + created_by=Concat('creator__first_name', V(' '), 'creator__last_name', output_field=CharField())) \ + .filter(created_by__icontains=created_by_search_string) + + # save the query parameters to a session variable + self.request.session['query_parameters'] = json.dumps(query_parameters) + self.request.session.modified = True + self.query_parameters = query_parameters + + return glosses_of_datasets + + class ToggleListView(ListView): model = Gloss diff --git a/signbank/dictionary/batch_edit.py b/signbank/dictionary/batch_edit.py new file mode 100644 index 000000000..d130c8ab5 --- /dev/null +++ b/signbank/dictionary/batch_edit.py @@ -0,0 +1,71 @@ +from django.core.exceptions import ObjectDoesNotExist + +from django.shortcuts import get_object_or_404 + +from django.contrib.auth.decorators import permission_required +from django.db import DatabaseError, IntegrityError +from django.db.transaction import TransactionManagementError + +from tagging.models import TaggedItem, Tag + +from signbank.dictionary.models import * +from signbank.dictionary.forms import * + + +def internal_batch_update_fields_for_gloss(gloss): + + languages = gloss.lemma.dataset.translation_languages + gloss_prefix = str(gloss.id) + '_' + gloss_suffix = '_' + str(gloss.id) + internal_batch_fields = [] + for language in languages: + gloss_lemma_field_name = BatchEditForm.gloss_lemma_field_prefix + gloss_prefix + language.language_code_2char + internal_batch_fields.append(gloss_lemma_field_name) + + for language in languages: + gloss_annotation_field_name = BatchEditForm.gloss_annotation_field_prefix + gloss_prefix + language.language_code_2char + internal_batch_fields.append(gloss_annotation_field_name) + + for language in languages: + gloss_sense_field_name = self.gloss_sense_field_prefix + gloss_prefix + language.language_code_2char + internal_batch_fields.append(gloss_sense_field_name) + + internal_batch_fields.append('handedness' + gloss_suffix) + internal_batch_fields.append('domhndsh' + gloss_suffix) + internal_batch_fields.append('subhndsh' + gloss_suffix) + + return internal_batch_fields + + +def get_sense_numbers(gloss): + senses_mapping = dict() + glosssenses = GlossSense.objects.filter(gloss=gloss).order_by('order') + languages = gloss.lemma.dataset.translation_languages.all() + if not glosssenses: + return [] + gloss_senses = dict() + for gs in glosssenses: + order = gs.order + sense = gs.sense + if order in gloss_senses.keys(): + continue + gloss_senses[order] = sense + for order, sense in gloss_senses.items(): + senses_mapping[order] = dict() + for language in languages: + sensetranslation = sense.senseTranslations.filter(language=language).first() + translations = sensetranslation.translations.all().order_by('index') if sensetranslation else [] + keywords_list = [translation.translation.text for translation in translations] + senses_mapping[order][language.language_code_2char] = ', '.join(keywords_list) + return senses_mapping + + +def batch_edit_update_gloss(request, glossid): + """Update the gloss fields""" + if not request.user.is_authenticated: + return {} + + if not request.user.has_perm('dictionary.change_gloss'): + return {} + + gloss = get_object_or_404(Gloss, id=glossid) diff --git a/signbank/dictionary/forms.py b/signbank/dictionary/forms.py index ad244a6dc..22415086c 100755 --- a/signbank/dictionary/forms.py +++ b/signbank/dictionary/forms.py @@ -1,17 +1,19 @@ from colorfield.fields import ColorWidget from django import forms -from django.core.exceptions import ValidationError +from django.core.exceptions import ValidationError, ObjectDoesNotExist + from django.utils.translation import override, gettext_lazy as _, get_language from django.db import OperationalError, ProgrammingError from django.db.transaction import atomic from signbank.video.fields import VideoUploadToFLVField -from signbank.dictionary.models import Dialect, Gloss, Morpheme, Definition, Relation, RelationToForeignSign, \ - MorphologyDefinition, OtherMedia, Handshape, SemanticField, DerivationHistory, \ - AnnotationIdglossTranslation, Dataset, FieldChoice, LemmaIdgloss, \ - LemmaIdglossTranslation, Translation, Keyword, Language, SignLanguage, \ - QueryParameterFieldChoice, SearchHistory, QueryParameter, \ - QueryParameterMultilingual, QueryParameterHandshape, SemanticFieldTranslation, \ - ExampleSentence, Affiliation, AffiliatedUser, AffiliatedGloss +from signbank.dictionary.models import (Dialect, Gloss, Morpheme, Definition, Relation, RelationToForeignSign, + MorphologyDefinition, OtherMedia, Handshape, SemanticField, DerivationHistory, + AnnotationIdglossTranslation, Dataset, FieldChoice, LemmaIdgloss, + LemmaIdglossTranslation, Translation, Keyword, Language, SignLanguage, + QueryParameterFieldChoice, SearchHistory, QueryParameter, + QueryParameterMultilingual, QueryParameterHandshape, SemanticFieldTranslation, + ExampleSentence, Affiliation, AffiliatedUser, AffiliatedGloss, GlossSense, + SenseTranslation) from signbank.dictionary.field_choices import fields_to_fieldcategory_dict from django.conf import settings from tagging.models import Tag @@ -52,7 +54,7 @@ class GlossCreateForm(forms.ModelForm): """Form for creating a new gloss from scratch""" gloss_create_field_prefix = "glosscreate_" - languages = None # Languages to use for annotation idgloss translations + languages = None # Languages to use for annotation idgloss translations user = None last_used_dataset = None @@ -1420,3 +1422,73 @@ def __init__(self, *args, **kwargs): choices=[(0, '-')], required=False, widget=Select2) self.fields['negative'].choices = [('0', '-'), ('yes', _('Yes')), ('no', _('No'))] + + +class BatchEditForm(forms.Form): + """Specify updates for Gloss fields""" + + languages = None # Languages to use for lemma, annotation translations + user = None + gloss = None + gloss_lemma_field_prefix = "lemma_" + gloss_annotation_field_prefix = "annotation_" + gloss_sense_field_prefix = "sense_" + + def __init__(self, queryDict, *args, **kwargs): + self.gloss = kwargs.pop('gloss') + self.languages = kwargs.pop('languages') + self.user = kwargs.pop('user') + + super(BatchEditForm, self).__init__(queryDict, *args, **kwargs) + + for language in self.languages: + gloss_lemma_field_name = self.gloss_lemma_field_prefix + language.language_code_2char + self.fields[gloss_lemma_field_name] = forms.CharField(label=_("Lemma")+(" (%s)" % language.name)) + if gloss_lemma_field_name in queryDict: + self.fields[gloss_lemma_field_name].value = queryDict[gloss_lemma_field_name] + + for language in self.languages: + gloss_annotation_field_name = self.gloss_annotation_field_prefix + language.language_code_2char + self.fields[gloss_annotation_field_name] = forms.CharField(label=_("Gloss")+(" (%s)" % language.name)) + if gloss_annotation_field_name in queryDict: + self.fields[gloss_annotation_field_name].value = queryDict[gloss_annotation_field_name] + + gloss_senses = GlossSense.objects.filter(gloss=self.gloss).order_by('order') + current_sense_numbers = [gs.order for gs in gloss_senses] + current_trans = [] + current_indices = [] + for gs in gloss_senses: + sense = gs.sense + for language in self.languages: + try: + sense_trans = sense.senseTranslations.get(language=language) + except ObjectDoesNotExist: + # there should only be one + sense_trans = SenseTranslation(language=language) + sense_trans.save() + sense.senseTranslations.add(sense_trans) + # the new sense translation object is empty + continue + for trans in sense_trans.translations.all().order_by('index'): + current_indices.append(trans.index) + current_trans.append(trans) + current_keywords = dict() + for order in current_sense_numbers: + current_keywords[order] = dict() + for language in self.languages: + current_keywords[order][language.id] = [t.translation.text for t in current_trans + if t.orderIndex == order and t.language == language] + + for language in self.languages: + gloss_sense_field_name = self.gloss_sense_field_prefix + language.language_code_2char + self.fields[gloss_sense_field_name] = forms.CharField(label=_("Sense") + (" (%s)" % language.name)) + if gloss_sense_field_name in queryDict: + self.fields[gloss_sense_field_name].value = queryDict[gloss_sense_field_name] + + @atomic + def save(self, commit=True): + + for field_key in self.instance.fields.keys(): + if self.instance.fields[field_key]: + print(self.instance.fields[field_key]) + diff --git a/signbank/dictionary/models.py b/signbank/dictionary/models.py index f4948da56..00623a6a4 100755 --- a/signbank/dictionary/models.py +++ b/signbank/dictionary/models.py @@ -1260,6 +1260,10 @@ def idgloss(self): except: return str(self.id) + def num_senses(self): + senses_for_this_gloss = GlossSense.objects.filter(gloss_pk=self.pk).count() + return senses_for_this_gloss + def reorder_senses(self): """when a sense is deleted, the senses should be reordered""" glosssenses_of_this_gloss = GlossSense.objects.filter(gloss=self).order_by('order') diff --git a/signbank/dictionary/templates/dictionary/admin_batch_edit_view.html b/signbank/dictionary/templates/dictionary/admin_batch_edit_view.html new file mode 100644 index 000000000..1cdfeda17 --- /dev/null +++ b/signbank/dictionary/templates/dictionary/admin_batch_edit_view.html @@ -0,0 +1,556 @@ +{% extends "baselayout.html" %} +{% load i18n %} +{% load stylesheet %} +{% load bootstrap3 %} +{% load tagging_tags %} + +{% load guardian_tags %} +{% load annotation_idgloss_translation %} + +{% block bootstrap3_title %} +{% blocktrans %}Signbank: Annotation Toggle View{% endblocktrans %} +{% endblock %} + +{% block extrajs %} + + + + + + + + + + + + +{% endblock %} + +{% block extrahead %} + + + +{% endblock %} + +{% block content %} + +
+ +
+

{% trans "Batch Edit View" %}

+

{% trans "On initial view, prior to searching, recently added glosses are shown below." %}

+ +
+
+ {% csrf_token %} +
+
{% trans "Construct Filter" %} +
+
+
+ + + +
+
{% trans "Search by Attributes" %}
+ + +
+
+
+ + +
+
+
+ +
+
+ +
+ + + + + + + + + + + + {% load underscore_to_space %} + {% for gloss in page_obj %} + + + + + + {% tags_for_object gloss as tag_list %} + + {% with gloss.semField.all as semantic_fields_list %} + + {% endwith %} + + + + + + {% endfor %} + +
{% trans "Gloss" %}{% trans "Fields" %}{% trans "Quick Toggles" %}{% trans "Tags" %}
{% if gloss.get_image_path %} + {% url 'dictionary:protected_media' '' as protected_media_url %} + + {% endif %} + + + + + + + + + + + + + + + +
+ + {{gloss|get_default_annotation_idgloss_translation}} +
+ {% load affiliation_tags %} + {% with gloss|get_affiliations_for_gloss as aff_list %} + {% if aff_list %} +
    + {% for aff in aff_list %} +
  • +
    + {{aff.acronym}} +
    +
  • +
+ {% endfor %} + {% endif %} + {% endwith %} +
+ {% for creator in gloss.creator.all %} + {% if forloop.last %} + {{creator.first_name}} {{creator.last_name}} + {% else %} + {{creator.first_name}} {{creator.last_name}}, + {% endif %} + {% endfor %} +
{{gloss.creationDate}}
+
+ + {% csrf_token %} + {% for dataset_lang in dataset_languages %} + {% with gloss.lemma|get_lemma_idgloss_translation:dataset_lang as lemmaidglosstranslation %} + + + + + {% endwith %} + {% endfor %} + {% for dataset_lang in dataset_languages %} + {% with gloss|get_annotation_idgloss_translation_no_default:dataset_lang as annotationidglosstranslation %} + + + + + {% endwith %} + {% endfor %} + {% with gloss|get_senses_mapping as senses_mapping %} + {% for order, translations in senses_mapping.items %} + {% for sense_lang, sensetranslation in translations.items %} + {% with sense_lang|upper as language %} + + + + + {% endwith %} + {% endfor %} + {% endfor %} + {% endwith %} + + + + + + + + + + + + + + + + + +
+ {% trans "Lemma" %} ({{dataset_lang.language_code_2char|upper}}) + + +
+ {% trans "Annotation" %} ({{dataset_lang.language_code_2char|upper}}) + + +
+ {% trans "Sense" %} #{{order}} ({{language}}) + + +
{% trans "Handedness" %} +
{% if gloss.handedness %}{{gloss.handedness.name}}{% endif %} +
+
{% trans "Sterke Hand" %} +
{% if gloss.domhndsh %}{{gloss.domhndsh.name}}{% endif %} +
+
+
+
+
+
{% trans "Tags" %} +
+
+
+ + {% for tag in available_tags %} + + {% endfor %} + +
+
+
+
+
{% trans "Handedness" %} +
+
+
+

+ {% for wc in available_handedness %} + + {% endfor %} +

+
+
+
+
+
{% trans "Sterke Hand" %} +
+
+
+

+ {% for wc in available_handshape %} + + {% endfor %} +

+
+
+
+
+
+
{% for tag in tag_list %}{{tag.name|underscore_to_space}} {% endfor %}
+
+
{% for sf in semantic_fields_list %}{{sf.name}} + {% if not forloop.last %}, {% endif %}{% endfor %} +
+
+ + + + + + + + +
+ {% trans "Similar Glosses" %} +
+ video + + gloss +
+
+
+
+ + +
+{% endblock content %} diff --git a/signbank/dictionary/templatetags/annotation_idgloss_translation.py b/signbank/dictionary/templatetags/annotation_idgloss_translation.py index 67caf65d6..661fe5586 100644 --- a/signbank/dictionary/templatetags/annotation_idgloss_translation.py +++ b/signbank/dictionary/templatetags/annotation_idgloss_translation.py @@ -1,6 +1,8 @@ from django.template import Library from signbank.dictionary.forms import GlossSearchForm, MorphemeSearchForm from signbank.tools import get_default_annotationidglosstranslation +from signbank.dictionary.batch_edit import get_sense_numbers + import json register = Library() @@ -62,7 +64,7 @@ def display_language(gloss,interface_language): @register.filter def get_lemma_idgloss_translation(lemma, language): lemmaidglosstranslations = lemma.lemmaidglosstranslation_set.filter(language=language) - if lemmaidglosstranslations is not None and len(lemmaidglosstranslations) > 0: + if lemmaidglosstranslations: return lemmaidglosstranslations.first().text return "" @@ -199,6 +201,13 @@ def translated_annotationidgloss(gloss, language_code): annotationidgloss = gloss.annotation_idgloss(language_code) return annotationidgloss +@register.filter +def get_senses_mapping(gloss): + + senses_mapping = get_sense_numbers(gloss) + return senses_mapping + + @register.filter def get_senses_for_language(sensetranslations, language): if language not in sensetranslations.keys(): diff --git a/signbank/dictionary/update.py b/signbank/dictionary/update.py index c6381325a..0f09ac49e 100755 --- a/signbank/dictionary/update.py +++ b/signbank/dictionary/update.py @@ -36,8 +36,8 @@ mapping_edit_senses_matrix, mapping_toggle_sense_tag from signbank.dictionary.consistency_senses import reorder_translations from signbank.dictionary.related_objects import gloss_related_objects, morpheme_related_objects -from signbank.dictionary.update_glosses import mapping_toggle_tag, mapping_toggle_semanticfield, \ - mapping_toggle_wordclass, mapping_toggle_namedentity +from signbank.dictionary.update_glosses import (mapping_toggle_tag, mapping_toggle_semanticfield, + mapping_toggle_wordclass, mapping_toggle_namedentity, mapping_toggle_handedness, mapping_toggle_domhndsh) def show_error(request, translated_message, form, dataset_languages): @@ -3517,6 +3517,34 @@ def toggle_namedentity(request, glossid, namedentity): return JsonResponse(result) +@permission_required('dictionary.change_gloss') +def toggle_handedness(request, glossid, handedness): + print('toggle handedness') + if not request.user.is_authenticated: + return JsonResponse({}) + + if not request.user.has_perm('dictionary.change_gloss'): + return JsonResponse({}) + + result = mapping_toggle_handedness(request, glossid, handedness) + + return JsonResponse(result) + + +@permission_required('dictionary.change_gloss') +def toggle_domhndsh(request, glossid, domhndsh): + print('toggle domhndsh') + if not request.user.is_authenticated: + return JsonResponse({}) + + if not request.user.has_perm('dictionary.change_gloss'): + return JsonResponse({}) + + result = mapping_toggle_domhndsh(request, glossid, domhndsh) + + return JsonResponse(result) + + @permission_required('dictionary.change_gloss') def add_affiliation(request, glossid): """View to add an affiliation to a gloss""" diff --git a/signbank/dictionary/update_glosses.py b/signbank/dictionary/update_glosses.py index 191c47459..6dd238caa 100644 --- a/signbank/dictionary/update_glosses.py +++ b/signbank/dictionary/update_glosses.py @@ -211,3 +211,100 @@ def mapping_toggle_namedentity(request, glossid, namedentity): result['namedentity'] = newvalue return result + + +@permission_required('dictionary.change_gloss') +def mapping_toggle_handedness(request, glossid, handedness): + if not request.user.is_authenticated: + return {} + + if not request.user.has_perm('dictionary.change_gloss'): + return {} + + try: + gloss_id = int(glossid) + except TypeError: + return {} + + gloss = Gloss.objects.filter(id=gloss_id).first() + + if not gloss: + return {} + + try: + handedness_machine_value = int(handedness) + except TypeError: + return {} + + empty_handedness = FieldChoice.objects.get(field='Handedness', machine_value=0) + new_handedness = FieldChoice.objects.filter(field='Handedness', machine_value=handedness_machine_value).first() + + if not new_handedness: + # if the word class does not exist, set it to empty + handedness_machine_value = 0 + new_handedness = empty_handedness + + with atomic(): + if not gloss.handedness: + gloss.handedness = new_handedness + elif gloss.handedness.machine_value != handedness_machine_value: + gloss.handedness = new_handedness + else: + gloss.handedness = empty_handedness + gloss.save() + + result = dict() + result['glossid'] = str(gloss.id) + newvalue = gloss.handedness.name + result['handedness'] = newvalue + + return result + + +@permission_required('dictionary.change_gloss') +def mapping_toggle_domhndsh(request, glossid, domhndsh): + if not request.user.is_authenticated: + return {} + + if not request.user.has_perm('dictionary.change_gloss'): + return {} + + try: + gloss_id = int(glossid) + except TypeError: + return {} + + gloss = Gloss.objects.filter(id=gloss_id).first() + + if not gloss: + return {} + + try: + domhndsh_machine_value = int(domhndsh) + except TypeError: + return {} + + empty_domhndsh = Handshape.objects.get(machine_value=0) + new_domhndsh = Handshape.objects.filter(machine_value=domhndsh_machine_value).first() + + if not new_domhndsh: + # if the word class does not exist, set it to empty + domhndsh_machine_value = 0 + new_domhndsh = empty_domhndsh + + with atomic(): + if not gloss.domhndsh: + gloss.domhndsh = new_domhndsh + elif gloss.domhndsh.machine_value != domhndsh_machine_value: + gloss.domhndsh = new_domhndsh + else: + gloss.domhndsh = empty_domhndsh + gloss.save() + + result = dict() + result['glossid'] = str(gloss.id) + newvalue = gloss.domhndsh.name + result['domhndsh'] = newvalue + + return result + diff --git a/signbank/dictionary/urls.py b/signbank/dictionary/urls.py index 6b84af2d7..2b93e345b 100755 --- a/signbank/dictionary/urls.py +++ b/signbank/dictionary/urls.py @@ -89,6 +89,12 @@ re_path(r'^update/toggle_namedentity/(?P\d+)/(?P.*)$', signbank.dictionary.update.toggle_namedentity, name='toggle_namedentity'), + re_path(r'^update/toggle_handedness/(?P\d+)/(?P.*)$', + signbank.dictionary.update.toggle_handedness, + name='toggle_handedness'), + re_path(r'^update/toggle_domhndsh/(?P\d+)/(?P.*)$', + signbank.dictionary.update.toggle_domhndsh, + name='toggle_domhndsh'), # The next one does not have a permission check because it should be accessible from a cronjob re_path(r'^update_ecv/', GlossListView.as_view(only_export_ecv=True)), diff --git a/signbank/urls.py b/signbank/urls.py index a15b43c7a..e1ba011f8 100755 --- a/signbank/urls.py +++ b/signbank/urls.py @@ -26,7 +26,7 @@ dataset_detail_view_by_acronym, FieldChoiceView, DatasetFrequencyView, QueryListView, SemanticFieldListView, DerivationHistoryListView, SearchHistoryView, SenseListView, LemmaListView, ToggleListView, - DatasetMediaView) + DatasetMediaView, BatchEditView) from signbank.dictionary.views import add_image, delete_image, add_new_morpheme, add_handshape_image from django.contrib import admin @@ -82,6 +82,7 @@ re_path(r'^analysis/queries/$', QueryListView.as_view(), name='admin_query_list'), re_path(r'^analysis/search_history/$', SearchHistoryView.as_view(), name='admin_search_history'), re_path(r'^analysis/toggle_view/$', ToggleListView.as_view(), name='admin_toggle_list'), + re_path(r'^analysis/batch_edit_view/$', BatchEditView.as_view(), name='admin_batch_edit_view'), re_path(r'^signs/recently_added/$', login_required(signbank.dictionary.views.recently_added_glosses), name='recently_added_glosses'),