From cee6d55b8287fa539a2037e8320ef09ce0a11563 Mon Sep 17 00:00:00 2001 From: FinnStutzenstein Date: Tue, 26 Mar 2019 14:57:04 +0100 Subject: [PATCH] Projectiondefaults, width slider direct save --- .travis.yml | 2 +- .../core/core-services/projector.service.ts | 12 ++-- .../countdown-repository.service.spec.ts | 2 +- .../projector/countdown-repository.service.ts | 20 +++++- ...jection-default-repository.service.spec.ts | 20 ++++++ .../projection-default-repository.service.ts | 68 +++++++++++++++++++ .../projector-repository.service.spec.ts | 2 +- .../projection-dialog.component.ts | 2 +- .../shared/models/core/projection-default.ts | 19 ++++++ .../src/app/shared/models/core/projector.ts | 14 +--- .../projector-list.component.html | 9 +++ .../projector-list.component.ts | 21 +++++- .../models/view-projection-default.ts | 41 +++++++++++ .../site/projector/models/view-projector.ts | 4 ++ .../app/site/projector/projector.config.ts | 9 +++ make/commands.py | 2 +- openslides/core/access_permissions.py | 8 +++ openslides/core/apps.py | 6 ++ openslides/core/models.py | 6 +- openslides/core/serializers.py | 1 - openslides/core/views.py | 54 ++++++++------- 21 files changed, 269 insertions(+), 53 deletions(-) create mode 100644 client/src/app/core/repositories/projector/projection-default-repository.service.spec.ts create mode 100644 client/src/app/core/repositories/projector/projection-default-repository.service.ts create mode 100644 client/src/app/shared/models/core/projection-default.ts create mode 100644 client/src/app/site/projector/models/view-projection-default.ts diff --git a/.travis.yml b/.travis.yml index 26f2a76a3..eecd9f435 100644 --- a/.travis.yml +++ b/.travis.yml @@ -34,7 +34,7 @@ matrix: script: - flake8 openslides tests - isort --check-only --diff --recursive openslides tests - - black --check --diff --py36 openslides tests + - black --check --diff --target-version py36 openslides tests - python -m mypy openslides/ tests/ - python -W ignore -m pytest --cov --cov-fail-under=70 diff --git a/client/src/app/core/core-services/projector.service.ts b/client/src/app/core/core-services/projector.service.ts index 0a4ee7931..1d36ee3a2 100644 --- a/client/src/app/core/core-services/projector.service.ts +++ b/client/src/app/core/core-services/projector.service.ts @@ -23,6 +23,7 @@ import { ViewModelStoreService } from './view-model-store.service'; import { BaseProjectableViewModel } from 'app/site/base/base-projectable-view-model'; import { ConfigService } from '../ui-services/config.service'; import { ProjectorDataService } from './projector-data.service'; +import { ProjectionDefault } from 'app/shared/models/core/projection-default'; /** * This service cares about Projectables being projected and manage all projection-related @@ -254,10 +255,13 @@ export class ProjectorService { * @param projectiondefault The projection default * @return the projector associated to the given projectiondefault. */ - public getProjectorForDefault(projectiondefault: string): Projector { - return this.DS.getAll('core/projector').find(projector => { - return projector.projectiondefaults.map(pd => pd.name).includes(projectiondefault); - }); + public getProjectorForDefault(projectiondefault: string): Projector | null { + const pd = this.DS.find(ProjectionDefault, _pd => _pd.name === projectiondefault); + if (pd) { + return this.DS.get(Projector, pd.projector_id); + } else { + return null; + } } /** diff --git a/client/src/app/core/repositories/projector/countdown-repository.service.spec.ts b/client/src/app/core/repositories/projector/countdown-repository.service.spec.ts index 50f05fd4c..0af2379b6 100644 --- a/client/src/app/core/repositories/projector/countdown-repository.service.spec.ts +++ b/client/src/app/core/repositories/projector/countdown-repository.service.spec.ts @@ -3,7 +3,7 @@ import { TestBed, inject } from '@angular/core/testing'; import { E2EImportsModule } from 'e2e-imports.module'; import { CountdownRepositoryService } from './countdown-repository.service'; -describe('StatuteParagraphRepositoryService', () => { +describe('CountdownRepositoryService', () => { beforeEach(() => { TestBed.configureTestingModule({ imports: [E2EImportsModule], diff --git a/client/src/app/core/repositories/projector/countdown-repository.service.ts b/client/src/app/core/repositories/projector/countdown-repository.service.ts index e8c96b80e..4c744e744 100644 --- a/client/src/app/core/repositories/projector/countdown-repository.service.ts +++ b/client/src/app/core/repositories/projector/countdown-repository.service.ts @@ -1,4 +1,7 @@ import { Injectable } from '@angular/core'; + +import { TranslateService } from '@ngx-translate/core'; + import { DataSendService } from '../../core-services/data-send.service'; import { DataStoreService } from '../../core-services/data-store.service'; import { BaseRepository } from '../base-repository'; @@ -6,7 +9,6 @@ import { CollectionStringMapperService } from '../../core-services/collectionStr import { ViewCountdown } from 'app/site/projector/models/view-countdown'; import { Countdown } from 'app/shared/models/core/countdown'; import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service'; -import { TranslateService } from '@ngx-translate/core'; import { ServertimeService } from 'app/core/core-services/servertime.service'; @Injectable({ @@ -34,15 +36,31 @@ export class CountdownRepositoryService extends BaseRepository { const endTime = this.servertimeService.getServertime() / 1000 + countdown.countdown_time; await this.update({ running: true, countdown_time: endTime }, countdown); } + /** + * Stops (former `reset`) a countdown. Sets the countdown time to the default time. If + * this should not happen, use `pause()`. + * + * @param countdown The countdown to stop. + */ public async stop(countdown: ViewCountdown): Promise { await this.update({ running: false, countdown_time: countdown.default_time }, countdown); } + /** + * Pauses the countdown. The remaining time will stay. + * + * @param countdown The countdown to pause. + */ public async pause(countdown: ViewCountdown): Promise { const endTime = countdown.countdown_time - this.servertimeService.getServertime() / 1000; await this.update({ running: false, countdown_time: endTime }, countdown); diff --git a/client/src/app/core/repositories/projector/projection-default-repository.service.spec.ts b/client/src/app/core/repositories/projector/projection-default-repository.service.spec.ts new file mode 100644 index 000000000..18b50c2ec --- /dev/null +++ b/client/src/app/core/repositories/projector/projection-default-repository.service.spec.ts @@ -0,0 +1,20 @@ +import { TestBed, inject } from '@angular/core/testing'; + +import { E2EImportsModule } from '../../../../e2e-imports.module'; +import { ProjectionDefaultRepositoryService } from './projection-default-repository.service'; + +describe('ProjectionDefaultRepositoryService', () => { + beforeEach(() => + TestBed.configureTestingModule({ + imports: [E2EImportsModule], + providers: [ProjectionDefaultRepositoryService] + }) + ); + + it('should be created', inject( + [ProjectionDefaultRepositoryService], + (service: ProjectionDefaultRepositoryService) => { + expect(service).toBeTruthy(); + } + )); +}); diff --git a/client/src/app/core/repositories/projector/projection-default-repository.service.ts b/client/src/app/core/repositories/projector/projection-default-repository.service.ts new file mode 100644 index 000000000..00b8c5bdf --- /dev/null +++ b/client/src/app/core/repositories/projector/projection-default-repository.service.ts @@ -0,0 +1,68 @@ +import { Injectable } from '@angular/core'; + +import { TranslateService } from '@ngx-translate/core'; + +import { BaseRepository } from '../base-repository'; +import { CollectionStringMapperService } from '../../core-services/collectionStringMapper.service'; +import { DataSendService } from '../../core-services/data-send.service'; +import { DataStoreService } from '../../core-services/data-store.service'; +import { Identifiable } from 'app/shared/models/base/identifiable'; +import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service'; +import { ProjectionDefault } from 'app/shared/models/core/projection-default'; +import { ViewProjectionDefault } from 'app/site/projector/models/view-projection-default'; + +/** + * Manages all projection default instances. + */ +@Injectable({ + providedIn: 'root' +}) +export class ProjectionDefaultRepositoryService extends BaseRepository { + /** + * Constructor calls the parent constructor + * + * @param DS The DataStore + * @param dataSend sending changed objects + * @param mapperService Maps collection strings to classes + * @param viewModelStoreService + * @param translate + */ + public constructor( + DS: DataStoreService, + dataSend: DataSendService, + mapperService: CollectionStringMapperService, + viewModelStoreService: ViewModelStoreService, + translate: TranslateService + ) { + super(DS, dataSend, mapperService, viewModelStoreService, translate, ProjectionDefault); + } + + public getVerboseName = (plural: boolean = false) => { + return this.translate.instant(plural ? 'Projectiondefaults' : 'Projectiondefault'); + }; + + public getTitle = (projectionDefault: Partial | Partial) => { + return this.translate.instant(projectionDefault.display_name); + }; + + public createViewModel(projectionDefault: ProjectionDefault): ViewProjectionDefault { + const viewProjectionDefault = new ViewProjectionDefault(projectionDefault); + viewProjectionDefault.getVerboseName = this.getVerboseName; + viewProjectionDefault.getTitle = () => this.getTitle(viewProjectionDefault); + return viewProjectionDefault; + } + + /** + * Creation of projection defaults is not supported. + */ + public async create(projectorData: Partial): Promise { + throw new Error('Not supported'); + } + + /** + * Deletion of projection defaults is not supported. + */ + public async delete(viewProjectionDefault: ViewProjectionDefault): Promise { + throw new Error('Not supported'); + } +} diff --git a/client/src/app/core/repositories/projector/projector-repository.service.spec.ts b/client/src/app/core/repositories/projector/projector-repository.service.spec.ts index fc19a4e8b..60dacf805 100644 --- a/client/src/app/core/repositories/projector/projector-repository.service.spec.ts +++ b/client/src/app/core/repositories/projector/projector-repository.service.spec.ts @@ -3,7 +3,7 @@ import { TestBed, inject } from '@angular/core/testing'; import { ProjectorRepositoryService } from './projector-repository.service'; import { E2EImportsModule } from '../../../../e2e-imports.module'; -describe('GroupRepositoryService', () => { +describe('ProjectorRepositoryService', () => { beforeEach(() => TestBed.configureTestingModule({ imports: [E2EImportsModule], diff --git a/client/src/app/shared/components/projection-dialog/projection-dialog.component.ts b/client/src/app/shared/components/projection-dialog/projection-dialog.component.ts index f40ef95a9..4839b0e88 100644 --- a/client/src/app/shared/components/projection-dialog/projection-dialog.component.ts +++ b/client/src/app/shared/components/projection-dialog/projection-dialog.component.ts @@ -47,7 +47,7 @@ export class ProjectionDialogComponent { const defaultProjector: Projector = this.projectorService.getProjectorForDefault( this.projectorElementBuildDescriptor.projectionDefaultName ); - if (!this.selectedProjectors.includes(defaultProjector)) { + if (defaultProjector && !this.selectedProjectors.includes(defaultProjector)) { this.selectedProjectors.push(defaultProjector); } } diff --git a/client/src/app/shared/models/core/projection-default.ts b/client/src/app/shared/models/core/projection-default.ts new file mode 100644 index 000000000..f2bf8bbcc --- /dev/null +++ b/client/src/app/shared/models/core/projection-default.ts @@ -0,0 +1,19 @@ +import { BaseModel } from '../base/base-model'; + +/** + * Representation of a projection default + * + * @ignore + */ +export class ProjectionDefault extends BaseModel { + public static COLLECTIONSTRING = 'core/projection-default'; + + public id: number; + public name: string; + public display_name: string; + public projector_id: number; + + public constructor(input?: any) { + super(ProjectionDefault.COLLECTIONSTRING, input); + } +} diff --git a/client/src/app/shared/models/core/projector.ts b/client/src/app/shared/models/core/projector.ts index aa970f1fc..7e5ac4dec 100644 --- a/client/src/app/shared/models/core/projector.ts +++ b/client/src/app/shared/models/core/projector.ts @@ -48,17 +48,7 @@ export function elementIdentifies(a: IdentifiableProjectorElement, b: ProjectorE export type ProjectorElements = ProjectorElement[]; /** - * A projectiondefault - */ -export interface ProjectionDefault { - id: number; - name: string; - display_name: string; - projector_id: number; -} - -/** - * Representation of a projector. Has the nested property "projectiondefaults" + * Representation of a projector. * * TODO: Move all function to the viewprojector. * @@ -77,7 +67,7 @@ export class Projector extends BaseModel { public width: number; public height: number; public reference_projector_id: number; - public projectiondefaults: ProjectionDefault[]; + public projectiondefaults_id: number[]; public background_color: string; public header_background_color: string; public header_font_color: string; diff --git a/client/src/app/site/projector/components/projector-list/projector-list.component.html b/client/src/app/site/projector/components/projector-list/projector-list.component.html index 9057399fc..ab47ccd26 100644 --- a/client/src/app/site/projector/components/projector-list/projector-list.component.html +++ b/client/src/app/site/projector/components/projector-list/projector-list.component.html @@ -104,9 +104,18 @@ min="800" max="3840" step="10" + (change)="widthSliderValueChanged(projector, $event)" > {{ updateForm.value.width }} + +

Projectiondefaults

+ + + {{ pd.getTitle() | translate }} + + + Background color diff --git a/client/src/app/site/projector/components/projector-list/projector-list.component.ts b/client/src/app/site/projector/components/projector-list/projector-list.component.ts index a98a951a4..289990dba 100644 --- a/client/src/app/site/projector/components/projector-list/projector-list.component.ts +++ b/client/src/app/site/projector/components/projector-list/projector-list.component.ts @@ -1,7 +1,7 @@ import { Component, OnInit } from '@angular/core'; import { FormGroup, FormBuilder, Validators } from '@angular/forms'; import { Title } from '@angular/platform-browser'; -import { MatSnackBar, MatSelectChange } from '@angular/material'; +import { MatSnackBar, MatSelectChange, MatSliderChange } from '@angular/material'; import { TranslateService } from '@ngx-translate/core'; @@ -12,6 +12,8 @@ import { BaseViewComponent } from 'app/site/base/base-view'; import { PromptService } from 'app/core/ui-services/prompt.service'; import { ClockSlideService } from '../../services/clock-slide.service'; import { OperatorService } from 'app/core/core-services/operator.service'; +import { ProjectionDefaultRepositoryService } from 'app/core/repositories/projector/projection-default-repository.service'; +import { ViewProjectionDefault } from '../../models/view-projection-default'; /** * All supported aspect rations for projectors. @@ -62,6 +64,8 @@ export class ProjectorListComponent extends BaseViewComponent implements OnInit */ public projectors: ViewProjector[]; + public projectionDefaults: ViewProjectionDefault[]; + /** * Helper to check manage permissions * @@ -91,7 +95,8 @@ export class ProjectorListComponent extends BaseViewComponent implements OnInit private formBuilder: FormBuilder, private promptService: PromptService, private clockSlideService: ClockSlideService, - private operator: OperatorService + private operator: OperatorService, + private projectionDefaultRepo: ProjectionDefaultRepositoryService ) { super(titleService, translate, matSnackBar); @@ -104,6 +109,7 @@ export class ProjectorListComponent extends BaseViewComponent implements OnInit name: ['', Validators.required], aspectRatio: ['', Validators.required], width: [0, Validators.required], + projectiondefaults_id: [[]], clock: [true], background_color: ['', Validators.required], header_background_color: ['', Validators.required], @@ -122,6 +128,8 @@ export class ProjectorListComponent extends BaseViewComponent implements OnInit super.setTitle('Projectors'); this.projectors = this.repo.getViewModelList(); this.repo.getViewModelListObservable().subscribe(projectors => (this.projectors = projectors)); + this.projectionDefaults = this.projectionDefaultRepo.getViewModelList(); + this.projectionDefaultRepo.getViewModelListObservable().subscribe(pds => (this.projectionDefaults = pds)); } /** @@ -271,4 +279,13 @@ export class ProjectorListComponent extends BaseViewComponent implements OnInit }); Promise.all(promises).then(null, this.raiseError); } + + public widthSliderValueChanged(projector: ViewProjector, event: MatSliderChange): void { + const aspectRatio = this.getAspectRatioKey(projector); + const updateProjector: Partial = { + width: event.value + }; + updateProjector.height = Math.round(event.value / aspectRatios[aspectRatio]); + this.repo.update(updateProjector, projector).then(null, this.raiseError); + } } diff --git a/client/src/app/site/projector/models/view-projection-default.ts b/client/src/app/site/projector/models/view-projection-default.ts new file mode 100644 index 000000000..0c23f9e81 --- /dev/null +++ b/client/src/app/site/projector/models/view-projection-default.ts @@ -0,0 +1,41 @@ +import { BaseViewModel } from '../../base/base-view-model'; +import { ProjectionDefault } from 'app/shared/models/core/projection-default'; + +export class ViewProjectionDefault extends BaseViewModel { + public static COLLECTIONSTRING = ProjectionDefault.COLLECTIONSTRING; + + private _projectionDefault: ProjectionDefault; + + public get projectionDefault(): ProjectionDefault { + return this._projectionDefault; + } + + public get id(): number { + return this.projectionDefault.id; + } + + public get name(): string { + return this.projectionDefault.name; + } + + public get display_name(): string { + return this.projectionDefault.display_name; + } + + /** + * This is set by the repository + */ + public getVerboseName: () => string; + public getTitle: () => string; + + public constructor(projectionDefault: ProjectionDefault) { + super(ProjectionDefault.COLLECTIONSTRING); + this._projectionDefault = projectionDefault; + } + + public getModel(): ProjectionDefault { + return this.projectionDefault; + } + + public updateDependencies(update: BaseViewModel): void {} +} diff --git a/client/src/app/site/projector/models/view-projector.ts b/client/src/app/site/projector/models/view-projector.ts index 7e00dde03..4c6537773 100644 --- a/client/src/app/site/projector/models/view-projector.ts +++ b/client/src/app/site/projector/models/view-projector.ts @@ -27,6 +27,10 @@ export class ViewProjector extends BaseViewModel { return this.projector.name; } + public get projectiondefaults_id(): number[] { + return this.projector.projectiondefaults_id; + } + public get elements(): ProjectorElements { return this.projector.elements; } diff --git a/client/src/app/site/projector/projector.config.ts b/client/src/app/site/projector/projector.config.ts index 010d9a135..3bb36a46d 100644 --- a/client/src/app/site/projector/projector.config.ts +++ b/client/src/app/site/projector/projector.config.ts @@ -8,6 +8,9 @@ import { ProjectorMessageRepositoryService } from 'app/core/repositories/project import { ViewProjector } from './models/view-projector'; import { ViewCountdown } from './models/view-countdown'; import { ViewProjectorMessage } from './models/view-projector-message'; +import { ProjectionDefault } from 'app/shared/models/core/projection-default'; +import { ViewProjectionDefault } from './models/view-projection-default'; +import { ProjectionDefaultRepositoryService } from 'app/core/repositories/projector/projection-default-repository.service'; export const ProjectorAppConfig: AppConfig = { name: 'projector', @@ -18,6 +21,12 @@ export const ProjectorAppConfig: AppConfig = { viewModel: ViewProjector, repository: ProjectorRepositoryService }, + { + collectionString: 'core/projection-default', + model: ProjectionDefault, + viewModel: ViewProjectionDefault, + repository: ProjectionDefaultRepositoryService + }, { collectionString: 'core/countdown', model: Countdown, diff --git a/make/commands.py b/make/commands.py index 698676f1b..daf7ad6be 100644 --- a/make/commands.py +++ b/make/commands.py @@ -80,4 +80,4 @@ def clean(args=None): @command("format", help="Format code with isort and black") def isort(args=None): call("isort --recursive openslides tests") - call("black --py36 openslides tests") + call("black --target-version py36 openslides tests") diff --git a/openslides/core/access_permissions.py b/openslides/core/access_permissions.py index feebc360e..502456ebb 100644 --- a/openslides/core/access_permissions.py +++ b/openslides/core/access_permissions.py @@ -9,6 +9,14 @@ class ProjectorAccessPermissions(BaseAccessPermissions): base_permission = "core.can_see_projector" +class ProjectionDefaultAccessPermissions(BaseAccessPermissions): + """ + Access permissions container for Projector and ProjectorViewSet. + """ + + base_permission = "core.can_see_projector" + + class TagAccessPermissions(BaseAccessPermissions): """ Access permissions container for Tag and TagViewSet. diff --git a/openslides/core/apps.py b/openslides/core/apps.py index 611f6f841..f1d51b1b1 100644 --- a/openslides/core/apps.py +++ b/openslides/core/apps.py @@ -33,6 +33,7 @@ class CoreAppConfig(AppConfig): HistoryViewSet, ProjectorMessageViewSet, ProjectorViewSet, + ProjectionDefaultViewSet, TagViewSet, ) from .websocket import ( @@ -74,6 +75,10 @@ class CoreAppConfig(AppConfig): router.register( self.get_model("Projector").get_collection_string(), ProjectorViewSet ) + router.register( + self.get_model("Projectiondefault").get_collection_string(), + ProjectionDefaultViewSet, + ) router.register( self.get_model("ChatMessage").get_collection_string(), ChatMessageViewSet ) @@ -121,6 +126,7 @@ class CoreAppConfig(AppConfig): """ for model_name in ( "Projector", + "ProjectionDefault", "ChatMessage", "Tag", "ProjectorMessage", diff --git a/openslides/core/models.py b/openslides/core/models.py index ec6206f04..90ecf7059 100644 --- a/openslides/core/models.py +++ b/openslides/core/models.py @@ -16,6 +16,7 @@ from .access_permissions import ( ConfigAccessPermissions, CountdownAccessPermissions, HistoryAccessPermissions, + ProjectionDefaultAccessPermissions, ProjectorAccessPermissions, ProjectorMessageAccessPermissions, TagAccessPermissions, @@ -123,6 +124,8 @@ class ProjectionDefault(RESTModelMixin, models.Model): name on the front end for the user. """ + access_permissions = ProjectionDefaultAccessPermissions() + name = models.CharField(max_length=256) display_name = models.CharField(max_length=256) @@ -131,9 +134,6 @@ class ProjectionDefault(RESTModelMixin, models.Model): Projector, on_delete=models.PROTECT, related_name="projectiondefaults" ) - def get_root_rest_element(self): - return self.projector - class Meta: default_permissions = () diff --git a/openslides/core/serializers.py b/openslides/core/serializers.py index 06317ed6b..4b0456f43 100644 --- a/openslides/core/serializers.py +++ b/openslides/core/serializers.py @@ -81,7 +81,6 @@ class ProjectorSerializer(ModelSerializer): elements_preview = JSONSerializerField(validators=[elements_validator]) elements_history = JSONSerializerField(validators=[elements_array_validator]) - projectiondefaults = ProjectionDefaultSerializer(many=True, read_only=True) width = IntegerField(min_value=800, max_value=3840, required=False) height = IntegerField(min_value=340, max_value=2880, required=False) diff --git a/openslides/core/views.py b/openslides/core/views.py index bffced46f..e17e258ea 100644 --- a/openslides/core/views.py +++ b/openslides/core/views.py @@ -39,6 +39,7 @@ from .access_permissions import ( ConfigAccessPermissions, CountdownAccessPermissions, HistoryAccessPermissions, + ProjectionDefaultAccessPermissions, ProjectorAccessPermissions, ProjectorMessageAccessPermissions, TagAccessPermissions, @@ -143,12 +144,18 @@ class ProjectorViewSet(ModelViewSet): REST API operation for DELETE requests. Assigns all ProjectionDefault objects from this projector to the - default projector (pk=1). + first projector found. """ + if len(Projector.objects.all()) <= 1: + raise ValidationError({"detail": "You can't delete the last projector."}) projector_instance = self.get_object() + new_projector_id = ( + Projector.objects.exclude(pk=projector_instance.pk).first().pk + ) + for projection_default in ProjectionDefault.objects.all(): if projection_default.projector.id == projector_instance.id: - projection_default.projector_id = 1 + projection_default.projector_id = new_projector_id projection_default.save() return super(ProjectorViewSet, self).destroy(*args, **kwargs) @@ -272,32 +279,29 @@ class ProjectorViewSet(ModelViewSet): message = f"Setting scroll to {request.data} was successful." return Response({"detail": message}) - @detail_route(methods=["post"]) - def set_projectiondefault(self, request, pk): - """ - REST API operation to set a projectiondefault to the requested projector. The argument - has to be an int representing the pk from the projectiondefault to be set. - It expects a POST request to - /rest/core/projector//set_projectiondefault/ with the projectiondefault id as the argument - """ - if not isinstance(request.data, int): - raise ValidationError({"detail": "Data must be an int."}) +class ProjectionDefaultViewSet(ModelViewSet): + """ + API endpoint for projection defaults. - try: - projectiondefault = ProjectionDefault.objects.get(pk=request.data) - except ProjectionDefault.DoesNotExist: - raise ValidationError( - { - "detail": f"The projectiondefault with pk={request.data} was not found." - } - ) + There are the following views: list, retrieve, create, update, + partial_update and destroy. + """ + + access_permissions = ProjectionDefaultAccessPermissions() + queryset = ProjectionDefault.objects.all() + + def check_view_permissions(self): + """ + Returns True if the user has required permissions. + """ + if self.action in ("list", "retrieve"): + result = self.get_access_permissions().check_permissions(self.request.user) + elif self.action in ("create", "partial_update", "update", "destroy"): + result = has_perm(self.request.user, "core.can_manage_projector") else: - projector_instance = self.get_object() - projectiondefault.projector = projector_instance - projectiondefault.save() - - return Response() + result = False + return result class TagViewSet(ModelViewSet):