Browse Source

feat(conversations): add option to force passwords in public conversations

Signed-off-by: Anna Larch <anna@nextcloud.com>
pull/13767/head
Anna Larch 11 months ago
parent
commit
d77753d1ce
  1. 4
      docs/capabilities.md
  2. 7
      docs/conversation.md
  3. 1
      docs/settings.md
  4. 4
      lib/Capabilities.php
  5. 4
      lib/Config.php
  6. 44
      lib/Controller/RoomController.php
  7. 19
      lib/Manager.php
  8. 1
      lib/ResponseDefinitions.php
  9. 103
      lib/Service/RoomService.php
  10. 6
      openapi-administration.json
  11. 6
      openapi-backend-recording.json
  12. 6
      openapi-backend-signaling.json
  13. 6
      openapi-backend-sipbridge.json
  14. 6
      openapi-bots.json
  15. 6
      openapi-federation.json
  16. 41
      openapi-full.json
  17. 41
      openapi.json
  18. 1
      src/__mocks__/capabilities.ts
  19. 1
      src/types/openapi/openapi-administration.ts
  20. 1
      src/types/openapi/openapi-backend-recording.ts
  21. 1
      src/types/openapi/openapi-backend-signaling.ts
  22. 1
      src/types/openapi/openapi-backend-sipbridge.ts
  23. 1
      src/types/openapi/openapi-bots.ts
  24. 1
      src/types/openapi/openapi-federation.ts
  25. 29
      src/types/openapi/openapi-full.ts
  26. 29
      src/types/openapi/openapi.ts
  27. 2
      tests/php/CapabilitiesTest.php
  28. 5
      tests/php/Service/RoomServiceTest.php

4
docs/capabilities.md

@ -166,3 +166,7 @@
* `config => call => start-without-media` (local) - Boolean, whether media should be disabled when starting or joining a conversation
* `config => call => max-duration` - Integer, maximum call duration in seconds. Please note that this should only be used with system cron and with a reasonable high value, due to the expended duration until the background job ran.
* `config => call => blur-virtual-background` (local) - Boolean, whether blur background is set by default when joining a conversation
## 21
* `config => conversations => force-passwords` - Whether passwords are enforced for public rooms
* `conversation-creation-password` - Whether the endpoints for creating public conversations or making a conversation public support setting a password

7
docs/conversation.md

@ -128,6 +128,7 @@
| `roomName` | string | Conversation name up to 255 characters (Not available for `roomType = 1`) |
| `objectType` | string | Type of an object this room references, currently only allowed value is `room` to indicate the parent of a breakout room (See [Object types](constants.md#object-types)) |
| `objectId` | string | Id of an object this room references, room token is used for the parent of a breakout room |
| `password` | string | Password for the room (only available with `conversation-creation-password` capability) |
* Response:
- Status code:
@ -135,6 +136,7 @@
+ `201 Created` When the conversation was created
+ `400 Bad Request` When an invalid conversation type was given
+ `400 Bad Request` When the conversation name is empty for `type = 3`
+ `400 Bad Request` When a password is required for a public room or when the password is invalid according to the password policy
+ `401 Unauthorized` When the user is not logged in
+ `404 Not Found` When the target to invite does not exist
@ -283,6 +285,11 @@ Get all (for moderators and in case of "free selection") or the assigned breakou
* Method: `POST`
* Endpoint: `/room/{token}/public`
* Data:
| field | type | Description |
|------------|---------|-------------------------------------------------------------------------------------------------|
| `password` | ?string | Password for the conversation (only available with `conversation-creation-password` capability) |
* Response:
- Status code:

1
docs/settings.md

@ -113,5 +113,6 @@ Legend:
| `conversations_files` | string<br>`1` or `0` | `1` | No | 🖌️ | Whether the files app integration is enabled allowing to start conversations in the right sidebar |
| `conversations_files_public_shares` | string<br>`1` or `0` | `1` | No | 🖌️ | Whether the public share integration is enabled allowing to start conversations in the right sidebar on the public share page (Requires `conversations_files` also to be enabled) |
| `enable_matterbridge` | string<br>`1` or `0` | `0` | No | 🖌️ | Whether the Matterbridge integration is enabled and can be configured |
| `force_passwords` | string<br>`1` or `0` | `0` | No | ️ | Whether public chats are forced to use a password |
| `inactivity_lock_after_days` | int | `0` | No | | A duration (in days) after which rooms are locked. Calculated from the last activity in the room. |
| `inactivity_enable_lobby` | string<br>`1` or `0` | `0` | No | | Additionally enable the lobby for inactive rooms so they can only be read by moderators. |

4
lib/Capabilities.php

@ -109,6 +109,7 @@ class Capabilities implements IPublicCapability {
'talk-polls-drafts',
'download-call-participants',
'email-csv-import',
'conversation-creation-password',
];
public const CONDITIONAL_FEATURES = [
@ -224,7 +225,8 @@ class Capabilities implements IPublicCapability {
'summary-threshold' => 100,
],
'conversations' => [
'can-create' => $user instanceof IUser && !$this->talkConfig->isNotAllowedToCreateConversations($user)
'can-create' => $user instanceof IUser && !$this->talkConfig->isNotAllowedToCreateConversations($user),
'force-passwords' => $this->talkConfig->isPasswordEnforced(),
],
'federation' => [
'enabled' => false,

4
lib/Config.php

@ -705,4 +705,8 @@ class Config {
public function enableLobbyOnLockedRooms(): bool {
return $this->appConfig->getAppValueBool('inactivity_enable_lobby');
}
public function isPasswordEnforced(): bool {
return $this->appConfig->getAppValueBool('force_passwords');
}
}

44
lib/Controller/RoomController.php

@ -502,16 +502,25 @@ class RoomController extends AEnvironmentAwareController {
* @param 'groups'|'circles'|'' $source Source of the invite ID ('circles' to create a room with a circle, etc.)
* @param string $objectType Type of the object
* @param string $objectId ID of the object
* @return DataResponse<Http::STATUS_OK|Http::STATUS_CREATED, TalkRoom, array{}>|DataResponse<Http::STATUS_BAD_REQUEST, array{error?: string}, array{}>|DataResponse<Http::STATUS_FORBIDDEN|Http::STATUS_NOT_FOUND, array<empty>, array{}>
* @param string $password The room password (only available with `conversation-creation-password` capability)
* @return DataResponse<Http::STATUS_OK|Http::STATUS_CREATED, TalkRoom, array{}>|DataResponse<Http::STATUS_BAD_REQUEST, array{error?: string, message?: string}, array{}>|DataResponse<Http::STATUS_FORBIDDEN|Http::STATUS_NOT_FOUND, array<empty>, array{}>
*
* 200: Room already existed
* 201: Room created successfully
* 400: Room type invalid
* 400: Room type invalid or missing or invalid password
* 403: Missing permissions to create room
* 404: User, group or other target to invite was not found
*/
#[NoAdminRequired]
public function createRoom(int $roomType, string $invite = '', string $roomName = '', string $source = '', string $objectType = '', string $objectId = ''): DataResponse {
public function createRoom(
int $roomType,
string $invite = '',
string $roomName = '',
string $source = '',
string $objectType = '',
string $objectId = '',
string $password = '',
): DataResponse {
if ($roomType !== Room::TYPE_ONE_TO_ONE) {
/** @var IUser $user */
$user = $this->userManager->get($this->userId);
@ -533,7 +542,7 @@ class RoomController extends AEnvironmentAwareController {
}
return $this->createGroupRoom($invite);
case Room::TYPE_PUBLIC:
return $this->createEmptyRoom($roomName, true, $objectType, $objectId);
return $this->createEmptyRoom($roomName, true, $objectType, $objectId, $password);
}
return new DataResponse([], Http::STATUS_BAD_REQUEST);
@ -645,10 +654,10 @@ class RoomController extends AEnvironmentAwareController {
}
/**
* @return DataResponse<Http::STATUS_CREATED, TalkRoom, array{}>|DataResponse<Http::STATUS_BAD_REQUEST, array{error?: string}, array{}>|DataResponse<Http::STATUS_NOT_FOUND, array<empty>, array{}>
* @return DataResponse<Http::STATUS_CREATED, TalkRoom, array{}>|DataResponse<Http::STATUS_BAD_REQUEST, array{error?: string, message?: string}, array{}>|DataResponse<Http::STATUS_NOT_FOUND, array<empty>, array{}>
*/
#[NoAdminRequired]
protected function createEmptyRoom(string $roomName, bool $public = true, string $objectType = '', string $objectId = ''): DataResponse {
protected function createEmptyRoom(string $roomName, bool $public = true, string $objectType = '', string $objectId = '', string $password = ''): DataResponse {
$currentUser = $this->userManager->get($this->userId);
if (!$currentUser instanceof IUser) {
return new DataResponse([], Http::STATUS_NOT_FOUND);
@ -686,7 +695,9 @@ class RoomController extends AEnvironmentAwareController {
// Create the room
try {
$room = $this->roomService->createConversation($roomType, $roomName, $currentUser, $objectType, $objectId);
$room = $this->roomService->createConversation($roomType, $roomName, $currentUser, $objectType, $objectId, $password);
} catch (PasswordException $e) {
return new DataResponse(['error' => 'password', 'message' => $e->getHint()], Http::STATUS_BAD_REQUEST);
} catch (\InvalidArgumentException $e) {
return new DataResponse([], Http::STATUS_BAD_REQUEST);
}
@ -1420,16 +1431,29 @@ class RoomController extends AEnvironmentAwareController {
/**
* Allowed guests to join conversation
*
* @return DataResponse<Http::STATUS_OK, array<empty>, array{}>|DataResponse<Http::STATUS_BAD_REQUEST, array{error: 'breakout-room'|'type'|'value'}, array{}>
* Required capability: `conversation-creation-password` for `string $password` parameter
*
* @param string $password New password (only available with `conversation-creation-password` capability)
* @return DataResponse<Http::STATUS_OK, array<empty>, array{}>|DataResponse<Http::STATUS_BAD_REQUEST, array{error: 'breakout-room'|'type'|'value'|'password', message?: null|string}, array{}>
*
* 200: Allowed guests successfully
* 400: Allowing guests is not possible
*/
#[NoAdminRequired]
#[RequireLoggedInModeratorParticipant]
public function makePublic(): DataResponse {
public function makePublic(string $password = ''): DataResponse {
if ($this->talkConfig->isPasswordEnforced() && $password === '') {
return new DataResponse(['error' => 'password', 'message' => $this->l->t('Password needs to be set')], Http::STATUS_BAD_REQUEST);
}
try {
$this->roomService->setType($this->room, Room::TYPE_PUBLIC);
if ($password !== '') {
$this->roomService->makePublicWithPassword($this->room, $password);
} else {
$this->roomService->setType($this->room, Room::TYPE_PUBLIC);
}
} catch (PasswordException $e) {
return new DataResponse(['error' => 'password', 'message' => $e->getHint()], Http::STATUS_BAD_REQUEST);
} catch (TypeException $e) {
return new DataResponse(['error' => $e->getReason()], Http::STATUS_BAD_REQUEST);
}

19
lib/Manager.php

@ -25,6 +25,7 @@ use OCP\AppFramework\Utility\ITimeFactory;
use OCP\Comments\IComment;
use OCP\Comments\ICommentsManager;
use OCP\Comments\NotFoundException;
use OCP\DB\Exception;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\ICache;
@ -1108,7 +1109,7 @@ class Manager {
* @param string $objectId
* @return Room
*/
public function createRoom(int $type, string $name = '', string $objectType = '', string $objectId = ''): Room {
public function createRoom(int $type, string $name = '', string $objectType = '', string $objectId = '', string $password = ''): Room {
$token = $this->getNewToken();
$insert = $this->db->getQueryBuilder();
@ -1118,6 +1119,7 @@ class Manager {
'name' => $insert->createNamedParameter($name),
'type' => $insert->createNamedParameter($type, IQueryBuilder::PARAM_INT),
'token' => $insert->createNamedParameter($token),
'password' => $insert->createNamedParameter($password),
]
);
@ -1135,6 +1137,7 @@ class Manager {
'token' => $token,
'object_type' => $objectType,
'object_id' => $objectId,
'password' => $password
]);
$event = new RoomCreatedEvent($room);
@ -1409,4 +1412,18 @@ class Manager {
$query->selectAlias('c.expire_date', 'comment_expire_date');
$query->selectAlias('c.meta_data', 'comment_meta_data');
}
/**
* @param int $roomId
* @param string $password
* @throws Exception
*/
public function setPublic(int $roomId, string $password = ''): void {
$update = $this->db->getQueryBuilder();
$update->update('talk_rooms')
->set('type', $update->createNamedParameter(Room::TYPE_PUBLIC, IQueryBuilder::PARAM_INT))
->set('password', $update->createNamedParameter($password, IQueryBuilder::PARAM_STR))
->where($update->expr()->eq('id', $update->createNamedParameter($roomId, IQueryBuilder::PARAM_INT)));
$update->executeStatement();
}
}

1
lib/ResponseDefinitions.php

@ -361,6 +361,7 @@ namespace OCA\Talk;
* },
* conversations: array{
* can-create: bool,
* force-passwords: bool,
* },
* federation: array{
* enabled: bool,

103
lib/Service/RoomService.php

@ -57,6 +57,7 @@ use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\HintException;
use OCP\IDBConnection;
use OCP\IL10N;
use OCP\IUser;
use OCP\Log\Audit\CriticalActionPerformedEvent;
use OCP\Security\Events\ValidatePasswordPolicyEvent;
@ -80,6 +81,7 @@ class RoomService {
protected IEventDispatcher $dispatcher,
protected IJobList $jobList,
protected LoggerInterface $logger,
protected IL10N $l10n,
) {
}
@ -127,17 +129,13 @@ class RoomService {
}
/**
* @param int $type
* @param string $name
* @param IUser|null $owner
* @param string $objectType
* @param string $objectId
* @return Room
* @throws InvalidArgumentException on too long or empty names
* @throws InvalidArgumentException unsupported type
* @throws InvalidArgumentException invalid object data
* @throws PasswordException empty or invalid password
*/
public function createConversation(int $type, string $name, ?IUser $owner = null, string $objectType = '', string $objectId = ''): Room {
public function createConversation(int $type, string $name, ?IUser $owner = null, string $objectType = '', string $objectId = '', string $password = ''): Room {
$name = trim($name);
if ($name === '' || mb_strlen($name) > 255) {
throw new InvalidArgumentException('name');
@ -167,7 +165,20 @@ class RoomService {
throw new InvalidArgumentException('object');
}
$room = $this->manager->createRoom($type, $name, $objectType, $objectId);
if ($type !== Room::TYPE_PUBLIC || !$this->config->isPasswordEnforced()) {
$room = $this->manager->createRoom($type, $name, $objectType, $objectId);
} elseif ($password === '') {
throw new PasswordException(PasswordException::REASON_VALUE, $this->l10n->t('Password needs to be set'));
} else {
$event = new ValidatePasswordPolicyEvent($password);
try {
$this->dispatcher->dispatchTyped($event);
} catch (HintException $e) {
throw new PasswordException(PasswordException::REASON_VALUE, $e->getHint());
}
$passwordHash = $this->hasher->hash($password);
$room = $this->manager->createRoom($type, $name, $objectType, $objectId, $passwordHash);
}
if ($owner instanceof IUser) {
$this->participantService->addUsers($room, [[
@ -177,8 +188,8 @@ class RoomService {
'participantType' => Participant::OWNER,
]], null);
}
return $room;
}
public function prepareConversationName(string $objectName): string {
@ -545,6 +556,44 @@ class RoomService {
$this->dispatcher->dispatchTyped($event);
}
/**
* @throws PasswordException|TypeException
*/
public function makePublicWithPassword(Room $room, string $password): void {
if ($room->getType() === Room::TYPE_PUBLIC) {
return;
}
if ($room->getType() !== Room::TYPE_GROUP) {
throw new TypeException(TypeException::REASON_TYPE);
}
if ($password === '') {
throw new PasswordException(PasswordException::REASON_VALUE, $this->l10n->t('Password needs to be set'));
}
$event = new ValidatePasswordPolicyEvent($password);
try {
$this->dispatcher->dispatchTyped($event);
} catch (HintException $e) {
throw new PasswordException(PasswordException::REASON_VALUE, $e->getHint());
}
$event = new BeforeRoomModifiedEvent($room, ARoomModifiedEvent::PROPERTY_TYPE, Room::TYPE_PUBLIC, $room->getType());
$this->dispatcher->dispatchTyped($event);
$event = new BeforeRoomModifiedEvent($room, ARoomModifiedEvent::PROPERTY_PASSWORD, $password);
$this->dispatcher->dispatchTyped($event);
$passwordHash = $this->hasher->hash($password);
$this->manager->setPublic($room->getId(), $passwordHash);
$room->setType(Room::TYPE_PUBLIC);
$event = new RoomModifiedEvent($room, ARoomModifiedEvent::PROPERTY_TYPE, Room::TYPE_PUBLIC, $room->getType());
$this->dispatcher->dispatchTyped($event);
$event = new RoomModifiedEvent($room, ARoomModifiedEvent::PROPERTY_PASSWORD, $password);
$this->dispatcher->dispatchTyped($event);
}
/**
* @param Room $room
* @param int $newState Currently it is only allowed to change between
@ -1221,4 +1270,42 @@ class RoomService {
public function getInactiveRooms(\DateTime $inactiveSince): array {
return $this->manager->getInactiveRooms($inactiveSince);
}
/**
* @param Room $room
* @param int $oldType
* @param int $newType
* @param bool $allowSwitchingOneToOne
* @return void
*/
public function validateRoomTypeSwitch(Room $room, int $oldType, int $newType, bool $allowSwitchingOneToOne): void {
if (!$allowSwitchingOneToOne && $oldType === Room::TYPE_ONE_TO_ONE) {
throw new TypeException(TypeException::REASON_TYPE);
}
if ($oldType === Room::TYPE_ONE_TO_ONE_FORMER) {
throw new TypeException(TypeException::REASON_TYPE);
}
if ($oldType === Room::TYPE_NOTE_TO_SELF) {
throw new TypeException(TypeException::REASON_TYPE);
}
if (!in_array($newType, [Room::TYPE_GROUP, Room::TYPE_PUBLIC, Room::TYPE_ONE_TO_ONE_FORMER], true)) {
throw new TypeException(TypeException::REASON_VALUE);
}
if ($newType === Room::TYPE_ONE_TO_ONE_FORMER && $oldType !== Room::TYPE_ONE_TO_ONE) {
throw new TypeException(TypeException::REASON_VALUE);
}
if ($room->getBreakoutRoomMode() !== BreakoutRoom::MODE_NOT_CONFIGURED) {
throw new TypeException(TypeException::REASON_BREAKOUT_ROOM);
}
if ($room->getObjectType() === BreakoutRoom::PARENT_OBJECT_TYPE) {
throw new TypeException(TypeException::REASON_BREAKOUT_ROOM);
}
}
}

6
openapi-administration.json

@ -237,11 +237,15 @@
"conversations": {
"type": "object",
"required": [
"can-create"
"can-create",
"force-passwords"
],
"properties": {
"can-create": {
"type": "boolean"
},
"force-passwords": {
"type": "boolean"
}
}
},

6
openapi-backend-recording.json

@ -170,11 +170,15 @@
"conversations": {
"type": "object",
"required": [
"can-create"
"can-create",
"force-passwords"
],
"properties": {
"can-create": {
"type": "boolean"
},
"force-passwords": {
"type": "boolean"
}
}
},

6
openapi-backend-signaling.json

@ -170,11 +170,15 @@
"conversations": {
"type": "object",
"required": [
"can-create"
"can-create",
"force-passwords"
],
"properties": {
"can-create": {
"type": "boolean"
},
"force-passwords": {
"type": "boolean"
}
}
},

6
openapi-backend-sipbridge.json

@ -213,11 +213,15 @@
"conversations": {
"type": "object",
"required": [
"can-create"
"can-create",
"force-passwords"
],
"properties": {
"can-create": {
"type": "boolean"
},
"force-passwords": {
"type": "boolean"
}
}
},

6
openapi-bots.json

@ -170,11 +170,15 @@
"conversations": {
"type": "object",
"required": [
"can-create"
"can-create",
"force-passwords"
],
"properties": {
"can-create": {
"type": "boolean"
},
"force-passwords": {
"type": "boolean"
}
}
},

6
openapi-federation.json

@ -213,11 +213,15 @@
"conversations": {
"type": "object",
"required": [
"can-create"
"can-create",
"force-passwords"
],
"properties": {
"can-create": {
"type": "boolean"
},
"force-passwords": {
"type": "boolean"
}
}
},

41
openapi-full.json

@ -389,11 +389,15 @@
"conversations": {
"type": "object",
"required": [
"can-create"
"can-create",
"force-passwords"
],
"properties": {
"can-create": {
"type": "boolean"
},
"force-passwords": {
"type": "boolean"
}
}
},
@ -11252,6 +11256,11 @@
"type": "string",
"default": "",
"description": "ID of the object"
},
"password": {
"type": "string",
"default": "",
"description": "The room password (only available with `conversation-creation-password` capability)"
}
}
}
@ -11344,7 +11353,7 @@
}
},
"400": {
"description": "Room type invalid",
"description": "Room type invalid or missing or invalid password",
"content": {
"application/json": {
"schema": {
@ -11368,6 +11377,9 @@
"properties": {
"error": {
"type": "string"
},
"message": {
"type": "string"
}
}
}
@ -11882,6 +11894,7 @@
"post": {
"operationId": "room-make-public",
"summary": "Allowed guests to join conversation",
"description": "Required capability: `conversation-creation-password` for `string $password` parameter",
"tags": [
"room"
],
@ -11893,6 +11906,23 @@
"basic_auth": []
}
],
"requestBody": {
"required": false,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"password": {
"type": "string",
"default": "",
"description": "New password (only available with `conversation-creation-password` capability)"
}
}
}
}
}
},
"parameters": [
{
"name": "apiVersion",
@ -11986,8 +12016,13 @@
"enum": [
"breakout-room",
"type",
"value"
"value",
"password"
]
},
"message": {
"type": "string",
"nullable": true
}
}
}

41
openapi.json

@ -330,11 +330,15 @@
"conversations": {
"type": "object",
"required": [
"can-create"
"can-create",
"force-passwords"
],
"properties": {
"can-create": {
"type": "boolean"
},
"force-passwords": {
"type": "boolean"
}
}
},
@ -11139,6 +11143,11 @@
"type": "string",
"default": "",
"description": "ID of the object"
},
"password": {
"type": "string",
"default": "",
"description": "The room password (only available with `conversation-creation-password` capability)"
}
}
}
@ -11231,7 +11240,7 @@
}
},
"400": {
"description": "Room type invalid",
"description": "Room type invalid or missing or invalid password",
"content": {
"application/json": {
"schema": {
@ -11255,6 +11264,9 @@
"properties": {
"error": {
"type": "string"
},
"message": {
"type": "string"
}
}
}
@ -12016,6 +12028,7 @@
"post": {
"operationId": "room-make-public",
"summary": "Allowed guests to join conversation",
"description": "Required capability: `conversation-creation-password` for `string $password` parameter",
"tags": [
"room"
],
@ -12027,6 +12040,23 @@
"basic_auth": []
}
],
"requestBody": {
"required": false,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"password": {
"type": "string",
"default": "",
"description": "New password (only available with `conversation-creation-password` capability)"
}
}
}
}
}
},
"parameters": [
{
"name": "apiVersion",
@ -12120,8 +12150,13 @@
"enum": [
"breakout-room",
"type",
"value"
"value",
"password"
]
},
"message": {
"type": "string",
"nullable": true
}
}
}

1
src/__mocks__/capabilities.ts

@ -130,6 +130,7 @@ export const mockedCapabilities: Capabilities = {
},
conversations: {
'can-create': true,
'force-passwords': false,
},
federation: {
enabled: false,

1
src/types/openapi/openapi-administration.ts

@ -246,6 +246,7 @@ export type components = {
};
conversations: {
"can-create": boolean;
"force-passwords": boolean;
};
federation: {
enabled: boolean;

1
src/types/openapi/openapi-backend-recording.ts

@ -80,6 +80,7 @@ export type components = {
};
conversations: {
"can-create": boolean;
"force-passwords": boolean;
};
federation: {
enabled: boolean;

1
src/types/openapi/openapi-backend-signaling.ts

@ -66,6 +66,7 @@ export type components = {
};
conversations: {
"can-create": boolean;
"force-passwords": boolean;
};
federation: {
enabled: boolean;

1
src/types/openapi/openapi-backend-sipbridge.ts

@ -161,6 +161,7 @@ export type components = {
};
conversations: {
"can-create": boolean;
"force-passwords": boolean;
};
federation: {
enabled: boolean;

1
src/types/openapi/openapi-bots.ts

@ -84,6 +84,7 @@ export type components = {
};
conversations: {
"can-create": boolean;
"force-passwords": boolean;
};
federation: {
enabled: boolean;

1
src/types/openapi/openapi-federation.ts

@ -192,6 +192,7 @@ export type components = {
};
conversations: {
"can-create": boolean;
"force-passwords": boolean;
};
federation: {
enabled: boolean;

29
src/types/openapi/openapi-full.ts

@ -855,7 +855,10 @@ export type paths = {
};
get?: never;
put?: never;
/** Allowed guests to join conversation */
/**
* Allowed guests to join conversation
* @description Required capability: `conversation-creation-password` for `string $password` parameter
*/
post: operations["room-make-public"];
/** Disallowed guests to join conversation */
delete: operations["room-make-private"];
@ -1989,6 +1992,7 @@ export type components = {
};
conversations: {
"can-create": boolean;
"force-passwords": boolean;
};
federation: {
enabled: boolean;
@ -6215,6 +6219,11 @@ export interface operations {
* @default
*/
objectId?: string;
/**
* @description The room password (only available with `conversation-creation-password` capability)
* @default
*/
password?: string;
};
};
};
@ -6247,7 +6256,7 @@ export interface operations {
};
};
};
/** @description Room type invalid */
/** @description Room type invalid or missing or invalid password */
400: {
headers: {
[name: string]: unknown;
@ -6258,6 +6267,7 @@ export interface operations {
meta: components["schemas"]["OCSMeta"];
data: {
error?: string;
message?: string;
};
};
};
@ -6478,7 +6488,17 @@ export interface operations {
};
cookie?: never;
};
requestBody?: never;
requestBody?: {
content: {
"application/json": {
/**
* @description New password (only available with `conversation-creation-password` capability)
* @default
*/
password?: string;
};
};
};
responses: {
/** @description Allowed guests successfully */
200: {
@ -6505,7 +6525,8 @@ export interface operations {
meta: components["schemas"]["OCSMeta"];
data: {
/** @enum {string} */
error: "breakout-room" | "type" | "value";
error: "breakout-room" | "type" | "value" | "password";
message?: string | null;
};
};
};

29
src/types/openapi/openapi.ts

@ -857,7 +857,10 @@ export type paths = {
};
get?: never;
put?: never;
/** Allowed guests to join conversation */
/**
* Allowed guests to join conversation
* @description Required capability: `conversation-creation-password` for `string $password` parameter
*/
post: operations["room-make-public"];
/** Disallowed guests to join conversation */
delete: operations["room-make-private"];
@ -1486,6 +1489,7 @@ export type components = {
};
conversations: {
"can-create": boolean;
"force-passwords": boolean;
};
federation: {
enabled: boolean;
@ -5696,6 +5700,11 @@ export interface operations {
* @default
*/
objectId?: string;
/**
* @description The room password (only available with `conversation-creation-password` capability)
* @default
*/
password?: string;
};
};
};
@ -5728,7 +5737,7 @@ export interface operations {
};
};
};
/** @description Room type invalid */
/** @description Room type invalid or missing or invalid password */
400: {
headers: {
[name: string]: unknown;
@ -5739,6 +5748,7 @@ export interface operations {
meta: components["schemas"]["OCSMeta"];
data: {
error?: string;
message?: string;
};
};
};
@ -6059,7 +6069,17 @@ export interface operations {
};
cookie?: never;
};
requestBody?: never;
requestBody?: {
content: {
"application/json": {
/**
* @description New password (only available with `conversation-creation-password` capability)
* @default
*/
password?: string;
};
};
};
responses: {
/** @description Allowed guests successfully */
200: {
@ -6086,7 +6106,8 @@ export interface operations {
meta: components["schemas"]["OCSMeta"];
data: {
/** @enum {string} */
error: "breakout-room" | "type" | "value";
error: "breakout-room" | "type" | "value" | "password";
message?: string | null;
};
};
};

2
tests/php/CapabilitiesTest.php

@ -152,6 +152,7 @@ class CapabilitiesTest extends TestCase {
],
'conversations' => [
'can-create' => false,
'force-passwords' => false,
],
'federation' => [
'enabled' => false,
@ -284,6 +285,7 @@ class CapabilitiesTest extends TestCase {
],
'conversations' => [
'can-create' => $canCreate,
'force-passwords' => false,
],
'federation' => [
'enabled' => false,

5
tests/php/Service/RoomServiceTest.php

@ -26,6 +26,7 @@ use OCP\AppFramework\Utility\ITimeFactory;
use OCP\BackgroundJob\IJobList;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\IDBConnection;
use OCP\IL10N;
use OCP\IUser;
use OCP\Security\IHasher;
use OCP\Share\IManager as IShareManager;
@ -46,6 +47,7 @@ class RoomServiceTest extends TestCase {
protected IEventDispatcher&MockObject $dispatcher;
protected IJobList&MockObject $jobList;
protected LoggerInterface&MockObject $logger;
protected IL10N&MockObject $l10n;
protected ?RoomService $service = null;
public function setUp(): void {
@ -60,6 +62,7 @@ class RoomServiceTest extends TestCase {
$this->dispatcher = $this->createMock(IEventDispatcher::class);
$this->jobList = $this->createMock(IJobList::class);
$this->logger = $this->createMock(LoggerInterface::class);
$this->l10n = $this->createMock(IL10N::class);
$this->service = new RoomService(
$this->manager,
$this->participantService,
@ -71,6 +74,7 @@ class RoomServiceTest extends TestCase {
$this->dispatcher,
$this->jobList,
$this->logger,
$this->l10n,
);
}
@ -332,6 +336,7 @@ class RoomServiceTest extends TestCase {
$dispatcher,
$this->jobList,
$this->logger,
$this->l10n,
);
$room = new Room(

Loading…
Cancel
Save