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

Anonymous user #3965

Open
wants to merge 21 commits into
base: feature/anonymous-user
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 10 commits
Commits
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
32 changes: 24 additions & 8 deletions client/src/app/domain/definitions/permission.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export type PermissionsMap = { [key in Permission]?: Permission[] };
export interface DisplayPermission {
display_name: string;
help_text?: string;
anon_allowed?: boolean;
value: Permission;
}

Expand All @@ -24,13 +25,15 @@ export const PERMISSIONS: AppPermission[] = [
help_text: _(
`Can see the Autopilot menu item with all content for which appropriate permissions are set.`
),
anon_allowed: true,
value: Permission.meetingCanSeeAutopilot
},
{
display_name: _(`Can see the projector`),
help_text: _(
`Can see the Projector menu item and all projectors (in the Autopilot as well as in the Projector menu item)`
),
anon_allowed: true,
value: Permission.projectorCanSee
},
{
Expand All @@ -46,11 +49,13 @@ export const PERMISSIONS: AppPermission[] = [
{
display_name: _(`Can see agenda`),
help_text: _(`Can see the Agenda menu item and all public topics in the agenda.`),
anon_allowed: true,
value: Permission.agendaItemCanSee
},
{
display_name: _(`Can see internal items and time scheduling of agenda`),
help_text: _(`Can see all internal topics, schedules and comments.`),
anon_allowed: true,
value: Permission.agendaItemCanSeeInternal
},
{
Expand All @@ -63,6 +68,7 @@ export const PERMISSIONS: AppPermission[] = [
{
display_name: _(`Can see list of speakers`),
help_text: _(`Can see all lists of speakers`),
anon_allowed: true,
value: Permission.listOfSpeakersCanSee
},
{
Expand All @@ -74,7 +80,7 @@ export const PERMISSIONS: AppPermission[] = [
},
{
display_name: _(`Can put oneself on the list of speakers`),
help_text: _(`Is allowed to add himself/herself to the list of speakers.
help_text: _(`Is allowed to add himself/herself to the list of speakers.

Note:
Optional combination of requests to speak with presence status is possible. ( > [Settings] > [List of speakers] > [General] )`),
Expand All @@ -88,6 +94,7 @@ Optional combination of requests to speak with presence status is possible. ( >
{
display_name: _(`Can see moderation notes`),
help_text: _(`Can see all moderation notes in each list of speakers.`),
anon_allowed: true,
value: Permission.agendaItemCanSeeModeratorNotes
},
{
Expand All @@ -105,6 +112,7 @@ Optional combination of requests to speak with presence status is possible. ( >
help_text: _(
`Can see the Motions menu item and all motions unless they are limited by access restrictions in the workflow.`
),
anon_allowed: true,
value: Permission.motionCanSee
},
{
Expand All @@ -114,6 +122,7 @@ Optional combination of requests to speak with presence status is possible. ( >

Tip: Cross-check desired visibility of motions with test delegate account. `
),
anon_allowed: true,
value: Permission.motionCanSeeInternal
},
{
Expand All @@ -133,10 +142,10 @@ Tip: Cross-check desired visibility of motions with test delegate account. `
{
display_name: _(`Can forward motions`),
help_text: _(
`Can forward motions to other meetings within the OpenSlides instance.
`Can forward motions to other meetings within the OpenSlides instance.

Further requirements:
1. forwarding hierarchy must be set at the organizational level in the committee.
1. forwarding hierarchy must be set at the organizational level in the committee.
2. target meeting must be created.
3. forwarding must be activated in the workflow in the state.`
),
Expand Down Expand Up @@ -176,10 +185,11 @@ Further requirements:
{
display_name: _(`Can see elections`),
help_text: _(
`Can see the menu item Elections, including the list of candidates and results.
`Can see the menu item Elections, including the list of candidates and results.

Note: The right to vote is defined directly in the ballot.`
),
anon_allowed: true,
value: Permission.assignmentCanSee
},
{
Expand All @@ -191,7 +201,7 @@ Note: The right to vote is defined directly in the ballot.`
},
{
display_name: _(`Can nominate another participant`),
help_text: _(`Can nominate other participants as candidates.
help_text: _(`Can nominate other participants as candidates.

Requires group permission: [Can see participants]`),
value: Permission.assignmentCanNominateOther
Expand All @@ -209,15 +219,17 @@ Requires group permission: [Can see participants]`),
{
display_name: _(`Can see participants`),
help_text: _(
`Can see the menu item Participants and therefore the following data from all participants:
Personal data: Name, pronoun, gender.
`Can see the menu item Participants and therefore the following data from all participants:
Personal data: Name, pronoun, gender.
Meeting specific information: Structure level, Group, Participant number, About me, Presence status.`
),
anon_allowed: true,
value: Permission.userCanSee
},
{
display_name: _(`Can see sensitive data`),
help_text: _(`Can see email, username and SSO identification of all participants.`),
anon_allowed: true,
value: Permission.userCanSeeSensitiveData
},
{
Expand Down Expand Up @@ -245,6 +257,7 @@ Meeting specific information: Structure level, Group, Participant number, About
help_text: _(`Can see the Files menu item and all shared folders and files.

Note: Sharing of folders and files may be restricted by group assignment.`),
anon_allowed: true,
value: Permission.mediafileCanSee
},
{
Expand All @@ -267,22 +280,25 @@ Note: Sharing of folders and files may be restricted by group assignment.`),
{
display_name: _(`Can see the front page`),
help_text: _(`Can see the Home menu item.`),
anon_allowed: true,
value: Permission.meetingCanSeeFrontpage
},
{
display_name: _(`Can see the live stream`),
help_text: _(
`Can see the livestream if there is a livestream URL entered in > [Settings] > [Livestream].`
),
anon_allowed: true,
value: Permission.meetingCanSeeLivestream
},
{
display_name: _(`Can see history`),
help_text: _(
`Can see the History menu item with the history of processing timestamps for motions, elections and participants.
`Can see the History menu item with the history of processing timestamps for motions, elections and participants.

Note: For privacy reasons, it is recommended to limit the rights to view the History significantly.`
),
anon_allowed: true,
value: Permission.meetingCanSeeHistory
},
{
Expand Down
4 changes: 3 additions & 1 deletion client/src/app/domain/models/meetings/meeting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,7 @@ export class Meeting extends BaseModel<Meeting> {

public default_group_id!: Id; // group/default_group_for_meeting_id;
public admin_group_id!: Id; // group/admin_group_for_meeting_id;
public anonymous_group_id!: Id; // group/anonymous_group_for_meeting_id;

public list_of_speakers_countdown_id: Id; // projector_countdown/used_as_list_of_speakers_meeting_id;
public poll_countdown_id: Id; // projector_countdown/used_as_poll_countdown_meeting_id;
Expand Down Expand Up @@ -511,7 +512,8 @@ export class Meeting extends BaseModel<Meeting> {
`default_projector_motion_poll_ids`,
`default_projector_poll_ids`,
`default_group_id`,
`admin_group_id`
`admin_group_id`,
`anonymous_group_id`
];
}
export interface Meeting
Expand Down
6 changes: 6 additions & 0 deletions client/src/app/domain/models/users/group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export class Group extends BaseModel<Group> {

public meeting_user_ids!: Id[]; // (meeting_user/group_ids)[];
public default_group_for_meeting_id!: Id; // meeting/default_group_id;
public anonymous_group_for_meeting_id!: Id; // meeting/admin_group_id;
public admin_group_for_meeting_id!: Id; // meeting/admin_group_id;
public mediafile_access_group_ids!: Id[]; // (mediafile/access_group_ids)[];
public mediafile_inherited_access_group_ids!: Id[]; // (mediafile/inherited_access_group_ids)[];
Expand All @@ -34,6 +35,10 @@ export class Group extends BaseModel<Group> {
return !!this.admin_group_for_meeting_id;
}

public get isAnonymousGroup(): boolean {
return !!this.anonymous_group_for_meeting_id;
}

public get isDefaultGroup(): boolean {
return !!this.default_group_for_meeting_id;
}
Expand All @@ -50,6 +55,7 @@ export class Group extends BaseModel<Group> {
`weight`,
`meeting_user_ids`,
`default_group_for_meeting_id`,
`anonymous_group_for_meeting_id`,
`admin_group_for_meeting_id`,
`mediafile_access_group_ids`,
`mediafile_inherited_access_group_ids`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -633,6 +633,12 @@ export const RELATIONS: Relation[] = [
AField: `default_group`,
BField: `default_group_for_meeting`
}),
...makeO2O({
AViewModel: ViewMeeting,
BViewModel: ViewGroup,
AField: `anonymous_group`,
BField: `anonymous_group_for_meeting`
}),
...makeO2O({
AViewModel: ViewMeeting,
BViewModel: ViewGroup,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,11 @@ export class AccountButtonComponent extends BaseUiComponent implements OnInit {

public async login(): Promise<void> {
await this.authService.logoutAnonymous();
this.router.navigate([`/`, this.activeMeetingId, `login`]);
if (this.activeMeetingId) {
this.router.navigate([`/`, this.activeMeetingId, `login`]);
} else {
this.router.navigate([`/`, `login`]);
}
}

public async logout(): Promise<void> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { Meeting } from 'src/app/domain/models/meetings/meeting';
import { fadeInAnim } from 'src/app/infrastructure/animations';
import { BaseMeetingComponent } from 'src/app/site/pages/meetings/base/base-meeting.component';
import { ViewMeeting } from 'src/app/site/pages/meetings/view-models/view-meeting';
import { OrganizationService } from 'src/app/site/pages/organization/services/organization.service';
import { ORGANIZATION_ID, OrganizationService } from 'src/app/site/pages/organization/services/organization.service';
import { OrganizationSettingsService } from 'src/app/site/pages/organization/services/organization-settings.service';
import { ViewOrganization } from 'src/app/site/pages/organization/view-models/view-organization';
import { AuthService } from 'src/app/site/services/auth.service';
Expand Down Expand Up @@ -90,6 +90,7 @@ export class LoginMaskComponent extends BaseMeetingComponent implements OnInit,
private loginMessage = `Loading data. Please wait ...`;

private currentMeetingId: number | null = null;
private guestMeetingId: number | null = null;

public constructor(
protected override translate: TranslateService,
Expand Down Expand Up @@ -134,6 +135,8 @@ export class LoginMaskComponent extends BaseMeetingComponent implements OnInit,
this.route.params.subscribe(params => {
if (params[`meetingId`]) {
this.loadMeeting(params[`meetingId`]);
} else {
this.loadActiveMeetings();
}
});

Expand Down Expand Up @@ -184,7 +187,7 @@ export class LoginMaskComponent extends BaseMeetingComponent implements OnInit,

public async guestLogin(): Promise<void> {
await this.authService.anonLogin();
this.osRouter.navigateAfterLogin(this.currentMeetingId);
this.osRouter.navigateAfterLogin(this.currentMeetingId || this.guestMeetingId);
}

public async samlLogin(): Promise<void> {
Expand Down Expand Up @@ -239,6 +242,26 @@ export class LoginMaskComponent extends BaseMeetingComponent implements OnInit,
this.guestsEnabled = this.meeting.enable_anonymous;
}

private async loadActiveMeetings(): Promise<void> {
const resp = await this.autoupdate.single(
await this.modelRequestBuilder.build({
ids: [ORGANIZATION_ID],
viewModelCtor: ViewOrganization,
follow: [{ idField: `active_meeting_ids`, fieldset: [`enable_anonymous`] }]
}),
`meeting_login`
);
if (!resp || !resp[`meeting`]) {
return;
}
const publicMeetings = Object.values(resp[`meeting`]).filter(m => m[`enable_anonymous`]);

this.guestsEnabled = !!publicMeetings.length;
if (publicMeetings.length === 1) {
this.guestMeetingId = publicMeetings[0][`id`];
}
}

private checkDevice(): void {
if (!this.browserSupport.isBrowserSupported()) {
this.router.navigate([`./unsupported-browser`], { relativeTo: this.route });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,7 @@ export class MeetingsNavigationWrapperComponent extends BaseMeetingComponent imp
}

public get showMeetingNav(): boolean {
return (
!this.operator.isAnonymous &&
(this.operator.knowsMultipleMeetings || this.operator.hasOrganizationPermissions())
);
return this.operator.knowsMultipleMeetings || this.operator.hasOrganizationPermissions();
}

public get meeting(): ViewMeeting | null {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ <h2 class="poll-preview-title">
<os-repo-search-selector
formControlName="entitled_group_ids"
[multiple]="true"
[pipeFn]="groupRepo.getFilterDefaultGroupFn()"
[pipeFn]="groupRepo.getFilterSystemGroupFn()"
[repo]="groupRepo"
[showChips]="false"
[sortFn]="sortFn"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export class ChatGroupDialogComponent implements OnInit {

public readonly previousChatGroupName!: string;

public readonly groupsObservable = this.groupsRepo.getViewModelListObservable();
public readonly groupsObservable = this.groupsRepo.getViewModelListWithoutAnonymousGroupObservable();

public sortFn = (groupA: ViewGroup, groupB: ViewGroup): number => groupA.weight - groupB.weight;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ export class MeetingSettingsGroupDetailFieldComponent extends BaseComponent impl
public ngOnInit(): void {
// filter out empty results in group observable. We never have no groups and it messes up
// the settings change detection
this.groupObservable = this.groupRepo.getViewModelListWithoutDefaultGroupObservable().pipe(
this.groupObservable = this.groupRepo.getViewModelListWithoutSystemGroupsObservable().pipe(
filter(groups => !!groups.length),
map(groups => this.getRestrictedValue(groups))
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ export class CommentSectionListComponent extends BaseComponent implements OnInit
public ngOnInit(): void {
super.setTitle(`Comment fields`);

this.groups = this.groupRepo.getViewModelListObservable();
this.groups = this.groupRepo.getViewModelListWithoutAnonymousGroupObservable();
this.subscriptions.push(
this.repo
.getViewModelListObservable()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ export class MotionPermissionService {

public canDoActionWhileDelegationEnabled(isAdditionalDelegationSettingEnabled: boolean): boolean {
return !(
!this.operator.isAnonymous &&
this.operator.user.isVoteRightDelegated &&
this._delegationEnabled &&
isAdditionalDelegationSettingEnabled
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,16 +57,20 @@ <h2>{{ 'Groups' | translate }}</h2>
</mat-header-cell>
<mat-cell *matCellDef="let perm">
<div class="inner-table">
@if (!group.isAdminGroup) {
@if (
group.isAdminGroup || (group.isAnonymousGroup && !perm.anon_allowed)
) {
<mat-checkbox
[checked]="group.isAdminGroup"
[disabled]="true"
></mat-checkbox>
} @else {
<mat-checkbox
name="cb-{{ group.id }}-{{ perm.value }}"
[(ngModel)]="currentPermissions[group.id][perm.value]"
(change)="onChange(group, perm.value, $event.checked)"
></mat-checkbox>
}
@if (group.isAdminGroup) {
<mat-checkbox [checked]="true" [disabled]="true"></mat-checkbox>
}
</div>
</mat-cell>
</ng-container>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ export class GroupListComponent extends BaseMeetingComponent implements OnInit,
* @param group ViewGroup
*/
public isProtected(group: ViewGroup): boolean {
return group.isAdminGroup || group.isDefaultGroup;
return group.isAdminGroup || group.isDefaultGroup || group.isAnonymousGroup;
}

/**
Expand Down
Loading