Merge pull request #4636 from FinnStutzenstein/assignmentAttachments
Add attachments to assignments
This commit is contained in:
commit
3dd659ae36
@ -42,7 +42,10 @@ export class ViewModelStoreService {
|
|||||||
* @param collectionType The collection of the view model
|
* @param collectionType The collection of the view model
|
||||||
* @param ids All ids to match
|
* @param ids All ids to match
|
||||||
*/
|
*/
|
||||||
public getMany<T extends BaseViewModel>(collectionType: ViewModelConstructor<T> | string, ids: number[]): T[] {
|
public getMany<T extends BaseViewModel>(collectionType: ViewModelConstructor<T> | string, ids?: number[]): T[] {
|
||||||
|
if (!ids) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
const repository = this.getRepository<T>(collectionType);
|
const repository = this.getRepository<T>(collectionType);
|
||||||
|
|
||||||
return ids
|
return ids
|
||||||
|
@ -21,6 +21,8 @@ import { ViewUser } from 'app/site/users/models/view-user';
|
|||||||
import { ViewAssignmentRelatedUser } from 'app/site/assignments/models/view-assignment-related-user';
|
import { ViewAssignmentRelatedUser } from 'app/site/assignments/models/view-assignment-related-user';
|
||||||
import { ViewAssignmentPoll } from 'app/site/assignments/models/view-assignment-poll';
|
import { ViewAssignmentPoll } from 'app/site/assignments/models/view-assignment-poll';
|
||||||
import { ViewAssignmentPollOption } from 'app/site/assignments/models/view-assignment-poll-option';
|
import { ViewAssignmentPollOption } from 'app/site/assignments/models/view-assignment-poll-option';
|
||||||
|
import { ViewMediafile } from 'app/site/mediafiles/models/view-mediafile';
|
||||||
|
import { Mediafile } from 'app/shared/models/mediafiles/mediafile';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Repository Service for Assignments.
|
* Repository Service for Assignments.
|
||||||
@ -56,7 +58,7 @@ export class AssignmentRepositoryService extends BaseAgendaContentObjectReposito
|
|||||||
protected translate: TranslateService,
|
protected translate: TranslateService,
|
||||||
private httpService: HttpService
|
private httpService: HttpService
|
||||||
) {
|
) {
|
||||||
super(DS, dataSend, mapperService, viewModelStoreService, translate, Assignment, [User, Item, Tag]);
|
super(DS, dataSend, mapperService, viewModelStoreService, translate, Assignment, [User, Item, Tag, Mediafile]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getAgendaTitle = (assignment: Partial<Assignment> | Partial<ViewAssignment>) => {
|
public getAgendaTitle = (assignment: Partial<Assignment> | Partial<ViewAssignment>) => {
|
||||||
@ -74,6 +76,7 @@ export class AssignmentRepositoryService extends BaseAgendaContentObjectReposito
|
|||||||
public createViewModel(assignment: Assignment): ViewAssignment {
|
public createViewModel(assignment: Assignment): ViewAssignment {
|
||||||
const agendaItem = this.viewModelStoreService.get(ViewItem, assignment.agenda_item_id);
|
const agendaItem = this.viewModelStoreService.get(ViewItem, assignment.agenda_item_id);
|
||||||
const tags = this.viewModelStoreService.getMany(ViewTag, assignment.tags_id);
|
const tags = this.viewModelStoreService.getMany(ViewTag, assignment.tags_id);
|
||||||
|
const attachments = this.viewModelStoreService.getMany(ViewMediafile, assignment.attachments_id);
|
||||||
const assignmentRelatedUsers = this.createViewAssignmentRelatedUsers(assignment.assignment_related_users);
|
const assignmentRelatedUsers = this.createViewAssignmentRelatedUsers(assignment.assignment_related_users);
|
||||||
const assignmentPolls = this.createViewAssignmentPolls(assignment.polls);
|
const assignmentPolls = this.createViewAssignmentPolls(assignment.polls);
|
||||||
|
|
||||||
@ -82,7 +85,8 @@ export class AssignmentRepositoryService extends BaseAgendaContentObjectReposito
|
|||||||
assignmentRelatedUsers,
|
assignmentRelatedUsers,
|
||||||
assignmentPolls,
|
assignmentPolls,
|
||||||
agendaItem,
|
agendaItem,
|
||||||
tags
|
tags,
|
||||||
|
attachments
|
||||||
);
|
);
|
||||||
viewAssignment.getVerboseName = this.getVerboseName;
|
viewAssignment.getVerboseName = this.getVerboseName;
|
||||||
viewAssignment.getAgendaTitle = () => this.getAgendaTitle(viewAssignment);
|
viewAssignment.getAgendaTitle = () => this.getAgendaTitle(viewAssignment);
|
||||||
|
@ -19,6 +19,7 @@ export class Assignment extends BaseModel<Assignment> {
|
|||||||
public polls: AssignmentPoll[];
|
public polls: AssignmentPoll[];
|
||||||
public agenda_item_id: number;
|
public agenda_item_id: number;
|
||||||
public tags_id: number[];
|
public tags_id: number[];
|
||||||
|
public attachments_id: number[];
|
||||||
|
|
||||||
public constructor(input?: any) {
|
public constructor(input?: any) {
|
||||||
super(Assignment.COLLECTIONSTRING, input);
|
super(Assignment.COLLECTIONSTRING, input);
|
||||||
|
@ -40,10 +40,9 @@
|
|||||||
<span translate>Attachments</span>:
|
<span translate>Attachments</span>:
|
||||||
<mat-list dense>
|
<mat-list dense>
|
||||||
<mat-list-item *ngFor="let file of topic.attachments">
|
<mat-list-item *ngFor="let file of topic.attachments">
|
||||||
<a [routerLink]="file.downloadUrl" target="_blank">{{ file.title }}</a>
|
<a [routerLink]="file.downloadUrl" target="_blank">{{ file.getTitle() }}</a>
|
||||||
</mat-list-item>
|
</mat-list-item>
|
||||||
</mat-list>
|
</mat-list>
|
||||||
<!-- TODO: Mediafiles and attachments are not fully implemented -->
|
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -98,6 +98,14 @@
|
|||||||
</button>
|
</button>
|
||||||
</mat-menu>
|
</mat-menu>
|
||||||
</div>
|
</div>
|
||||||
|
<div *ngIf="assignment.attachments.length">
|
||||||
|
<span translate>Election documents</span>:
|
||||||
|
<mat-list dense>
|
||||||
|
<mat-list-item *ngFor="let file of assignment.attachments">
|
||||||
|
<a [routerLink]="file.downloadUrl" target="_blank">{{ file.getTitle() }}</a>
|
||||||
|
</mat-list-item>
|
||||||
|
</mat-list>
|
||||||
|
</div>
|
||||||
</mat-card>
|
</mat-card>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
|
||||||
@ -214,6 +222,7 @@
|
|||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</div>
|
</div>
|
||||||
<h4 translate>Description:</h4>
|
<h4 translate>Description:</h4>
|
||||||
|
|
||||||
<!-- description: HTML Editor -->
|
<!-- description: HTML Editor -->
|
||||||
<editor
|
<editor
|
||||||
formControlName="description"
|
formControlName="description"
|
||||||
@ -221,6 +230,7 @@
|
|||||||
*ngIf="assignment && editAssignment"
|
*ngIf="assignment && editAssignment"
|
||||||
required
|
required
|
||||||
></editor>
|
></editor>
|
||||||
|
|
||||||
<!-- searchValueSelector: tags -->
|
<!-- searchValueSelector: tags -->
|
||||||
<div class="content-field" *ngIf="tagsAvailable">
|
<div class="content-field" *ngIf="tagsAvailable">
|
||||||
<os-search-value-selector
|
<os-search-value-selector
|
||||||
@ -234,6 +244,18 @@
|
|||||||
></os-search-value-selector>
|
></os-search-value-selector>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Attachments -->
|
||||||
|
<div class="content-field" *ngIf="mediafilesAvailable">
|
||||||
|
<os-search-value-selector
|
||||||
|
ngDefaultControl
|
||||||
|
[form]="assignmentForm"
|
||||||
|
[formControl]="assignmentForm.get('attachments_id')"
|
||||||
|
[multiple]="true"
|
||||||
|
listname="{{ 'Election documents' | translate }}"
|
||||||
|
[InputListValues]="mediafilesObserver"
|
||||||
|
></os-search-value-selector>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- searchValueSelector: agendaItem -->
|
<!-- searchValueSelector: agendaItem -->
|
||||||
<div class="content-field" *ngIf="parentsAvailable">
|
<div class="content-field" *ngIf="parentsAvailable">
|
||||||
<os-search-value-selector
|
<os-search-value-selector
|
||||||
@ -258,6 +280,7 @@
|
|||||||
/>
|
/>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- open posts: number -->
|
<!-- open posts: number -->
|
||||||
<div>
|
<div>
|
||||||
<mat-form-field>
|
<mat-form-field>
|
||||||
|
@ -25,6 +25,8 @@ import { ViewItem } from 'app/site/agenda/models/view-item';
|
|||||||
import { ViewportService } from 'app/core/ui-services/viewport.service';
|
import { ViewportService } from 'app/core/ui-services/viewport.service';
|
||||||
import { ViewTag } from 'app/site/tags/models/view-tag';
|
import { ViewTag } from 'app/site/tags/models/view-tag';
|
||||||
import { ViewUser } from 'app/site/users/models/view-user';
|
import { ViewUser } from 'app/site/users/models/view-user';
|
||||||
|
import { ViewMediafile } from 'app/site/mediafiles/models/view-mediafile';
|
||||||
|
import { MediafileRepositoryService } from 'app/core/repositories/mediafiles/mediafile-repository.service';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component for the assignment detail view
|
* Component for the assignment detail view
|
||||||
@ -77,6 +79,11 @@ export class AssignmentDetailComponent extends BaseViewComponent implements OnIn
|
|||||||
*/
|
*/
|
||||||
public tagsObserver: BehaviorSubject<ViewTag[]>;
|
public tagsObserver: BehaviorSubject<ViewTag[]>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used for the search value selector
|
||||||
|
*/
|
||||||
|
public mediafilesObserver: BehaviorSubject<ViewMediafile[]>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used in the search Value selector to assign an agenda item
|
* Used in the search Value selector to assign an agenda item
|
||||||
*/
|
*/
|
||||||
@ -133,7 +140,14 @@ export class AssignmentDetailComponent extends BaseViewComponent implements OnIn
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if there are any tags available
|
* Checks if there are any mediafiles available
|
||||||
|
*/
|
||||||
|
public get mediafilesAvailable(): boolean {
|
||||||
|
return this.mediafilesObserver.getValue().length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if there are any items available
|
||||||
*/
|
*/
|
||||||
public get parentsAvailable(): boolean {
|
public get parentsAvailable(): boolean {
|
||||||
return this.agendaObserver.getValue().length > 0;
|
return this.agendaObserver.getValue().length > 0;
|
||||||
@ -174,7 +188,8 @@ export class AssignmentDetailComponent extends BaseViewComponent implements OnIn
|
|||||||
private agendaRepo: ItemRepositoryService,
|
private agendaRepo: ItemRepositoryService,
|
||||||
private tagRepo: TagRepositoryService,
|
private tagRepo: TagRepositoryService,
|
||||||
private promptService: PromptService,
|
private promptService: PromptService,
|
||||||
private pdfService: AssignmentPdfExportService
|
private pdfService: AssignmentPdfExportService,
|
||||||
|
private mediafileRepo: MediafileRepositoryService
|
||||||
) {
|
) {
|
||||||
super(title, translate, matSnackBar);
|
super(title, translate, matSnackBar);
|
||||||
this.subscriptions.push(
|
this.subscriptions.push(
|
||||||
@ -187,6 +202,7 @@ export class AssignmentDetailComponent extends BaseViewComponent implements OnIn
|
|||||||
this.assignmentForm = formBuilder.group({
|
this.assignmentForm = formBuilder.group({
|
||||||
phase: null,
|
phase: null,
|
||||||
tags_id: [],
|
tags_id: [],
|
||||||
|
attachments_id: [],
|
||||||
title: '',
|
title: '',
|
||||||
description: '',
|
description: '',
|
||||||
poll_description_default: '',
|
poll_description_default: '',
|
||||||
@ -205,6 +221,7 @@ export class AssignmentDetailComponent extends BaseViewComponent implements OnIn
|
|||||||
this.getAssignmentByUrl();
|
this.getAssignmentByUrl();
|
||||||
this.agendaObserver = this.agendaRepo.getViewModelListBehaviorSubject();
|
this.agendaObserver = this.agendaRepo.getViewModelListBehaviorSubject();
|
||||||
this.tagsObserver = this.tagRepo.getViewModelListBehaviorSubject();
|
this.tagsObserver = this.tagRepo.getViewModelListBehaviorSubject();
|
||||||
|
this.mediafilesObserver = this.mediafileRepo.getViewModelListBehaviorSubject();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -281,6 +298,7 @@ export class AssignmentDetailComponent extends BaseViewComponent implements OnIn
|
|||||||
this.assignmentForm.patchValue({
|
this.assignmentForm.patchValue({
|
||||||
title: assignment.title || '',
|
title: assignment.title || '',
|
||||||
tags_id: assignment.assignment.tags_id || [],
|
tags_id: assignment.assignment.tags_id || [],
|
||||||
|
attachments_id: assignment.assignment.attachments_id || [],
|
||||||
agendaItem: assignment.assignment.agenda_item_id || null,
|
agendaItem: assignment.assignment.agenda_item_id || null,
|
||||||
phase: assignment.phase, // todo default: 0?
|
phase: assignment.phase, // todo default: 0?
|
||||||
description: assignment.assignment.description || '',
|
description: assignment.assignment.description || '',
|
||||||
|
@ -8,6 +8,7 @@ import { ViewTag } from 'app/site/tags/models/view-tag';
|
|||||||
import { BaseViewModel } from 'app/site/base/base-view-model';
|
import { BaseViewModel } from 'app/site/base/base-view-model';
|
||||||
import { ViewAssignmentRelatedUser } from './view-assignment-related-user';
|
import { ViewAssignmentRelatedUser } from './view-assignment-related-user';
|
||||||
import { ViewAssignmentPoll } from './view-assignment-poll';
|
import { ViewAssignmentPoll } from './view-assignment-poll';
|
||||||
|
import { ViewMediafile } from 'app/site/mediafiles/models/view-mediafile';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A constant containing all possible assignment phases and their different
|
* A constant containing all possible assignment phases and their different
|
||||||
@ -40,6 +41,7 @@ export class ViewAssignment extends BaseAgendaViewModel {
|
|||||||
private _assignmentPolls: ViewAssignmentPoll[];
|
private _assignmentPolls: ViewAssignmentPoll[];
|
||||||
private _agendaItem?: ViewItem;
|
private _agendaItem?: ViewItem;
|
||||||
private _tags?: ViewTag[];
|
private _tags?: ViewTag[];
|
||||||
|
private _attachments?: ViewMediafile[];
|
||||||
|
|
||||||
public get id(): number {
|
public get id(): number {
|
||||||
return this._assignment ? this._assignment.id : null;
|
return this._assignment ? this._assignment.id : null;
|
||||||
@ -81,6 +83,10 @@ export class ViewAssignment extends BaseAgendaViewModel {
|
|||||||
return this._tags || [];
|
return this._tags || [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get attachments(): ViewMediafile[] {
|
||||||
|
return this._attachments || [];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* unknown where the identifier to the phase is get
|
* unknown where the identifier to the phase is get
|
||||||
*/
|
*/
|
||||||
@ -129,7 +135,8 @@ export class ViewAssignment extends BaseAgendaViewModel {
|
|||||||
assignmentRelatedUsers: ViewAssignmentRelatedUser[],
|
assignmentRelatedUsers: ViewAssignmentRelatedUser[],
|
||||||
assignmentPolls: ViewAssignmentPoll[],
|
assignmentPolls: ViewAssignmentPoll[],
|
||||||
agendaItem?: ViewItem,
|
agendaItem?: ViewItem,
|
||||||
tags?: ViewTag[]
|
tags?: ViewTag[],
|
||||||
|
attachments?: ViewMediafile[]
|
||||||
) {
|
) {
|
||||||
super(Assignment.COLLECTIONSTRING);
|
super(Assignment.COLLECTIONSTRING);
|
||||||
|
|
||||||
@ -138,6 +145,7 @@ export class ViewAssignment extends BaseAgendaViewModel {
|
|||||||
this._assignmentPolls = assignmentPolls;
|
this._assignmentPolls = assignmentPolls;
|
||||||
this._agendaItem = agendaItem;
|
this._agendaItem = agendaItem;
|
||||||
this._tags = tags;
|
this._tags = tags;
|
||||||
|
this._attachments = attachments;
|
||||||
}
|
}
|
||||||
|
|
||||||
public updateDependencies(update: BaseViewModel): void {
|
public updateDependencies(update: BaseViewModel): void {
|
||||||
@ -153,6 +161,13 @@ export class ViewAssignment extends BaseAgendaViewModel {
|
|||||||
} else if (update instanceof ViewUser) {
|
} else if (update instanceof ViewUser) {
|
||||||
this.assignmentRelatedUsers.forEach(aru => aru.updateDependencies(update));
|
this.assignmentRelatedUsers.forEach(aru => aru.updateDependencies(update));
|
||||||
this.polls.forEach(poll => poll.updateDependencies(update));
|
this.polls.forEach(poll => poll.updateDependencies(update));
|
||||||
|
} else if (update instanceof ViewMediafile && this.assignment.attachments_id.includes(update.id)) {
|
||||||
|
const mediafileIndex = this._attachments.findIndex(_mediafile => _mediafile.id === update.id);
|
||||||
|
if (mediafileIndex < 0) {
|
||||||
|
this._attachments.push(update);
|
||||||
|
} else {
|
||||||
|
this._attachments[mediafileIndex] = update;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,19 @@
|
|||||||
|
# Generated by Django 2.1.7 on 2019-04-26 11:06
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("mediafiles", "0003_auto_20190119_1425"),
|
||||||
|
("assignments", "0006_auto_20190119_1425"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="assignment",
|
||||||
|
name="attachments",
|
||||||
|
field=models.ManyToManyField(blank=True, to="mediafiles.Mediafile"),
|
||||||
|
)
|
||||||
|
]
|
@ -10,6 +10,7 @@ from django.db import models
|
|||||||
from openslides.agenda.models import Item, Speaker
|
from openslides.agenda.models import Item, Speaker
|
||||||
from openslides.core.config import config
|
from openslides.core.config import config
|
||||||
from openslides.core.models import Tag
|
from openslides.core.models import Tag
|
||||||
|
from openslides.mediafiles.models import Mediafile
|
||||||
from openslides.poll.models import (
|
from openslides.poll.models import (
|
||||||
BaseOption,
|
BaseOption,
|
||||||
BasePoll,
|
BasePoll,
|
||||||
@ -78,7 +79,7 @@ class AssignmentManager(models.Manager):
|
|||||||
polls are prefetched from the database.
|
polls are prefetched from the database.
|
||||||
"""
|
"""
|
||||||
return self.get_queryset().prefetch_related(
|
return self.get_queryset().prefetch_related(
|
||||||
"related_users", "agenda_items", "polls", "tags"
|
"related_users", "agenda_items", "polls", "tags", "attachments"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -141,6 +142,11 @@ class Assignment(RESTModelMixin, models.Model):
|
|||||||
Tags for the assignment.
|
Tags for the assignment.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
attachments = models.ManyToManyField(Mediafile, blank=True)
|
||||||
|
"""
|
||||||
|
Mediafiles as attachments for this assignment.
|
||||||
|
"""
|
||||||
|
|
||||||
# In theory there could be one then more agenda_item. But we support only
|
# In theory there could be one then more agenda_item. But we support only
|
||||||
# one. See the property agenda_item.
|
# one. See the property agenda_item.
|
||||||
agenda_items = GenericRelation(Item, related_name="assignments")
|
agenda_items = GenericRelation(Item, related_name="assignments")
|
||||||
|
@ -206,6 +206,7 @@ class AssignmentFullSerializer(ModelSerializer):
|
|||||||
"agenda_type",
|
"agenda_type",
|
||||||
"agenda_parent_id",
|
"agenda_parent_id",
|
||||||
"tags",
|
"tags",
|
||||||
|
"attachments",
|
||||||
)
|
)
|
||||||
validators = (posts_validator,)
|
validators = (posts_validator,)
|
||||||
|
|
||||||
@ -222,10 +223,12 @@ class AssignmentFullSerializer(ModelSerializer):
|
|||||||
agenda_type = validated_data.pop("agenda_type", None)
|
agenda_type = validated_data.pop("agenda_type", None)
|
||||||
agenda_parent_id = validated_data.pop("agenda_parent_id", None)
|
agenda_parent_id = validated_data.pop("agenda_parent_id", None)
|
||||||
tags = validated_data.pop("tags", [])
|
tags = validated_data.pop("tags", [])
|
||||||
|
attachments = validated_data.pop("attachments", [])
|
||||||
assignment = Assignment(**validated_data)
|
assignment = Assignment(**validated_data)
|
||||||
assignment.agenda_item_update_information["type"] = agenda_type
|
assignment.agenda_item_update_information["type"] = agenda_type
|
||||||
assignment.agenda_item_update_information["parent_id"] = agenda_parent_id
|
assignment.agenda_item_update_information["parent_id"] = agenda_parent_id
|
||||||
assignment.save()
|
assignment.save()
|
||||||
assignment.tags.add(*tags)
|
assignment.tags.add(*tags)
|
||||||
|
assignment.attachments.add(*attachments)
|
||||||
inform_changed_data(assignment)
|
inform_changed_data(assignment)
|
||||||
return assignment
|
return assignment
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
import pytest
|
import pytest
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
|
from django.core.files.uploadedfile import SimpleUploadedFile
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from rest_framework import status
|
from rest_framework import status
|
||||||
from rest_framework.test import APIClient
|
from rest_framework.test import APIClient
|
||||||
|
|
||||||
from openslides.assignments.models import Assignment
|
from openslides.assignments.models import Assignment
|
||||||
|
from openslides.core.models import Tag
|
||||||
|
from openslides.mediafiles.models import Mediafile
|
||||||
from openslides.utils.autoupdate import inform_changed_data
|
from openslides.utils.autoupdate import inform_changed_data
|
||||||
from openslides.utils.test import TestCase
|
from openslides.utils.test import TestCase
|
||||||
|
|
||||||
@ -19,16 +22,56 @@ def test_assignment_db_queries():
|
|||||||
* 1 request to get all related users,
|
* 1 request to get all related users,
|
||||||
* 1 request to get the agenda item,
|
* 1 request to get the agenda item,
|
||||||
* 1 request to get the polls,
|
* 1 request to get the polls,
|
||||||
* 1 request to get the tags and
|
* 1 request to get the tags,
|
||||||
|
* 1 request to get the attachments and
|
||||||
|
|
||||||
* 10 request to fetch each related user again.
|
* 10 request to fetch each related user again.
|
||||||
|
|
||||||
TODO: The last request are a bug.
|
TODO: The last requests are a bug.
|
||||||
"""
|
"""
|
||||||
for index in range(10):
|
for index in range(10):
|
||||||
Assignment.objects.create(title=f"assignment{index}", open_posts=1)
|
Assignment.objects.create(title=f"assignment{index}", open_posts=1)
|
||||||
|
|
||||||
assert count_queries(Assignment.get_elements) == 15
|
assert count_queries(Assignment.get_elements) == 16
|
||||||
|
|
||||||
|
|
||||||
|
class CreateAssignment(TestCase):
|
||||||
|
"""
|
||||||
|
Tests basic creation of assignments.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.client = APIClient()
|
||||||
|
self.client.login(username="admin", password="admin")
|
||||||
|
|
||||||
|
def test_simple(self):
|
||||||
|
response = self.client.post(
|
||||||
|
reverse("assignment-list"),
|
||||||
|
{"title": "test_title_ef3jpF)M329f30m)f82", "open_posts": 1},
|
||||||
|
)
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
||||||
|
assignment = Assignment.objects.get()
|
||||||
|
self.assertEqual(assignment.title, "test_title_ef3jpF)M329f30m)f82")
|
||||||
|
|
||||||
|
def test_with_tags_and_mediafiles(self):
|
||||||
|
Tag.objects.create(name="test_tag")
|
||||||
|
Mediafile.objects.create(
|
||||||
|
title="test_file", mediafile=SimpleUploadedFile("title.txt", b"content")
|
||||||
|
)
|
||||||
|
response = self.client.post(
|
||||||
|
reverse("assignment-list"),
|
||||||
|
{
|
||||||
|
"title": "test_title_ef3jpF)M329f30m)f82",
|
||||||
|
"open_posts": 1,
|
||||||
|
"tags_id": [1],
|
||||||
|
"attachments_id": [1],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
||||||
|
assignment = Assignment.objects.get()
|
||||||
|
self.assertEqual(assignment.title, "test_title_ef3jpF)M329f30m)f82")
|
||||||
|
self.assertTrue(assignment.tags.exists())
|
||||||
|
self.assertTrue(assignment.attachments.exists())
|
||||||
|
|
||||||
|
|
||||||
class CanidatureSelf(TestCase):
|
class CanidatureSelf(TestCase):
|
||||||
|
Loading…
Reference in New Issue
Block a user