Skip to content

Commit

Permalink
#1268: Initial Batch Edit View.
Browse files Browse the repository at this point in the history
  • Loading branch information
susanodd committed Jun 22, 2024
1 parent f93d865 commit d672e5a
Show file tree
Hide file tree
Showing 11 changed files with 1,033 additions and 13 deletions.
53 changes: 53 additions & 0 deletions media/js/glosses_toggle_edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 = "<span class='handedness'>"+handedness+"</span>";
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 = "<span class='domhndsh'>"+domhndsh+"</span>";
hCell.html(cell);
}

$(document).ready(function() {

// setup required for Ajax POST
Expand Down Expand Up @@ -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
});
});

});
123 changes: 123 additions & 0 deletions signbank/dictionary/adminviews.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
71 changes: 71 additions & 0 deletions signbank/dictionary/batch_edit.py
Original file line number Diff line number Diff line change
@@ -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)
90 changes: 81 additions & 9 deletions signbank/dictionary/forms.py
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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])

4 changes: 4 additions & 0 deletions signbank/dictionary/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down
Loading

0 comments on commit d672e5a

Please sign in to comment.