diff --git a/client/src/app/core/repositories/motions/motion-comment-section-repository.service.ts b/client/src/app/core/repositories/motions/motion-comment-section-repository.service.ts index a0c528341..dc57fdfa7 100644 --- a/client/src/app/core/repositories/motions/motion-comment-section-repository.service.ts +++ b/client/src/app/core/repositories/motions/motion-comment-section-repository.service.ts @@ -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 { 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 { + return await this.http.post('/rest/motions/motion-comment-section', { + ids: sections.map(section => section.id) + }); + } } diff --git a/client/src/app/shared/models/motions/motion-comment-section.ts b/client/src/app/shared/models/motions/motion-comment-section.ts index 0e4a3d304..715cee484 100644 --- a/client/src/app/shared/models/motions/motion-comment-section.ts +++ b/client/src/app/shared/models/motions/motion-comment-section.ts @@ -11,6 +11,7 @@ export class MotionCommentSection extends BaseModel { public name: string; public read_groups_id: number[]; public write_groups_id: number[]; + public weight: number; public constructor(input?: any) { super(MotionCommentSection.COLLECTIONSTRING, input); diff --git a/client/src/app/site/motions/models/view-motion-comment-section.ts b/client/src/app/site/motions/models/view-motion-comment-section.ts index d14b2a7f1..6de22db6f 100644 --- a/client/src/app/site/motions/models/view-motion-comment-section.ts +++ b/client/src/app/site/motions/models/view-motion-comment-section.ts @@ -48,6 +48,10 @@ export class ViewMotionCommentSection extends BaseViewModel, , ...] } + """ + # 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): """ diff --git a/tests/integration/motions/test_viewset.py b/tests/integration/motions/test_viewset.py index 2e60d00e2..7fccf8487 100644 --- a/tests/integration/motions/test_viewset.py +++ b/tests/integration/motions/test_viewset.py @@ -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