Commit 816b5bed1645ea179a72a901bb7a8cff195ece72

Authored by Marcel Kawski
1 parent f38c6209

Change "name" field constraint, add moving sudocuments and fix bug when splittin…

…g document after deleting one with smaller sequence
collector/storage/models.py
... ... @@ -3,6 +3,7 @@ import os
3 3 from django.contrib.postgres.fields import ArrayField, JSONField
4 4 from django.contrib.auth import get_user_model
5 5 from django.db import models
  6 +from django.db.models import UniqueConstraint
6 7 from partial_date import PartialDateField
7 8 from languages.fields import LanguageField
8 9  
... ... @@ -12,7 +13,7 @@ User = get_user_model()
12 13  
13 14  
14 15 class Document(models.Model):
15   - name = models.TextField(unique=True)
  16 + name = models.TextField()
16 17 source_id = models.CharField(max_length=32)
17 18 lang = models.CharField(max_length=5)
18 19 original_lang = LanguageField()
... ... @@ -144,6 +145,9 @@ class Document(models.Model):
144 145 class Meta:
145 146 db_table = 'document'
146 147 ordering = ['id']
  148 + constraints = [
  149 + models.UniqueConstraint(fields=['name', 'sequence'], name='unique subdocument sequence')
  150 + ]
147 151  
148 152 def __str__(self):
149 153 return str(self.id) + '-' + self.name
... ...
collector/storage/static/storage/css/document.css
... ... @@ -161,6 +161,10 @@ a.nav-button:hover {
161 161 color: #ffcd00;
162 162 }
163 163  
  164 +.arrow:hover {
  165 + color: #ff6600;
  166 +}
  167 +
164 168 .col-actions {
165 169 width: 5%;
166 170 }
... ...
collector/storage/templates/storage/annotation.html
... ... @@ -108,12 +108,18 @@
108 108 <tbody>
109 109 {% for subdocument in subdocuments %}
110 110 <tr>
111   - <td><a href="{% url 'annotation' subdocument.id %}">{{ subdocument.name }}</a></td>
  111 + <td><a href="{% url 'annotation' subdocument.id %}">{{ subdocument.name }}-{{ subdocument.id }}</a></td>
112 112 <td>{{ subdocument.sequence }}</td>
113 113 <td class="actions">
114 114 {% if user.is_authenticated %}
115   - <i class="material-icons button" title="Edytuj">edit</i>
116   - <i class="material-icons button" title="Usuń">delete</i>
  115 + <a class="button"
  116 + href="{% url 'move_subdoc' subdocument.id 'up' %}">
  117 + <i class="material-icons button arrow" title="Przesuń w górę">arrow_drop_up</i>
  118 + </a>
  119 + <a class="button"
  120 + href="{% url 'move_subdoc' subdocument.id 'down' %}">
  121 + <i class="material-icons button arrow" title="Przesuń w dół">arrow_drop_down</i>
  122 + </a>
117 123 {% endif %}
118 124 </td>
119 125 </tr>
... ...
collector/storage/urls.py
... ... @@ -40,7 +40,8 @@ urlpatterns = [
40 40 path('keyword/add/<str:doc_id>', login_required(views.add_keyword), name='add_keyword'),
41 41 path('keyword/edit/<str:doc_id>/<int:pk>', login_required(views.edit_keyword), name='edit_keyword'),
42 42 path('keyword/delete/<str:doc_id>/<int:pk>', login_required(views.delete_keyword), name='delete_keyword'),
43   - path('split-doc/<str:doc_id>/', login_required(views.split_doc), name='split_doc'),
  43 + path('split-doc/<str:doc_id>', login_required(views.split_doc), name='split_doc'),
  44 + path('move-subdoc/<str:subdoc_id>/<str:direction>', login_required(views.move_subdoc), name='move_subdoc'),
44 45 path('revert-subdoc-division/<int:pk>/', login_required(views.RevertSubdocDivisionView.as_view()),
45 46 name='revert_subdoc_division'),
46 47 path('md-name-autocomplete/', views.md_name_autocomplete, name='md_name_autocomplete'),
... ...
collector/storage/views.py
... ... @@ -16,6 +16,7 @@ from django.db.models import Q
16 16 from django.template.loader import render_to_string
17 17  
18 18 from keras import backend
  19 +from sys import maxsize
19 20  
20 21 from .forms import ChunkForm, ParticipantForm, SubchunkForm, MetadataForm, DocDetailsForm, KeywordForm, DocSplitForm, \
21 22 MoveChunkForm, SubDocDetailsForm, AuthorForm
... ... @@ -526,7 +527,7 @@ class AnnotationView(View):
526 527 context = {'document': None}
527 528 try:
528 529 doc = Document.objects.get(id=doc_id)
529   - subdocuments = Document.objects.filter(parent=doc)
  530 + subdocuments = Document.objects.filter(parent=doc).order_by('sequence')
530 531 metadata = doc.metadata.order_by('sequence')
531 532 chunks = doc.chunks.order_by('sequence')
532 533 keywords = doc.keywords.all()
... ... @@ -830,7 +831,7 @@ def split_doc(request, doc_id):
830 831 parent = document
831 832 else:
832 833 parent = document.parent
833   - new_document = Document.objects.create(name=parent.name + f'_text-{sequence + 1}',
  834 + new_document = Document.objects.create(name=parent.name,
834 835 lang=parent.lang,
835 836 original_lang=parent.original_lang,
836 837 pipeline=parent.pipeline,
... ... @@ -841,7 +842,7 @@ def split_doc(request, doc_id):
841 842 status=parent.status,
842 843 parent=parent,
843 844 processing_status=parent.processing_status,
844   - sequence=sequence+1)
  845 + sequence=sequence + 1)
845 846 new_document.chunks.set(chunks.filter(sequence__range=(chunk_beg, chunk_end)))
846 847 new_document.save()
847 848 document.chunks.set(chunks.filter(sequence__lt=chunk_beg) | chunks.filter(sequence__gt=chunk_end))
... ... @@ -855,6 +856,37 @@ def split_doc(request, doc_id):
855 856 'submit_btn_text': 'Podziel'})
856 857  
857 858  
  859 +def swap_subdocs(direction, subdoc, subdoc_seq, temp_seq, max_seq):
  860 + sign = None
  861 + if direction == 'up' and subdoc_seq > 1:
  862 + sign = '-'
  863 + elif direction == 'down' and subdoc_seq < max_seq:
  864 + sign = '+'
  865 + if sign is not None:
  866 + neighbour = Document.objects.get(sequence=eval(f'{str(subdoc_seq)} {sign} 1'))
  867 + neighbour.sequence = temp_seq
  868 + neighbour.save()
  869 + subdoc.sequence = eval(f'{str(subdoc_seq)} {sign} 1')
  870 + subdoc.save()
  871 + neighbour.sequence = subdoc_seq
  872 + neighbour.save()
  873 +
  874 +
  875 +def move_subdoc(request, subdoc_id, direction):
  876 + subdoc = Document.objects.get(id=subdoc_id)
  877 + subdoc_seq = subdoc.sequence
  878 + parent_doc = Document.objects.get(id=subdoc_id).parent
  879 + max_seq_doc = Document.objects.filter(parent=parent_doc).order_by('-sequence').first()
  880 + if max_seq_doc is not None:
  881 + max_seq = max_seq_doc.sequence
  882 + temp_seq = max_seq + 10
  883 + else:
  884 + max_seq = 0
  885 + temp_seq = 10
  886 + swap_subdocs(direction, subdoc, subdoc_seq, temp_seq, max_seq)
  887 + return HttpResponseRedirect(reverse('annotation', kwargs={'doc_id': parent_doc.id}))
  888 +
  889 +
858 890 class RevertSubdocDivisionView(DeleteView):
859 891 model = Document
860 892 template_name = 'storage/delete.html'
... ...