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 25 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
50584ed
Add Check for Orgaadmin
Elblinator Nov 21, 2024
2ede1f4
Remove and rename functions
Elblinator Nov 21, 2024
186ffe1
Rename (and remove tests)
Elblinator Nov 25, 2024
e996062
Add canSkipPermissionCheck
Elblinator Nov 25, 2024
d545861
Merge remote-tracking branch 'upstream/main' into 4380-restrictor-change
Elblinator Dec 13, 2024
e42218c
Merge remote-tracking branch 'upstream/main' into 4380-restrictor-change
Elblinator Dec 16, 2024
34373c1
Add Buttons if operator is meeting-admin
Elblinator Dec 16, 2024
6125737
Merge remote-tracking branch 'upstream/main' into 4380-restrictor-change
Elblinator Dec 17, 2024
bd064bc
Adjust 4455
Elblinator Dec 17, 2024
63966a8
Merge remote-tracking branch 'upstream/main' into 4380-restrictor-change
Elblinator Jan 9, 2025
8bf12a9
Change the accessibility field to locker_from_inside
Elblinator Jan 9, 2025
51a4d1e
Accessibility field to a required field
Elblinator Jan 11, 2025
bfe9e66
Change small things
Elblinator Jan 11, 2025
21e9bcf
Merge remote-tracking branch 'upstream/main' into 4380-restrictor-change
Elblinator Jan 11, 2025
f3355cc
ng on init
Elblinator Jan 13, 2025
b7dc587
Add Subscription
Elblinator Jan 13, 2025
c9b380d
Remove cd
Elblinator Jan 14, 2025
297f5bc
Merge remote-tracking branch 'upstream/main' into 4380-restrictor-change
Elblinator Jan 28, 2025
ce6c7c4
Merge branch 'main' into 4380-restrictor-change
Elblinator Feb 4, 2025
9974421
Merge branch 'main' into 4380-restrictor-change
Elblinator Feb 4, 2025
ffae566
Merge branch 'main' into 4380-restrictor-change
Elblinator Feb 17, 2025
e3a41b3
Merge branch 'main' into 4380-restrictor-change
Elblinator Feb 19, 2025
ea76b9d
Meeting edit Orga admin
Elblinator Feb 21, 2025
9c3d8a0
Merge remote-tracking branch 'upstream/main' into 4380-restrictor-change
Elblinator Feb 27, 2025
6c343e4
Change Los restirction
Elblinator Feb 27, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 {
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) {
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 {
// 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 {
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