feat: sharing rooms with moderators and users

Dialog and permissions management
pull/281/head
Sebastien Marinier 2024-05-29 17:09:06 +02:00
parent fbf33378aa
commit 9fed698723
6 changed files with 88 additions and 34 deletions

View File

@ -88,12 +88,18 @@ class ServerController extends Controller {
return new DataResponse([], Http::STATUS_NOT_FOUND);
}
if (!$this->permission->isAdmin($room, $this->userId)) {
if (!$this->permission->isUser($room, $this->userId)) {
return new DataResponse([], Http::STATUS_FORBIDDEN);
}
$recordings = $this->server->getRecordings($room);
if (!$this->permission->isAdmin($room, $this->userId)) {
$recordings = array_filter($recordings, function ($recording) {
return $recording['published'];
});
}
return new DataResponse($recordings);
}

View File

@ -1,4 +1,4 @@
import { Access } from './Api';
import { Access, Permission } from './Api';
export const AccessOptions = {
[Access.Public]: t('bbb', 'Public'),
@ -8,3 +8,9 @@ export const AccessOptions = {
[Access.Internal]: t('bbb', 'Internal'),
[Access.InternalRestricted]: t('bbb', 'Internal restricted'),
};
export const PermissionsOptions = {
[Permission.Admin]: t('bbb', 'admin'),
[Permission.Moderator]: t('bbb', 'moderator'),
[Permission.User]: t('bbb', 'user'),
};

View File

@ -282,6 +282,10 @@ pre {
}
}
.bbb-simple-menu {
min-width: auto;
}
.bbb-input-container {
display: flex;
}

View File

@ -123,17 +123,18 @@ const EditRoomDialog: React.FC<Props> = ({ room, restriction, updateProperty, op
updateProperty('access', value);
})}
{room.access === Access.InternalRestricted && <div className="bbb-form-element bbb-form-shareWith">
<ShareWith permission={Permission.User} room={room} shares={shares} setShares={setShares} />
<em>{descriptions.internalRestrictedShareWith}</em>
</div>}
<div className="bbb-form-element">
<label htmlFor={'bbb-moderator'}>
<h3>Moderator</h3>
<label htmlFor={'bbb-sharing'}>
<h3>{t('bbb', 'Sharing')}</h3>
</label>
{!room.everyoneIsModerator && <ShareWith permission={Permission.Moderator} room={room} shares={shares} setShares={setShares} />}
{<ShareWith permission={Permission.User} room={room} shares={shares} setShares={setShares} />}
{room.access === Access.InternalRestricted &&
<div className="bbb-form-element bbb-form-shareWith">
<span className="icon icon-details icon-visible"></span><em>{`${t('bbb', 'Access')} : ${descriptions.internalRestrictedShareWith}`}</em>
</div>
}
<div className="bbb-mt-1">
<input id={`bbb-everyoneIsModerator-${room.id}`}

View File

@ -155,6 +155,28 @@ const RoomRow: React.FC<Props> = (props) => {
);
}
function publishRecording(recording: Recording, publish: boolean) {
api.publishRecording(recording.id, publish).then(success=> {
if (recordings === null) {
return;
}
setRecordings(recordings.map(recordItem => {
if (recordItem.id === recording.id) {
recordItem.published = success;
recordItem.state = success ? 'published' : 'unpublished';
}
return recordItem;
}));
}).catch(err => {
console.warn('Could not modify publishing state', err);
OC.dialogs.info(
t('bbb', 'Could not modify publishing state'),
t('bbb', 'Server error'),
() => undefined,
);
});
}
function accessToIcon(access: string) {
switch(access) {
case Access.Public:
@ -172,7 +194,7 @@ const RoomRow: React.FC<Props> = (props) => {
return <span></span>;
}
function edit(field: string, type: 'text' | 'number' = 'text', canEdit: boolean = true, options?) {
function edit(field: string, type: 'text' | 'number' = 'text', canEdit = true, options?) {
return canEdit ?
<EditableValue field={field} value={room[field]} setValue={updateRoom} type={type} options={options} />
:
@ -235,11 +257,11 @@ const RoomRow: React.FC<Props> = (props) => {
}
{!adminRoom &&
<td className="record bbb-shrink">
<span className={"icon "+(room.record ? "icon-checkmark" : "icon-close")+" icon-visible"}></span>
<span className={'icon '+(room.record ? 'icon-checkmark' : 'icon-close')+' icon-visible'}></span>
</td>
}
<td className="bbb-shrink">
{adminRoom &&
{(adminRoom || true ) &&
<RecordingsNumber recordings={recordings} showRecordings={showRecordings} setShowRecordings={setShowRecordings} />
}
</td>
@ -265,7 +287,7 @@ const RoomRow: React.FC<Props> = (props) => {
<td colSpan={11}>
<table>
<tbody>
{recordings?.sort((r1, r2) => r1.startTime - r2.startTime).map(recording => <RecordingRow key={recording.id} recording={recording} deleteRecording={deleteRecording} storeRecording={storeRecording} />)}
{recordings?.sort((r1, r2) => r1.startTime - r2.startTime).map(recording => <RecordingRow key={recording.id} isAdmin={adminRoom} recording={recording} deleteRecording={deleteRecording} storeRecording={storeRecording} publishRecording={publishRecording} />)}
</tbody>
</table>
</td>

View File

@ -2,6 +2,7 @@ import React from 'react';
import { api, ShareWith, ShareType, RoomShare, Room, Permission } from '../Common/Api';
import './ShareWith.scss';
import ShareSelection from '../Common/ShareSelection';
import { PermissionsOptions } from '../Common/Translation';
type Props = {
room: Room;
@ -45,9 +46,7 @@ const ShareWith: React.FC<Props> = ({ room, permission, shares: allShares, setSh
setShares((allShares ? [...allShares] : []).filter(share => share.id !== id));
}
async function toggleAdminShare(share: RoomShare) {
const newPermission = share.permission === Permission.Admin ? Permission.Moderator : Permission.Admin;
async function setSharePermission(share: RoomShare, newPermission: number) {
return addRoomShare(share.shareWith, share.shareType, share.shareWithDisplayName || share.shareWith, newPermission);
}
@ -59,17 +58,40 @@ const ShareWith: React.FC<Props> = ({ room, permission, shares: allShares, setSh
});
}
function ucFirst(s: string)
{
return s && s[0].toUpperCase() + s.slice(1);
}
function selectPermission(value: Permission, onChange: (value: number) => void) {
return (
<div className="bbb-form-element bbb-simple-menu">
<select name="permission" value={value} onChange={(event) => onChange(Number(event.target.value))}>
{Object.keys(PermissionsOptions).map(key => {
const label = PermissionsOptions[key];
return <option key={key} value={key}>{ucFirst(label)}</option>;
})}
</select>
</div>
);
}
function permissionLabel(permission: Permission) {
return PermissionsOptions[permission] ?? '';
}
function renderShares(shares: RoomShare[]) {
const currentUser = OC.getCurrentUser();
const ROOM_OWNER_ID = -1;
const ownShare = {
id: -1,
id: ROOM_OWNER_ID,
roomId: room.id,
shareType: ShareType.User,
shareWith: currentUser.uid,
shareWithDisplayName: currentUser.displayName,
permission: Permission.Admin,
};
return (
<ul className="bbb-shareWith">
{[ownShare, ...shares].map(share => {
@ -85,20 +107,13 @@ const ShareWith: React.FC<Props> = ({ room, permission, shares: allShares, setSh
</div>
<div className="bbb-shareWith__item__label">
<h5>{displayName}
{(share.permission === Permission.Moderator && permission === Permission.User) && ` (${t('bbb', 'moderator')})`}
{(share.permission === Permission.Admin) && ` (${t('bbb', 'admin')})`}</h5>
{(share.id === ROOM_OWNER_ID || !isOwner) && ` (${permissionLabel(share.permission)})`}
</h5>
</div>
{(share.id > -1 && permission === Permission.Moderator && isOwner) && <div className="bbb-shareWith__item__action">
<button className="action-item"
onClick={ev => {
ev.preventDefault();
toggleAdminShare(share);
}}
title={t('bbb', 'Share')}>
<span className={`icon icon-shared icon-visible ${share.permission === Permission.Admin ? 'bbb-icon-selected' : 'bbb-icon-unselected'}`}></span>
</button>
</div>}
{(share.id > -1 && isOwner) && <div className="bbb-shareWith__item__action">
{(share.id > ROOM_OWNER_ID && isOwner) && selectPermission(share.permission, (value) => {
setSharePermission(share, value);
})}
{(share.id > ROOM_OWNER_ID && isOwner) && <div className="bbb-shareWith__item__action">
<button className="action-item"
onClick={ev => {ev.preventDefault(); deleteRoomShare(share.id);}}
title={t('bbb', 'Delete')}>
@ -116,8 +131,6 @@ const ShareWith: React.FC<Props> = ({ room, permission, shares: allShares, setSh
return (
<>
{shares ? renderShares(shares) : loading}
{isOwner ?
<ShareSelection
selectShare={(shareOption) => addRoomShare(shareOption.value.shareWith, shareOption.value.shareType, shareOption.label, permission)}
@ -127,6 +140,8 @@ const ShareWith: React.FC<Props> = ({ room, permission, shares: allShares, setSh
<span className="icon icon-details icon-visible"></span> {t('bbb', 'You are not allowed to change this option, because this room is shared with you.')}
</em>
}
{shares ? renderShares(shares) : loading}
</>
);
};