Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change restrictor for Orgaadmin #4382

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ export class CommitteeRepositoryService extends BaseRepository<ViewCommittee, Co
const viewModel = super.createViewModel(model);
viewModel.getViewUser = (id: Id): ViewUser => this.userRepo.getViewModel(id);
viewModel.canAccess = (): boolean =>
this.operator.hasCommitteePermissions(model.id, CML.can_manage) ||
this.operator.hasCommitteePermissionsOrOrgaPermissions(model.id, CML.can_manage) ||
this.operator.hasOrganizationPermissions(OML.can_manage_users) ||
this.operator.isInCommitteesNonAdminCheck(model);
return viewModel;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { ActivatedRoute } from '@angular/router';
import { TranslateService } from '@ngx-translate/core';
import { Observable, Subject } from 'rxjs';
import { Collection, Fqid, Id } from 'src/app/domain/definitions/key-types';
import { OML } from 'src/app/domain/definitions/organization-permission';
import { Selectable } from 'src/app/domain/interfaces';
import { BaseModel } from 'src/app/domain/models/base/base-model';
import { HistoryPosition, HistoryPresenterService } from 'src/app/gateways/presenter/history-presenter.service';
Expand Down Expand Up @@ -94,10 +93,6 @@ export class HistoryListComponent extends BaseMeetingComponent implements OnInit
}
}

public get isSuperadmin(): boolean {
return this.operator.hasOrganizationPermissions(OML.superadmin);
}

public constructor(
protected override translate: TranslateService,
private viewModelStore: ViewModelStoreService,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,6 @@ export class GroupListComponent extends BaseMeetingComponent implements OnInit,
* Function to allow to edit the external_id
*/
public get allowExternalId(): boolean {
return this.operator.isMeetingAdmin || this.operator.isSuperAdmin;
return this.operator.isMeetingAdmin || this.operator.isSuperAdmin || this.operator.isOrgaManager;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ export class AccountAddToMeetingsComponent extends BaseUiComponent implements On
.getViewModelListObservable()
.pipe(
map(meetings =>
this.operator.isSuperAdmin
this.operator.isSuperAdmin || this.operator.isOrgaManager
? meetings.filter(meeting => !meeting.locked_from_inside)
: meetings.filter(
meeting => this.operator.isInMeeting(meeting.id) && !meeting.locked_from_inside
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,10 @@ export class AccountDetailComponent extends BaseComponent implements OnInit {
}

public get orgaManagementLevelChangeDisabled(): boolean {
return this.user?.id === this.operator.operatorId && this.operator.isSuperAdmin;
return (
this.user?.id === this.operator.operatorId &&
(this.operator.isSuperAdmin || this.operator.isOrgaManager || this.operator.isAccountAdmin)
);
}

@ViewChild(UserDetailViewComponent, { static: false })
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,10 @@ export class AccountListComponent extends BaseListViewComponent<ViewUser> {
const meetings = this.meetingRepo.getViewModelList();
const result = await this.choiceService.open<ViewMeeting>({
title,
choices: this.operator.isSuperAdmin
? meetings.filter(meeting => !meeting.locked_from_inside)
: meetings.filter(meeting => this.operator.isInMeeting(meeting.id) && !meeting.locked_from_inside),
choices:
this.operator.isSuperAdmin || this.operator.isOrgaManager
? meetings.filter(meeting => !meeting.locked_from_inside)
: meetings.filter(meeting => this.operator.isInMeeting(meeting.id) && !meeting.locked_from_inside),
multiSelect: true,
actions,
content: this.translate.instant(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
@if (meeting.isArchived) {
<mat-label class="archived-label">{{ 'Archived' | translate }}</mat-label>
}
<ng-container *osCmlPerms="CML.can_manage; committeeId: committee.id; nonAdminCheck: true">
<ng-container *osCmlPerms="CML.can_manage; committeeId: committee.id">
@if (isTemplateMeeting) {
<div class="template-indicator">
<mat-icon [matTooltip]="'Public template' | translate">star</mat-icon>
Expand Down Expand Up @@ -131,7 +131,10 @@

<mat-menu #meetingMenu="matMenu">
<ng-template matMenuContent>
@if (!meeting.isArchived && (meeting?.canBeEnteredBy(operator.user) || operator.isSuperAdmin)) {
@if (
!meeting.isArchived &&
(meeting?.canBeEnteredBy(operator.user) || operator.isSuperAdmin || operator.isOrgaManager)
) {
<a mat-menu-item [routerLink]="['meeting', 'edit', meeting.id]">
<mat-icon>edit</mat-icon>
<span>{{ 'Edit' | translate }}</span>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,11 @@ export class MeetingEditComponent extends BaseComponent implements OnInit {

private onAfterCreateForm(): void {
this.enableFormControls();
if (!this.operator.isSuperAdmin && !this.isMeetingAdmin && !this.isCreateView) {
if (
!(this.operator.isSuperAdmin || this.operator.isOrgaManager) &&
!this.isMeetingAdmin &&
!this.isCreateView
) {
Object.keys(this.meetingForm.controls).forEach(controlName => {
if (!ORGA_ADMIN_ALLOWED_CONTROLNAMES.includes(controlName)) {
this.meetingForm.get(controlName)!.disable();
Expand Down Expand Up @@ -347,7 +351,9 @@ export class MeetingEditComponent extends BaseComponent implements OnInit {

private async doUpdateMeeting(): Promise<void> {
const options =
this.operator.isSuperAdmin && !this.isMeetingAdmin && this.editMeeting?.locked_from_inside
(this.operator.isSuperAdmin || this.operator.isOrgaManager) &&
!this.isMeetingAdmin &&
this.editMeeting?.locked_from_inside
? {}
: this.getUsersToUpdateForMeetingObject();
await this.meetingRepo.update(this.sanitizePayload(this.getPayload()), {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<os-head-bar
[customMenu]="true"
[hasMainButton]="canManageMeetingsInCommittee"
[hasMainButton]="canManageCommitteeOrMeetingsInCommittee"
[mainActionTooltip]="'New meeting' | translate"
[nav]="false"
(mainEvent)="onCreateMeeting()"
Expand Down Expand Up @@ -105,7 +105,7 @@ <h1>
</os-committee-meta-info>
}
<!-- Member amount -->
@if (canManageCommittee) {
@if (canManageCommitteeOrMeetingsInCommittee) {
<os-committee-meta-info icon="engineering" title="{{ 'Committee admin' | translate }}">
@if (committee.getManagers(); as managers) {
<os-comma-separated-listing [list]="managers">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,8 @@ export class CommitteeDetailViewComponent extends BaseUiComponent {
public forwardingExpanded = false;
public requireDuplicateFrom = false;

public get canManageMeetingsInCommittee(): boolean {
return this.operator.hasCommitteePermissionsNonAdminCheck(this.committeeId, CML.can_manage);
}

public get canManageCommittee(): boolean {
return this.operator.hasCommitteePermissions(this.committeeId, CML.can_manage);
public get canManageCommitteeOrMeetingsInCommittee(): boolean {
Elblinator marked this conversation as resolved.
Show resolved Hide resolved
return this.operator.hasCommitteePermissionsOrOrgaPermissions(this.committeeId, CML.can_manage);
}

public constructor(
Expand Down Expand Up @@ -90,7 +86,7 @@ export class CommitteeDetailViewComponent extends BaseUiComponent {

public canAccessCommittee(committee: Committee): boolean {
return (
this.operator.hasCommitteePermissions(committee.id, CML.can_manage) ||
this.operator.hasCommitteePermissionsOrOrgaPermissions(committee.id, CML.can_manage) ||
this.operator.isInCommittees(committee)
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ export class DashboardComponent extends BaseComponent {
meeting =>
this.operator.isInMeeting(meeting.id) ||
this.operator.isSuperAdmin ||
this.operator.isOrgaManager ||
(meeting.publicAccessPossible() && this.operator.isAnonymous)
);
const currentDate = new Date();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,7 @@ <h2>{{ 'Meetings' | translate }}</h2>

<!-- Is Template -->
<span
*osCmlPerms="
CML.can_manage;
committeeId: meeting.committee_id;
nonAdminCheck: true;
and: meeting.isTemplate
"
*osCmlPerms="CML.can_manage; committeeId: meeting.committee_id; and: meeting.isTemplate"
class="icon-prefix"
>
<mat-icon [matTooltip]="'Public template' | translate">star</mat-icon>
Expand Down Expand Up @@ -181,7 +176,7 @@ <h2>{{ 'Meetings' | translate }}</h2>

<div *osScrollingTableCell="'menu'; row as meeting; config: { width: 40 }">
<button
*osCmlPerms="CML.can_manage; committeeId: meeting.committee?.id; nonAdminCheck: true"
*osCmlPerms="CML.can_manage; committeeId: meeting.committee?.id"
data-cy="meetingListSingleMenuTrigger"
mat-icon-button
[disabled]="isMultiSelect"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ export class MeetingListFilterService extends BaseFilterListService<ViewMeeting>
}

protected override preFilter(rawInputData: ViewMeeting[]): ViewMeeting[] {
return this.operator.isSuperAdmin
return this.operator.isSuperAdmin || this.operator.isOrgaManager
? rawInputData
: rawInputData.filter(meeting => this.operator.isInMeeting(meeting.id));
}
Expand Down
6 changes: 5 additions & 1 deletion client/src/app/site/services/auth-check.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,11 @@ export class AuthCheckService {
await this.fetchMeetingIfNotExists(+meetingIdString);

await this.operator.ready;
return this.operator.isInMeeting(Number(meetingIdString)) || this.operator.isSuperAdmin;
return (
this.operator.isInMeeting(Number(meetingIdString)) ||
this.operator.isSuperAdmin ||
this.operator.isOrgaManager
);
}

private async fetchMeetingIfNotExists(meetingId: Id): Promise<void> {
Expand Down
35 changes: 13 additions & 22 deletions client/src/app/site/services/operator.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -588,7 +588,7 @@ export class OperatorService {
// console.warn(`has perms: Usage outside of meeting!`);
return false;
}
if (this.isSuperAdmin && !this.activeMeeting.locked_from_inside) {
if ((this.isSuperAdmin || this.isOrgaManager) && !this.activeMeeting.locked_from_inside) {
Elblinator marked this conversation as resolved.
Show resolved Hide resolved
return true;
}

Expand All @@ -612,7 +612,7 @@ export class OperatorService {
// console.warn(`has perms: Operator is not ready!`);
return false;
}
if (this.isSuperAdmin && !this.activeMeeting.locked_from_inside) {
if ((this.isSuperAdmin || this.isOrgaManager) && !this.activeMeeting.locked_from_inside) {
return true;
}
const groups = this.user.groups(meetingId);
Expand Down Expand Up @@ -659,18 +659,9 @@ export class OperatorService {
*
* @returns A boolean whether an operator's CML is high enough.
*/
public hasCommitteePermissions(committeeId: Id | null, ...permissionsToCheck: CML[]): boolean {
// If a user can manage an entire organization, they can also manage every committee.
// Regardless, if they have no CML.
if (this.isOrgaManager) {
return true;
}
return this.hasCommitteePermissionsNonAdminCheck(committeeId, ...permissionsToCheck);
}

public hasCommitteePermissionsNonAdminCheck(committeeId: Id | null, ...permissionsToCheck: CML[]): boolean {
// A superadmin can still do everything
if (this.isSuperAdmin) {
public hasCommitteePermissionsOrOrgaPermissions(committeeId: Id | null, ...permissionsToCheck: CML[]): boolean {
Elblinator marked this conversation as resolved.
Show resolved Hide resolved
// A superadmin and orgaadmin can do everything
if (this.isSuperAdmin || this.isOrgaManager) {
return true;
}
// A user can have a CML for any committee but they could be not present in some of them.
Expand All @@ -694,7 +685,7 @@ export class OperatorService {
* @returns `true`, if the current operator is included in at least one of the given committees.
*/
public isInCommittees(...committees: Committee[]): boolean {
if (this.isSuperAdmin) {
if (this.isSuperAdmin || this.isOrgaManager) {
return true;
}
return this.isInCommitteesNonAdminCheck(...committees);
Expand All @@ -714,7 +705,7 @@ export class OperatorService {

/**
* This function checks if the operator is in one of the given groups. It is also a permission check.
* That means, if the operator is an admin or a superadmin, this function will return `true`, too.
* That means, if the operator is an admin a superadmin or an orgaadmin, this function will return `true`, too.
*
* TODO: what if no active meeting??
*
Expand All @@ -728,19 +719,19 @@ export class OperatorService {

/**
* This checks if an operator is in at least one of the given groups. It is also a permission check.
* That means, if the operator is an admin or a superadmin, this function returns `true`, too.
* That means, if the operator is an admin, a superadmin or an orgaadmin, this function returns `true`, too.
*
* TODO: what if no active meeting??
*
* @param groups The group ids to check
*
* @returns `true`, if the operator is in at least one group or they are an admin or a superadmin.
* @returns `true`, if the operator is in at least one group or they are an admin. a superadmin or a orgaadmin.
*/
public isInGroupIds(...groupIds: Id[]): boolean {
if (!this._groupIds) {
return false;
}
if (this.isSuperAdmin) {
if (this.isSuperAdmin || this.isOrgaManager) {
return true;
}
if (!this.isInGroupIdsNonAdminCheck(...groupIds)) {
Expand All @@ -751,7 +742,7 @@ export class OperatorService {
}

public isInMeetingIds(...meetingIds: Id[]): boolean {
if (this.isSuperAdmin) {
if (this.isSuperAdmin || this.isOrgaManager) {
return true;
}
if (!this._meetingIds) {
Expand All @@ -762,8 +753,8 @@ export class OperatorService {

/**
* Function to clear check if an operator is in at least of the given groups.
* This check is not a check for permissions and does neither include a check for an admin
* nor include a check for a superadmin.
* This check is not a check for permissions and does
* neither include a check for an admin, a superadmin, nor an orgaadmin
*
* @param groups The group ids to check
*
Expand Down
7 changes: 5 additions & 2 deletions client/src/app/site/services/user.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,14 +96,17 @@ export class UserService {
hasPerms = true;
}
if (!hasPerms && toCompare.collection === UserScope.COMMITTEE) {
hasPerms = hasPerms || this.operator.hasCommitteePermissions(toCompare.id, CML.can_manage);
hasPerms =
hasPerms ||
this.operator.hasCommitteePermissionsOrOrgaPermissions(toCompare.id, CML.can_manage);
}
if (!hasPerms && toCompare.collection === UserScope.MEETING) {
const committee_id = this.meetingRepo.getViewModel(toCompare.id)?.committee_id;
hasPerms =
hasPerms ||
this.operator.hasPermsInMeeting(toCompare.id, Permission.userCanManage) ||
(committee_id && this.operator.hasCommitteePermissions(committee_id, CML.can_manage));
(committee_id &&
this.operator.hasCommitteePermissionsOrOrgaPermissions(committee_id, CML.can_manage));
}
return hasPerms;
});
Expand Down
13 changes: 3 additions & 10 deletions client/src/app/ui/directives/perms/cml-perms.directive.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,7 @@ type TestConditionalType = {

@Component({
template: `
<div
*osCmlPerms="permission; committeeId: conditionals.id; nonAdminCheck: conditionals.nonAdmin"
id="normal"
></div>
<div *osCmlPerms="permission; committeeId: conditionals.id" id="normal"></div>
<div *osCmlPerms="permission; committeeId: conditionals.id; or: conditionals.or" id="or"></div>
<div *osCmlPerms="permission; committeeId: conditionals.id; and: conditionals.and" id="and"></div>
<div
Expand Down Expand Up @@ -63,12 +60,8 @@ class MockOperatorService {
return checkPerms.some(perm => perm === this._oml);
}

public hasCommitteePermissions(committeeId: Id | null, ...checkPerms: CML[]): boolean {
return this._isAdmin || this.hasCommitteePermissionsNonAdminCheck(committeeId, ...checkPerms);
}

public hasCommitteePermissionsNonAdminCheck(committeeId: Id | null, ...checkPerms: CML[]): boolean {
return checkPerms.some(perm => this._permList.includes(perm));
public hasCommitteePermissionsOrOrgaPermissions(committeeId: Id | null, ...checkPerms: CML[]): boolean {
Elblinator marked this conversation as resolved.
Show resolved Hide resolved
return this._isAdmin || checkPerms.some(perm => this._permList.includes(perm));
}

public changeOperatorPermsForTest(newPermList: CML[], oml?: OML | undefined): void {
Expand Down
13 changes: 1 addition & 12 deletions client/src/app/ui/directives/perms/cml-perms.directive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,6 @@ export class CmlPermsDirective extends BasePermsDirective<CML> {
this.setComplementCondition(value);
}

@Input()
public set osCmlPermsNonAdminCheck(value: boolean) {
this._checkNonAdmin = value;
this.updatePermission();
}

@Input()
public set osCmlPermsThen(template: TemplateRef<any>) {
this.setThenTemplate(template);
Expand All @@ -57,7 +51,6 @@ export class CmlPermsDirective extends BasePermsDirective<CML> {
}

private _committeeId: Id | undefined = undefined;
private _checkNonAdmin = false;
private _orOML: OML | undefined = undefined;

protected hasPermissions(): boolean {
Expand All @@ -67,10 +60,6 @@ export class CmlPermsDirective extends BasePermsDirective<CML> {
if (!this._committeeId) {
return false;
}
if (this._checkNonAdmin) {
return this.operator.hasCommitteePermissionsNonAdminCheck(this._committeeId, ...this.permissions);
} else {
return this.operator.hasCommitteePermissions(this._committeeId, ...this.permissions);
}
return this.operator.hasCommitteePermissionsOrOrgaPermissions(this._committeeId, ...this.permissions);
}
}
Loading