Merge pull request #4541 from FinnStutzenstein/projectionDefaults2

Projectiondefaults, width slider direct save
This commit is contained in:
Finn Stutzenstein 2019-04-02 12:30:20 +02:00 committed by GitHub
commit 29762ad89e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 269 additions and 53 deletions

View File

@ -34,7 +34,7 @@ matrix:
script: script:
- flake8 openslides tests - flake8 openslides tests
- isort --check-only --diff --recursive 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 -m mypy openslides/ tests/
- python -W ignore -m pytest --cov --cov-fail-under=70 - python -W ignore -m pytest --cov --cov-fail-under=70

View File

@ -23,6 +23,7 @@ import { ViewModelStoreService } from './view-model-store.service';
import { BaseProjectableViewModel } from 'app/site/base/base-projectable-view-model'; import { BaseProjectableViewModel } from 'app/site/base/base-projectable-view-model';
import { ConfigService } from '../ui-services/config.service'; import { ConfigService } from '../ui-services/config.service';
import { ProjectorDataService } from './projector-data.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 * This service cares about Projectables being projected and manage all projection-related
@ -254,10 +255,13 @@ export class ProjectorService {
* @param projectiondefault The projection default * @param projectiondefault The projection default
* @return the projector associated to the given projectiondefault. * @return the projector associated to the given projectiondefault.
*/ */
public getProjectorForDefault(projectiondefault: string): Projector { public getProjectorForDefault(projectiondefault: string): Projector | null {
return this.DS.getAll<Projector>('core/projector').find(projector => { const pd = this.DS.find(ProjectionDefault, _pd => _pd.name === projectiondefault);
return projector.projectiondefaults.map(pd => pd.name).includes(projectiondefault); if (pd) {
}); return this.DS.get<Projector>(Projector, pd.projector_id);
} else {
return null;
}
} }
/** /**

View File

@ -3,7 +3,7 @@ import { TestBed, inject } from '@angular/core/testing';
import { E2EImportsModule } from 'e2e-imports.module'; import { E2EImportsModule } from 'e2e-imports.module';
import { CountdownRepositoryService } from './countdown-repository.service'; import { CountdownRepositoryService } from './countdown-repository.service';
describe('StatuteParagraphRepositoryService', () => { describe('CountdownRepositoryService', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [E2EImportsModule], imports: [E2EImportsModule],

View File

@ -1,4 +1,7 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { DataSendService } from '../../core-services/data-send.service'; import { DataSendService } from '../../core-services/data-send.service';
import { DataStoreService } from '../../core-services/data-store.service'; import { DataStoreService } from '../../core-services/data-store.service';
import { BaseRepository } from '../base-repository'; 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 { ViewCountdown } from 'app/site/projector/models/view-countdown';
import { Countdown } from 'app/shared/models/core/countdown'; import { Countdown } from 'app/shared/models/core/countdown';
import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service'; 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'; import { ServertimeService } from 'app/core/core-services/servertime.service';
@Injectable({ @Injectable({
@ -34,15 +36,31 @@ export class CountdownRepositoryService extends BaseRepository<ViewCountdown, Co
return viewCountdown; return viewCountdown;
} }
/**
* Starts a countdown.
*
* @param countdown The countdown to start.
*/
public async start(countdown: ViewCountdown): Promise<void> { public async start(countdown: ViewCountdown): Promise<void> {
const endTime = this.servertimeService.getServertime() / 1000 + countdown.countdown_time; const endTime = this.servertimeService.getServertime() / 1000 + countdown.countdown_time;
await this.update({ running: true, countdown_time: endTime }, countdown); 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<void> { public async stop(countdown: ViewCountdown): Promise<void> {
await this.update({ running: false, countdown_time: countdown.default_time }, countdown); 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<void> { public async pause(countdown: ViewCountdown): Promise<void> {
const endTime = countdown.countdown_time - this.servertimeService.getServertime() / 1000; const endTime = countdown.countdown_time - this.servertimeService.getServertime() / 1000;
await this.update({ running: false, countdown_time: endTime }, countdown); await this.update({ running: false, countdown_time: endTime }, countdown);

View File

@ -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();
}
));
});

View File

@ -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<ViewProjectionDefault, ProjectionDefault> {
/**
* 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<ProjectionDefault> | Partial<ViewProjectionDefault>) => {
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<ProjectionDefault>): Promise<Identifiable> {
throw new Error('Not supported');
}
/**
* Deletion of projection defaults is not supported.
*/
public async delete(viewProjectionDefault: ViewProjectionDefault): Promise<void> {
throw new Error('Not supported');
}
}

View File

@ -3,7 +3,7 @@ import { TestBed, inject } from '@angular/core/testing';
import { ProjectorRepositoryService } from './projector-repository.service'; import { ProjectorRepositoryService } from './projector-repository.service';
import { E2EImportsModule } from '../../../../e2e-imports.module'; import { E2EImportsModule } from '../../../../e2e-imports.module';
describe('GroupRepositoryService', () => { describe('ProjectorRepositoryService', () => {
beforeEach(() => beforeEach(() =>
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [E2EImportsModule], imports: [E2EImportsModule],

View File

@ -47,7 +47,7 @@ export class ProjectionDialogComponent {
const defaultProjector: Projector = this.projectorService.getProjectorForDefault( const defaultProjector: Projector = this.projectorService.getProjectorForDefault(
this.projectorElementBuildDescriptor.projectionDefaultName this.projectorElementBuildDescriptor.projectionDefaultName
); );
if (!this.selectedProjectors.includes(defaultProjector)) { if (defaultProjector && !this.selectedProjectors.includes(defaultProjector)) {
this.selectedProjectors.push(defaultProjector); this.selectedProjectors.push(defaultProjector);
} }
} }

View File

@ -0,0 +1,19 @@
import { BaseModel } from '../base/base-model';
/**
* Representation of a projection default
*
* @ignore
*/
export class ProjectionDefault extends BaseModel<ProjectionDefault> {
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);
}
}

View File

@ -48,17 +48,7 @@ export function elementIdentifies(a: IdentifiableProjectorElement, b: ProjectorE
export type ProjectorElements = ProjectorElement[]; export type ProjectorElements = ProjectorElement[];
/** /**
* A projectiondefault * Representation of a projector.
*/
export interface ProjectionDefault {
id: number;
name: string;
display_name: string;
projector_id: number;
}
/**
* Representation of a projector. Has the nested property "projectiondefaults"
* *
* TODO: Move all function to the viewprojector. * TODO: Move all function to the viewprojector.
* *
@ -77,7 +67,7 @@ export class Projector extends BaseModel<Projector> {
public width: number; public width: number;
public height: number; public height: number;
public reference_projector_id: number; public reference_projector_id: number;
public projectiondefaults: ProjectionDefault[]; public projectiondefaults_id: number[];
public background_color: string; public background_color: string;
public header_background_color: string; public header_background_color: string;
public header_font_color: string; public header_font_color: string;

View File

@ -104,9 +104,18 @@
min="800" min="800"
max="3840" max="3840"
step="10" step="10"
(change)="widthSliderValueChanged(projector, $event)"
></mat-slider> ></mat-slider>
{{ updateForm.value.width }} {{ updateForm.value.width }}
<!-- projection defaults -->
<h3 translate>Projectiondefaults</h3>
<mat-select formControlName="projectiondefaults_id" placeholder="{{ 'Projectiondefaults' | translate }}" [multiple]="true">
<mat-option *ngFor="let pd of projectionDefaults" [value]="pd.id">
{{ pd.getTitle() | translate }}
</mat-option>
</mat-select>
<!-- colors --> <!-- colors -->
<mat-form-field> <mat-form-field>
<span translate>Background color</span> <span translate>Background color</span>

View File

@ -1,7 +1,7 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder, Validators } from '@angular/forms'; import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { Title } from '@angular/platform-browser'; 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'; 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 { PromptService } from 'app/core/ui-services/prompt.service';
import { ClockSlideService } from '../../services/clock-slide.service'; import { ClockSlideService } from '../../services/clock-slide.service';
import { OperatorService } from 'app/core/core-services/operator.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. * All supported aspect rations for projectors.
@ -62,6 +64,8 @@ export class ProjectorListComponent extends BaseViewComponent implements OnInit
*/ */
public projectors: ViewProjector[]; public projectors: ViewProjector[];
public projectionDefaults: ViewProjectionDefault[];
/** /**
* Helper to check manage permissions * Helper to check manage permissions
* *
@ -91,7 +95,8 @@ export class ProjectorListComponent extends BaseViewComponent implements OnInit
private formBuilder: FormBuilder, private formBuilder: FormBuilder,
private promptService: PromptService, private promptService: PromptService,
private clockSlideService: ClockSlideService, private clockSlideService: ClockSlideService,
private operator: OperatorService private operator: OperatorService,
private projectionDefaultRepo: ProjectionDefaultRepositoryService
) { ) {
super(titleService, translate, matSnackBar); super(titleService, translate, matSnackBar);
@ -104,6 +109,7 @@ export class ProjectorListComponent extends BaseViewComponent implements OnInit
name: ['', Validators.required], name: ['', Validators.required],
aspectRatio: ['', Validators.required], aspectRatio: ['', Validators.required],
width: [0, Validators.required], width: [0, Validators.required],
projectiondefaults_id: [[]],
clock: [true], clock: [true],
background_color: ['', Validators.required], background_color: ['', Validators.required],
header_background_color: ['', Validators.required], header_background_color: ['', Validators.required],
@ -122,6 +128,8 @@ export class ProjectorListComponent extends BaseViewComponent implements OnInit
super.setTitle('Projectors'); super.setTitle('Projectors');
this.projectors = this.repo.getViewModelList(); this.projectors = this.repo.getViewModelList();
this.repo.getViewModelListObservable().subscribe(projectors => (this.projectors = projectors)); 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); Promise.all(promises).then(null, this.raiseError);
} }
public widthSliderValueChanged(projector: ViewProjector, event: MatSliderChange): void {
const aspectRatio = this.getAspectRatioKey(projector);
const updateProjector: Partial<Projector> = {
width: event.value
};
updateProjector.height = Math.round(event.value / aspectRatios[aspectRatio]);
this.repo.update(updateProjector, projector).then(null, this.raiseError);
}
} }

View File

@ -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 {}
}

View File

@ -27,6 +27,10 @@ export class ViewProjector extends BaseViewModel {
return this.projector.name; return this.projector.name;
} }
public get projectiondefaults_id(): number[] {
return this.projector.projectiondefaults_id;
}
public get elements(): ProjectorElements { public get elements(): ProjectorElements {
return this.projector.elements; return this.projector.elements;
} }

View File

@ -8,6 +8,9 @@ import { ProjectorMessageRepositoryService } from 'app/core/repositories/project
import { ViewProjector } from './models/view-projector'; import { ViewProjector } from './models/view-projector';
import { ViewCountdown } from './models/view-countdown'; import { ViewCountdown } from './models/view-countdown';
import { ViewProjectorMessage } from './models/view-projector-message'; 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 = { export const ProjectorAppConfig: AppConfig = {
name: 'projector', name: 'projector',
@ -18,6 +21,12 @@ export const ProjectorAppConfig: AppConfig = {
viewModel: ViewProjector, viewModel: ViewProjector,
repository: ProjectorRepositoryService repository: ProjectorRepositoryService
}, },
{
collectionString: 'core/projection-default',
model: ProjectionDefault,
viewModel: ViewProjectionDefault,
repository: ProjectionDefaultRepositoryService
},
{ {
collectionString: 'core/countdown', collectionString: 'core/countdown',
model: Countdown, model: Countdown,

View File

@ -80,4 +80,4 @@ def clean(args=None):
@command("format", help="Format code with isort and black") @command("format", help="Format code with isort and black")
def isort(args=None): def isort(args=None):
call("isort --recursive openslides tests") call("isort --recursive openslides tests")
call("black --py36 openslides tests") call("black --target-version py36 openslides tests")

View File

@ -9,6 +9,14 @@ class ProjectorAccessPermissions(BaseAccessPermissions):
base_permission = "core.can_see_projector" 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): class TagAccessPermissions(BaseAccessPermissions):
""" """
Access permissions container for Tag and TagViewSet. Access permissions container for Tag and TagViewSet.

View File

@ -33,6 +33,7 @@ class CoreAppConfig(AppConfig):
HistoryViewSet, HistoryViewSet,
ProjectorMessageViewSet, ProjectorMessageViewSet,
ProjectorViewSet, ProjectorViewSet,
ProjectionDefaultViewSet,
TagViewSet, TagViewSet,
) )
from .websocket import ( from .websocket import (
@ -74,6 +75,10 @@ class CoreAppConfig(AppConfig):
router.register( router.register(
self.get_model("Projector").get_collection_string(), ProjectorViewSet self.get_model("Projector").get_collection_string(), ProjectorViewSet
) )
router.register(
self.get_model("Projectiondefault").get_collection_string(),
ProjectionDefaultViewSet,
)
router.register( router.register(
self.get_model("ChatMessage").get_collection_string(), ChatMessageViewSet self.get_model("ChatMessage").get_collection_string(), ChatMessageViewSet
) )
@ -121,6 +126,7 @@ class CoreAppConfig(AppConfig):
""" """
for model_name in ( for model_name in (
"Projector", "Projector",
"ProjectionDefault",
"ChatMessage", "ChatMessage",
"Tag", "Tag",
"ProjectorMessage", "ProjectorMessage",

View File

@ -16,6 +16,7 @@ from .access_permissions import (
ConfigAccessPermissions, ConfigAccessPermissions,
CountdownAccessPermissions, CountdownAccessPermissions,
HistoryAccessPermissions, HistoryAccessPermissions,
ProjectionDefaultAccessPermissions,
ProjectorAccessPermissions, ProjectorAccessPermissions,
ProjectorMessageAccessPermissions, ProjectorMessageAccessPermissions,
TagAccessPermissions, TagAccessPermissions,
@ -123,6 +124,8 @@ class ProjectionDefault(RESTModelMixin, models.Model):
name on the front end for the user. name on the front end for the user.
""" """
access_permissions = ProjectionDefaultAccessPermissions()
name = models.CharField(max_length=256) name = models.CharField(max_length=256)
display_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" Projector, on_delete=models.PROTECT, related_name="projectiondefaults"
) )
def get_root_rest_element(self):
return self.projector
class Meta: class Meta:
default_permissions = () default_permissions = ()

View File

@ -81,7 +81,6 @@ class ProjectorSerializer(ModelSerializer):
elements_preview = JSONSerializerField(validators=[elements_validator]) elements_preview = JSONSerializerField(validators=[elements_validator])
elements_history = JSONSerializerField(validators=[elements_array_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) width = IntegerField(min_value=800, max_value=3840, required=False)
height = IntegerField(min_value=340, max_value=2880, required=False) height = IntegerField(min_value=340, max_value=2880, required=False)

View File

@ -39,6 +39,7 @@ from .access_permissions import (
ConfigAccessPermissions, ConfigAccessPermissions,
CountdownAccessPermissions, CountdownAccessPermissions,
HistoryAccessPermissions, HistoryAccessPermissions,
ProjectionDefaultAccessPermissions,
ProjectorAccessPermissions, ProjectorAccessPermissions,
ProjectorMessageAccessPermissions, ProjectorMessageAccessPermissions,
TagAccessPermissions, TagAccessPermissions,
@ -143,12 +144,18 @@ class ProjectorViewSet(ModelViewSet):
REST API operation for DELETE requests. REST API operation for DELETE requests.
Assigns all ProjectionDefault objects from this projector to the 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() projector_instance = self.get_object()
new_projector_id = (
Projector.objects.exclude(pk=projector_instance.pk).first().pk
)
for projection_default in ProjectionDefault.objects.all(): for projection_default in ProjectionDefault.objects.all():
if projection_default.projector.id == projector_instance.id: if projection_default.projector.id == projector_instance.id:
projection_default.projector_id = 1 projection_default.projector_id = new_projector_id
projection_default.save() projection_default.save()
return super(ProjectorViewSet, self).destroy(*args, **kwargs) return super(ProjectorViewSet, self).destroy(*args, **kwargs)
@ -272,32 +279,29 @@ class ProjectorViewSet(ModelViewSet):
message = f"Setting scroll to {request.data} was successful." message = f"Setting scroll to {request.data} was successful."
return Response({"detail": message}) 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 class ProjectionDefaultViewSet(ModelViewSet):
/rest/core/projector/<pk>/set_projectiondefault/ with the projectiondefault id as the argument
""" """
if not isinstance(request.data, int): API endpoint for projection defaults.
raise ValidationError({"detail": "Data must be an int."})
try: There are the following views: list, retrieve, create, update,
projectiondefault = ProjectionDefault.objects.get(pk=request.data) partial_update and destroy.
except ProjectionDefault.DoesNotExist: """
raise ValidationError(
{ access_permissions = ProjectionDefaultAccessPermissions()
"detail": f"The projectiondefault with pk={request.data} was not found." 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: else:
projector_instance = self.get_object() result = False
projectiondefault.projector = projector_instance return result
projectiondefault.save()
return Response()
class TagViewSet(ModelViewSet): class TagViewSet(ModelViewSet):