sorting of motion comment sections

This commit is contained in:
FinnStutzenstein 2019-07-19 13:43:33 +02:00
parent 8cb9892426
commit 74647dc75d
8 changed files with 151 additions and 2 deletions

View File

@ -54,6 +54,14 @@ export class MotionCommentSectionRepositoryService extends BaseRepository<
private http: HttpService
) {
super(DS, dataSend, mapperService, viewModelStoreService, translate, MotionCommentSection, [Group]);
this.viewModelSortFn = (a: ViewMotionCommentSection, b: ViewMotionCommentSection) => {
if (a.weight === b.weight) {
return a.id - b.id;
} else {
return a.weight - b.weight;
}
};
}
public getTitle = (titleInformation: MotionCommentSectionTitleInformation) => {
@ -109,4 +117,13 @@ export class MotionCommentSectionRepositoryService extends BaseRepository<
private async deleteComment(motion: ViewMotion, section: ViewMotionCommentSection): Promise<void> {
return await this.http.delete(`/rest/motions/motion/${motion.id}/manage_comments/`, { section_id: section.id });
}
/**
* Sort all comment sections. All sections must be given excatly once.
*/
public async sortCommentSections(sections: ViewMotionCommentSection[]): Promise<void> {
return await this.http.post('/rest/motions/motion-comment-section', {
ids: sections.map(section => section.id)
});
}
}

View File

@ -11,6 +11,7 @@ export class MotionCommentSection extends BaseModel<MotionCommentSection> {
public name: string;
public read_groups_id: number[];
public write_groups_id: number[];
public weight: number;
public constructor(input?: any) {
super(MotionCommentSection.COLLECTIONSTRING, input);

View File

@ -48,6 +48,10 @@ export class ViewMotionCommentSection extends BaseViewModel<MotionCommentSection
return this._writeGroups;
}
public get weight(): number {
return this.section.weight;
}
/**
* TODO: Where is this needed? Try to avoid this.
*/

View File

@ -0,0 +1,16 @@
# Generated by Django 2.2.3 on 2019-07-19 10:52
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [("motions", "0028_subcategories")]
operations = [
migrations.AddField(
model_name="motioncommentsection",
name="weight",
field=models.IntegerField(default=10000),
)
]

View File

@ -583,6 +583,11 @@ class MotionCommentSection(RESTModelMixin, models.Model):
These groups have write-access to the section.
"""
weight = models.IntegerField(default=10000)
"""
To sort comment sections.
"""
class Meta:
default_permissions = ()

View File

@ -373,7 +373,8 @@ class MotionCommentSectionSerializer(ModelSerializer):
class Meta:
model = MotionCommentSection
fields = ("id", "name", "read_groups", "write_groups")
fields = ("id", "name", "read_groups", "write_groups", "weight")
read_only_fields = ("weight",)
def create(self, validated_data):
""" Call inform_changed_data on creation, so the cache includes the groups. """

View File

@ -4,6 +4,7 @@ import jsonschema
from django.contrib.auth import get_user_model
from django.core.exceptions import ValidationError as DjangoValidationError
from django.db import transaction
from django.db.models import Case, When
from django.db.models.deletion import ProtectedError
from django.http.request import QueryDict
from rest_framework import status
@ -1228,7 +1229,7 @@ class MotionCommentSectionViewSet(ModelViewSet):
"""
if self.action in ("list", "retrieve"):
result = self.get_access_permissions().check_permissions(self.request.user)
elif self.action in ("create", "destroy", "update", "partial_update"):
elif self.action in ("create", "destroy", "update", "partial_update", "sort"):
result = has_perm(self.request.user, "motions.can_see") and has_perm(
self.request.user, "motions.can_manage"
)
@ -1268,6 +1269,39 @@ class MotionCommentSectionViewSet(ModelViewSet):
inform_changed_data(MotionComment.objects.filter(section=section))
return response
@list_route(methods=["post"])
def sort(self, request, *args, **kwargs):
"""
Changes the sorting of comment sections. Every id must be given exactly once.
Expected data: { ids: [<id>, <id>, ...] }
"""
# Check request data format
ids = request.data.get("ids")
if not isinstance(ids, list):
raise ValidationError({"detail": "ids must be a list"})
for id in ids:
if not isinstance(id, int):
raise ValidationError({"detail": "every id must be an int"})
# Validate, that every id is given exactly once.
ids_set = set(ids)
if len(ids_set) != len(ids):
raise ValidationError({"detail": "only unique ids are expected"})
db_ids_set = set(
list(MotionCommentSection.objects.all().values_list(flat=True))
)
if ids_set != db_ids_set:
raise ValidationError({"detail": "every id must be given"})
# Ids are ok.
preserved = Case(*[When(pk=pk, then=pos) for pos, pk in enumerate(ids)])
queryset = MotionCommentSection.objects.filter(pk__in=ids).order_by(preserved)
for index, section in enumerate(queryset):
section.weight = index + 1
section.save()
return Response()
class StatuteParagraphViewSet(ModelViewSet):
"""

View File

@ -1331,6 +1331,77 @@ class TestMotionCommentSection(TestCase):
self.assertEqual(MotionCommentSection.objects.count(), 1)
class TestMotionCommentSectionSorting(TestCase):
"""
Tests sorting of comment sections.
"""
def setUp(self):
self.client = APIClient()
self.client.login(username="admin", password="admin")
self.section1 = MotionCommentSection(name="test_name_hponzp<zp7NUJKLAykbX")
self.section1.save()
self.section2 = MotionCommentSection(name="test_name_eix,b<bojbP'JO;<kVKL")
self.section2.save()
self.section3 = MotionCommentSection(name="test_name_ojMOeigSIOfhmpouweqc")
self.section3.save()
def test_simple(self):
response = self.client.post(
reverse("motioncommentsection-sort"), {"ids": [3, 2, 1]}, format="json"
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
section1 = MotionCommentSection.objects.get(pk=1)
self.assertEqual(section1.weight, 3)
section2 = MotionCommentSection.objects.get(pk=2)
self.assertEqual(section2.weight, 2)
section3 = MotionCommentSection.objects.get(pk=3)
self.assertEqual(section3.weight, 1)
def test_wrong_data(self):
response = self.client.post(
reverse("motioncommentsection-sort"), {"ids": "some_string"}, format="json"
)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assert_not_changed()
def test_wrong_id_type(self):
response = self.client.post(
reverse("motioncommentsection-sort"),
{"ids": [1, 2, "some_string"]},
format="json",
)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assert_not_changed()
def test_missing_id(self):
response = self.client.post(
reverse("motioncommentsection-sort"), {"ids": [3, 1]}, format="json"
)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assert_not_changed()
def test_duplicate_id(self):
response = self.client.post(
reverse("motioncommentsection-sort"), {"ids": [3, 2, 1, 1]}, format="json"
)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assert_not_changed()
def test_wrong_id(self):
response = self.client.post(
reverse("motioncommentsection-sort"), {"ids": [3, 4, 1]}, format="json"
)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assert_not_changed()
def assert_not_changed(self):
""" Asserts, that every comment section has the default weight of 10000. """
for section in MotionCommentSection.objects.all():
self.assertEqual(section.weight, 10000)
class RetrieveMotionChangeRecommendation(TestCase):
"""
Tests retrieving motion change recommendations.