diff --git a/appinfo/info.xml b/appinfo/info.xml
index c5243f4c29a..fdc4c96394f 100644
--- a/appinfo/info.xml
+++ b/appinfo/info.xml
@@ -18,7 +18,7 @@
* 🌉 **Sync with other chat solutions** With [Matterbridge](https://github.com/42wim/matterbridge/) being integrated in Talk, you can easily sync a lot of other chat solutions to Nextcloud Talk and vice-versa.
]]>
- 21.0.0-dev.0
+ 21.0.0-dev.1
agpl
Daniel Calviño Sánchez
diff --git a/appinfo/routes/routesRoomController.php b/appinfo/routes/routesRoomController.php
index ee176504f7b..0c2d29febbe 100644
--- a/appinfo/routes/routesRoomController.php
+++ b/appinfo/routes/routesRoomController.php
@@ -111,5 +111,9 @@
['name' => 'Room#getCapabilities', 'url' => '/api/{apiVersion}/room/{token}/capabilities', 'verb' => 'GET', 'requirements' => $requirementsWithToken],
/** @see \OCA\Talk\Controller\RoomController::setMentionPermissions() */
['name' => 'Room#setMentionPermissions', 'url' => '/api/{apiVersion}/room/{token}/mention-permissions', 'verb' => 'PUT', 'requirements' => $requirementsWithToken],
+ /** @see \OCA\Talk\Controller\RoomController::archiveConversation() */
+ ['name' => 'Room#archiveConversation', 'url' => '/api/{apiVersion}/room/{token}/archive', 'verb' => 'POST', 'requirements' => $requirementsWithToken],
+ /** @see \OCA\Talk\Controller\RoomController::unarchiveConversation() */
+ ['name' => 'Room#unarchiveConversation', 'url' => '/api/{apiVersion}/room/{token}/archive', 'verb' => 'DELETE', 'requirements' => $requirementsWithToken],
],
];
diff --git a/docs/capabilities.md b/docs/capabilities.md
index dcb7214801c..7fdd4f639b3 100644
--- a/docs/capabilities.md
+++ b/docs/capabilities.md
@@ -155,3 +155,6 @@
* `mention-permissions` - Whether non-moderators are allowed to mention `@all`
* `federation-v2` - Whether federated session ids are used and calls are possible with federation
* `edit-messages-note-to-self` - Messages in note-to-self conversations can be edited indefinitely
+
+## 20.1
+* `archived-conversations` (local) - Conversations can be marked as archived which will hide them from the conversation list by default
diff --git a/docs/conversation.md b/docs/conversation.md
index b2e37065bbe..efd24a8fde5 100644
--- a/docs/conversation.md
+++ b/docs/conversation.md
@@ -110,6 +110,7 @@
| `callRecording` | int | v4 | | Type of call recording (see [Constants - Call recording status](constants.md#call-recording-status)) (only available with `recording-v1` capability) |
| `recordingConsent` | int | v4 | | Whether recording consent is required before joining a call (Only 0 and 1 will be returned, see [constants list](constants.md#recording-consent-required)) (only available with `recording-consent` capability) |
| `mentionPermissions` | int | v4 | | Whether all participants can mention using `@all` or only moderators (see [constants list](constants.md#mention-permissions)) (only available with `mention-permissions` capability) |
+| `isArchived` | bool | v4 | | Flag if the conversation is archived by the user (only available with `archived-conversations` capability) | |
## Creating a new conversation
diff --git a/lib/Capabilities.php b/lib/Capabilities.php
index 5df082d7391..0cff6f89ae4 100644
--- a/lib/Capabilities.php
+++ b/lib/Capabilities.php
@@ -103,6 +103,7 @@ class Capabilities implements IPublicCapability {
'chat-reference-id',
'mention-permissions',
'edit-messages-note-to-self',
+ 'archived-conversations',
];
public const LOCAL_FEATURES = [
@@ -115,6 +116,7 @@ class Capabilities implements IPublicCapability {
'avatar',
'remind-me-later',
'note-to-self',
+ 'archived-conversations',
];
public const LOCAL_CONFIGS = [
diff --git a/lib/Chat/Notifier.php b/lib/Chat/Notifier.php
index 653efb57205..a48f199aed7 100644
--- a/lib/Chat/Notifier.php
+++ b/lib/Chat/Notifier.php
@@ -76,9 +76,8 @@ public function notifyMentionedUsers(Room $chat, IComment $comment, array $alrea
$shouldFlush = $this->notificationManager->defer();
}
-
foreach ($usersToNotify as $mentionedUser) {
- if ($this->shouldMentionedUserBeNotified($mentionedUser['id'], $comment, $chat, $mentionedUser['attendee'] ?? null)) {
+ if ($this->shouldMentionedUserBeNotified($mentionedUser['id'], $comment, $chat, $mentionedUser['attendee'] ?? null, $mentionedUser['reason'])) {
if (!$silent) {
$notification->setUser($mentionedUser['id']);
if (isset($mentionedUser['reason'])) {
@@ -210,7 +209,7 @@ public function notifyReplyToAuthor(Room $chat, IComment $comment, IComment $rep
];
}
- if (!$this->shouldMentionedUserBeNotified($replyTo->getActorId(), $comment, $chat)) {
+ if (!$this->shouldMentionedUserBeNotified($replyTo->getActorId(), $comment, $chat, null, 'reply')) {
return [];
}
@@ -565,14 +564,8 @@ protected function getDefaultGroupNotification(): int {
* 2. The user must exist
* 3. The user must be a participant of the room
* 4. The user must not be active in the room
- *
- * @param string $userId
- * @param IComment $comment
- * @param Room $room
- * @param Attendee|null $attendee
- * @return bool
*/
- protected function shouldMentionedUserBeNotified(string $userId, IComment $comment, Room $room, ?Attendee $attendee = null): bool {
+ protected function shouldMentionedUserBeNotified(string $userId, IComment $comment, Room $room, ?Attendee $attendee, string $reason): bool {
if ($comment->getActorType() === Attendee::ACTOR_USERS && $userId === $comment->getActorId()) {
// Do not notify the user if they mentioned themselves
return false;
@@ -590,6 +583,10 @@ protected function shouldMentionedUserBeNotified(string $userId, IComment $comme
$participant = new Participant($room, $attendee, null);
}
+ if ($reason === 'all' && $attendee->isArchived()) {
+ return false;
+ }
+
if ($room->getLobbyState() !== Webinary::LOBBY_NONE &&
!($participant->getPermissions() & Attendee::PERMISSIONS_LOBBY_IGNORE)) {
return false;
diff --git a/lib/Controller/RoomController.php b/lib/Controller/RoomController.php
index bbb38774574..d8b47b9604f 100644
--- a/lib/Controller/RoomController.php
+++ b/lib/Controller/RoomController.php
@@ -1543,6 +1543,36 @@ public function setPassword(string $password): DataResponse {
return new DataResponse();
}
+ /**
+ * Archive a conversation
+ *
+ * @return DataResponse
+ *
+ * 200: Conversation was archived
+ */
+ #[NoAdminRequired]
+ #[FederationSupported]
+ #[RequireLoggedInParticipant]
+ public function archiveConversation(): DataResponse {
+ $this->participantService->archiveConversation($this->participant);
+ return new DataResponse($this->formatRoom($this->room, $this->participant));
+ }
+
+ /**
+ * Unarchive a conversation
+ *
+ * @return DataResponse
+ *
+ * 200: Conversation was unarchived
+ */
+ #[NoAdminRequired]
+ #[FederationSupported]
+ #[RequireLoggedInParticipant]
+ public function unarchiveConversation(): DataResponse {
+ $this->participantService->unarchiveConversation($this->participant);
+ return new DataResponse($this->formatRoom($this->room, $this->participant));
+ }
+
/**
* Join a room
*
diff --git a/lib/Migration/Version21000Date20240919222538.php b/lib/Migration/Version21000Date20240919222538.php
new file mode 100644
index 00000000000..a5e01731f6c
--- /dev/null
+++ b/lib/Migration/Version21000Date20240919222538.php
@@ -0,0 +1,40 @@
+getTable('talk_attendees');
+ if (!$table->hasColumn('archived')) {
+ $table->addColumn('archived', Types::BOOLEAN, [
+ 'default' => 0,
+ 'notnull' => false,
+ ]);
+ }
+
+ return $schema;
+ }
+}
diff --git a/lib/Model/Attendee.php b/lib/Model/Attendee.php
index 2682c9b44f9..74527b32632 100644
--- a/lib/Model/Attendee.php
+++ b/lib/Model/Attendee.php
@@ -39,6 +39,8 @@
* @method void setReadPrivacy(int $readPrivacy)
* @method int getReadPrivacy()
* @method void setPermissions(int $permissions)
+ * @method void setArchived(bool $archived)
+ * @method bool isArchived()
* @internal
* @method int getPermissions()
* @method void setAccessToken(string $accessToken)
@@ -108,6 +110,7 @@ class Attendee extends Entity {
protected bool $favorite = false;
protected int $notificationLevel = 0;
protected int $notificationCalls = 0;
+ protected bool $archived = false;
protected int $lastJoinedCall = 0;
protected int $lastReadMessage = 0;
protected int $lastMentionMessage = 0;
@@ -131,6 +134,7 @@ public function __construct() {
$this->addType('pin', 'string');
$this->addType('participantType', 'int');
$this->addType('favorite', 'bool');
+ $this->addType('archived', 'bool');
$this->addType('notificationLevel', 'int');
$this->addType('notificationCalls', 'int');
$this->addType('lastJoinedCall', 'int');
diff --git a/lib/Model/AttendeeMapper.php b/lib/Model/AttendeeMapper.php
index 2448942ed69..100f1a7a5b1 100644
--- a/lib/Model/AttendeeMapper.php
+++ b/lib/Model/AttendeeMapper.php
@@ -324,6 +324,7 @@ public function createAttendeeFromRow(array $row): Attendee {
'state' => (int)$row['state'],
'unread_messages' => (int)$row['unread_messages'],
'last_attendee_activity' => (int)$row['last_attendee_activity'],
+ 'archived' => (bool)$row['archived'],
]);
}
}
diff --git a/lib/Model/SelectHelper.php b/lib/Model/SelectHelper.php
index c3022c4445f..14f5dc36f96 100644
--- a/lib/Model/SelectHelper.php
+++ b/lib/Model/SelectHelper.php
@@ -76,6 +76,7 @@ public function selectAttendeesTable(IQueryBuilder $query, string $alias = 'a'):
->addSelect($alias . 'state')
->addSelect($alias . 'unread_messages')
->addSelect($alias . 'last_attendee_activity')
+ ->addSelect($alias . 'archived')
->selectAlias($alias . 'id', 'a_id');
}
diff --git a/lib/ResponseDefinitions.php b/lib/ResponseDefinitions.php
index f690e01829e..7344e078f6c 100644
--- a/lib/ResponseDefinitions.php
+++ b/lib/ResponseDefinitions.php
@@ -278,6 +278,7 @@
* unreadMention: bool,
* unreadMentionDirect: bool,
* unreadMessages: int,
+ * isArchived: bool,
* }
*
* @psalm-type TalkSignalingSession = array{
diff --git a/lib/Service/ParticipantService.php b/lib/Service/ParticipantService.php
index b89d2e9e257..16e9db52ad4 100644
--- a/lib/Service/ParticipantService.php
+++ b/lib/Service/ParticipantService.php
@@ -298,6 +298,26 @@ public function updateNotificationCalls(Participant $participant, int $level): v
$this->attendeeMapper->update($attendee);
}
+ /**
+ * @param Participant $participant
+ */
+ public function archiveConversation(Participant $participant): void {
+ $attendee = $participant->getAttendee();
+ $attendee->setArchived(true);
+ $attendee->setLastAttendeeActivity($this->timeFactory->getTime());
+ $this->attendeeMapper->update($attendee);
+ }
+
+ /**
+ * @param Participant $participant
+ */
+ public function unarchiveConversation(Participant $participant): void {
+ $attendee = $participant->getAttendee();
+ $attendee->setArchived(false);
+ $attendee->setLastAttendeeActivity($this->timeFactory->getTime());
+ $this->attendeeMapper->update($attendee);
+ }
+
/**
* @param RoomService $roomService
* @param Room $room
@@ -1733,6 +1753,7 @@ public function getParticipantUserIdsForCallNotifications(Room $room): array {
->where($query->expr()->eq('a.room_id', $query->createNamedParameter($room->getId(), IQueryBuilder::PARAM_INT)))
->andWhere($query->expr()->eq('a.actor_type', $query->createNamedParameter(Attendee::ACTOR_USERS)))
->andWhere($query->expr()->eq('a.notification_calls', $query->createNamedParameter(Participant::NOTIFY_CALLS_ON)))
+ ->andWhere($query->expr()->eq('a.archived', $query->createNamedParameter(false, IQueryBuilder::PARAM_BOOL)))
->andWhere($query->expr()->isNull('s.in_call'));
if ($room->getLobbyState() !== Webinary::LOBBY_NONE) {
diff --git a/lib/Service/RoomFormatter.php b/lib/Service/RoomFormatter.php
index 92d9cee65bf..eeab3e1ab8b 100644
--- a/lib/Service/RoomFormatter.php
+++ b/lib/Service/RoomFormatter.php
@@ -140,6 +140,7 @@ public function formatRoomV4(
'breakoutRoomStatus' => BreakoutRoom::STATUS_STOPPED,
'recordingConsent' => $this->talkConfig->recordingConsentRequired() === RecordingService::CONSENT_REQUIRED_OPTIONAL ? $room->getRecordingConsent() : $this->talkConfig->recordingConsentRequired(),
'mentionPermissions' => Room::MENTION_PERMISSIONS_EVERYONE,
+ 'isArchived' => false,
];
if ($room->isFederatedConversation()) {
@@ -223,6 +224,7 @@ public function formatRoomV4(
'breakoutRoomMode' => $room->getBreakoutRoomMode(),
'breakoutRoomStatus' => $room->getBreakoutRoomStatus(),
'mentionPermissions' => $room->getMentionPermissions(),
+ 'isArchived' => $attendee->isArchived(),
]);
if ($room->isFederatedConversation()) {
diff --git a/openapi-backend-sipbridge.json b/openapi-backend-sipbridge.json
index de382613f1b..9dd9c985c56 100644
--- a/openapi-backend-sipbridge.json
+++ b/openapi-backend-sipbridge.json
@@ -554,7 +554,8 @@
"type",
"unreadMention",
"unreadMentionDirect",
- "unreadMessages"
+ "unreadMessages",
+ "isArchived"
],
"properties": {
"actorId": {
@@ -769,6 +770,9 @@
"unreadMessages": {
"type": "integer",
"format": "int64"
+ },
+ "isArchived": {
+ "type": "boolean"
}
}
},
diff --git a/openapi-federation.json b/openapi-federation.json
index 7e9364ada09..2b7b8a278b5 100644
--- a/openapi-federation.json
+++ b/openapi-federation.json
@@ -608,7 +608,8 @@
"type",
"unreadMention",
"unreadMentionDirect",
- "unreadMessages"
+ "unreadMessages",
+ "isArchived"
],
"properties": {
"actorId": {
@@ -823,6 +824,9 @@
"unreadMessages": {
"type": "integer",
"format": "int64"
+ },
+ "isArchived": {
+ "type": "boolean"
}
}
},
diff --git a/openapi-full.json b/openapi-full.json
index 57cd23cf210..6fe5a4e43db 100644
--- a/openapi-full.json
+++ b/openapi-full.json
@@ -1142,7 +1142,8 @@
"type",
"unreadMention",
"unreadMentionDirect",
- "unreadMessages"
+ "unreadMessages",
+ "isArchived"
],
"properties": {
"actorId": {
@@ -1357,6 +1358,9 @@
"unreadMessages": {
"type": "integer",
"format": "int64"
+ },
+ "isArchived": {
+ "type": "boolean"
}
}
},
@@ -15806,6 +15810,168 @@
}
}
},
+ "/ocs/v2.php/apps/spreed/api/{apiVersion}/room/{token}/archive": {
+ "post": {
+ "operationId": "room-archive-conversation",
+ "summary": "Archive a conversation",
+ "tags": [
+ "room"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "apiVersion",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string",
+ "enum": [
+ "v4"
+ ],
+ "default": "v4"
+ }
+ },
+ {
+ "name": "token",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string",
+ "pattern": "^[a-z0-9]{4,30}$"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Conversation was archived",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "$ref": "#/components/schemas/Room"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "delete": {
+ "operationId": "room-unarchive-conversation",
+ "summary": "Unarchive a conversation",
+ "tags": [
+ "room"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "apiVersion",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string",
+ "enum": [
+ "v4"
+ ],
+ "default": "v4"
+ }
+ },
+ {
+ "name": "token",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string",
+ "pattern": "^[a-z0-9]{4,30}$"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Conversation was unarchived",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "$ref": "#/components/schemas/Room"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/ocs/v2.php/apps/spreed/api/{apiVersion}/settings/user": {
"post": {
"operationId": "settings-set-user-setting",
diff --git a/openapi.json b/openapi.json
index 3e3a6b48a4f..fcab24e35c5 100644
--- a/openapi.json
+++ b/openapi.json
@@ -1029,7 +1029,8 @@
"type",
"unreadMention",
"unreadMentionDirect",
- "unreadMessages"
+ "unreadMessages",
+ "isArchived"
],
"properties": {
"actorId": {
@@ -1244,6 +1245,9 @@
"unreadMessages": {
"type": "integer",
"format": "int64"
+ },
+ "isArchived": {
+ "type": "boolean"
}
}
},
@@ -15940,6 +15944,168 @@
}
}
},
+ "/ocs/v2.php/apps/spreed/api/{apiVersion}/room/{token}/archive": {
+ "post": {
+ "operationId": "room-archive-conversation",
+ "summary": "Archive a conversation",
+ "tags": [
+ "room"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "apiVersion",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string",
+ "enum": [
+ "v4"
+ ],
+ "default": "v4"
+ }
+ },
+ {
+ "name": "token",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string",
+ "pattern": "^[a-z0-9]{4,30}$"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Conversation was archived",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "$ref": "#/components/schemas/Room"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "delete": {
+ "operationId": "room-unarchive-conversation",
+ "summary": "Unarchive a conversation",
+ "tags": [
+ "room"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "apiVersion",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string",
+ "enum": [
+ "v4"
+ ],
+ "default": "v4"
+ }
+ },
+ {
+ "name": "token",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string",
+ "pattern": "^[a-z0-9]{4,30}$"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Conversation was unarchived",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "$ref": "#/components/schemas/Room"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/ocs/v2.php/apps/spreed/api/{apiVersion}/settings/user": {
"post": {
"operationId": "settings-set-user-setting",
diff --git a/src/types/openapi/openapi-backend-sipbridge.ts b/src/types/openapi/openapi-backend-sipbridge.ts
index 7b16c3f74b7..e52a228156f 100644
--- a/src/types/openapi/openapi-backend-sipbridge.ts
+++ b/src/types/openapi/openapi-backend-sipbridge.ts
@@ -332,6 +332,7 @@ export type components = {
unreadMentionDirect: boolean;
/** Format: int64 */
unreadMessages: number;
+ isArchived: boolean;
};
RoomLastMessage: components["schemas"]["ChatMessage"] | components["schemas"]["ChatProxyMessage"];
};
diff --git a/src/types/openapi/openapi-federation.ts b/src/types/openapi/openapi-federation.ts
index 980015022a6..1aabd84c1f2 100644
--- a/src/types/openapi/openapi-federation.ts
+++ b/src/types/openapi/openapi-federation.ts
@@ -379,6 +379,7 @@ export type components = {
unreadMentionDirect: boolean;
/** Format: int64 */
unreadMessages: number;
+ isArchived: boolean;
};
RoomLastMessage: components["schemas"]["ChatMessage"] | components["schemas"]["ChatProxyMessage"];
};
diff --git a/src/types/openapi/openapi-full.ts b/src/types/openapi/openapi-full.ts
index dd7cc552370..8cbdba663d4 100644
--- a/src/types/openapi/openapi-full.ts
+++ b/src/types/openapi/openapi-full.ts
@@ -1222,6 +1222,24 @@ export type paths = {
patch?: never;
trace?: never;
};
+ "/ocs/v2.php/apps/spreed/api/{apiVersion}/room/{token}/archive": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get?: never;
+ put?: never;
+ /** Archive a conversation */
+ post: operations["room-archive-conversation"];
+ /** Unarchive a conversation */
+ delete: operations["room-unarchive-conversation"];
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
"/ocs/v2.php/apps/spreed/api/{apiVersion}/settings/user": {
parameters: {
query?: never;
@@ -2175,6 +2193,7 @@ export type components = {
unreadMentionDirect: boolean;
/** Format: int64 */
unreadMessages: number;
+ isArchived: boolean;
};
RoomLastMessage: components["schemas"]["ChatMessage"] | components["schemas"]["ChatProxyMessage"];
SignalingSession: {
@@ -7994,6 +8013,68 @@ export interface operations {
};
};
};
+ "room-archive-conversation": {
+ parameters: {
+ query?: never;
+ header: {
+ /** @description Required to be true for the API request to pass */
+ "OCS-APIRequest": boolean;
+ };
+ path: {
+ apiVersion: "v4";
+ token: string;
+ };
+ cookie?: never;
+ };
+ requestBody?: never;
+ responses: {
+ /** @description Conversation was archived */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": {
+ ocs: {
+ meta: components["schemas"]["OCSMeta"];
+ data: components["schemas"]["Room"];
+ };
+ };
+ };
+ };
+ };
+ };
+ "room-unarchive-conversation": {
+ parameters: {
+ query?: never;
+ header: {
+ /** @description Required to be true for the API request to pass */
+ "OCS-APIRequest": boolean;
+ };
+ path: {
+ apiVersion: "v4";
+ token: string;
+ };
+ cookie?: never;
+ };
+ requestBody?: never;
+ responses: {
+ /** @description Conversation was unarchived */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": {
+ ocs: {
+ meta: components["schemas"]["OCSMeta"];
+ data: components["schemas"]["Room"];
+ };
+ };
+ };
+ };
+ };
+ };
"settings-set-user-setting": {
parameters: {
query?: never;
diff --git a/src/types/openapi/openapi.ts b/src/types/openapi/openapi.ts
index d2ec65d2d52..594f0479e2e 100644
--- a/src/types/openapi/openapi.ts
+++ b/src/types/openapi/openapi.ts
@@ -1224,6 +1224,24 @@ export type paths = {
patch?: never;
trace?: never;
};
+ "/ocs/v2.php/apps/spreed/api/{apiVersion}/room/{token}/archive": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ get?: never;
+ put?: never;
+ /** Archive a conversation */
+ post: operations["room-archive-conversation"];
+ /** Unarchive a conversation */
+ delete: operations["room-unarchive-conversation"];
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
"/ocs/v2.php/apps/spreed/api/{apiVersion}/settings/user": {
parameters: {
query?: never;
@@ -1656,6 +1674,7 @@ export type components = {
unreadMentionDirect: boolean;
/** Format: int64 */
unreadMessages: number;
+ isArchived: boolean;
};
RoomLastMessage: components["schemas"]["ChatMessage"] | components["schemas"]["ChatProxyMessage"];
SignalingSession: {
@@ -7575,6 +7594,68 @@ export interface operations {
};
};
};
+ "room-archive-conversation": {
+ parameters: {
+ query?: never;
+ header: {
+ /** @description Required to be true for the API request to pass */
+ "OCS-APIRequest": boolean;
+ };
+ path: {
+ apiVersion: "v4";
+ token: string;
+ };
+ cookie?: never;
+ };
+ requestBody?: never;
+ responses: {
+ /** @description Conversation was archived */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": {
+ ocs: {
+ meta: components["schemas"]["OCSMeta"];
+ data: components["schemas"]["Room"];
+ };
+ };
+ };
+ };
+ };
+ };
+ "room-unarchive-conversation": {
+ parameters: {
+ query?: never;
+ header: {
+ /** @description Required to be true for the API request to pass */
+ "OCS-APIRequest": boolean;
+ };
+ path: {
+ apiVersion: "v4";
+ token: string;
+ };
+ cookie?: never;
+ };
+ requestBody?: never;
+ responses: {
+ /** @description Conversation was unarchived */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": {
+ ocs: {
+ meta: components["schemas"]["OCSMeta"];
+ data: components["schemas"]["Room"];
+ };
+ };
+ };
+ };
+ };
+ };
"settings-set-user-setting": {
parameters: {
query?: never;
diff --git a/tests/integration/features/bootstrap/FeatureContext.php b/tests/integration/features/bootstrap/FeatureContext.php
index 3c92b9b16f6..0b2dff7a1f3 100644
--- a/tests/integration/features/bootstrap/FeatureContext.php
+++ b/tests/integration/features/bootstrap/FeatureContext.php
@@ -4828,6 +4828,45 @@ public function userSetsMentionPermissionsOfTheRoom(string $user, string $identi
$this->assertStatusCode($this->response, $statusCode);
}
+ /**
+ * @When /^user "([^"]*)" (unarchives|archives) room "([^"]*)" with (\d+) \((v4)\)$/
+ *
+ * @param string $user
+ * @param string $identifier
+ * @param string $action
+ * @param int $statusCode
+ * @param string $apiVersion
+ */
+ public function userArchivesConversation(string $user, string $identifier, string $action, int $statusCode, string $apiVersion): void {
+ $httpMethod = 'POST';
+
+ if ($action === 'unarchives') {
+ $httpMethod = 'DELETE';
+ }
+
+ $this->setCurrentUser($user);
+ $this->sendRequest(
+ $httpMethod, '/apps/spreed/api/' . $apiVersion . '/room/' . self::$identifierToToken[$identifier] . '/archive',
+ );
+ $this->assertStatusCode($this->response, $statusCode);
+ }
+
+ /**
+ * @When /^user "([^"]*)" unarchives room "([^"]*)" with (\d+) \((v4)\)$/
+ *
+ * @param string $user
+ * @param string $identifier
+ * @param int $statusCode
+ * @param string $apiVersion
+ */
+ public function userUnarchivesConversation(string $user, string $identifier, int $statusCode, string $apiVersion): void {
+ $this->setCurrentUser($user);
+ $this->sendRequest(
+ 'DELETE', '/apps/spreed/api/' . $apiVersion . '/room/' . self::$identifierToToken[$identifier] . '/archive',
+ );
+ $this->assertStatusCode($this->response, $statusCode);
+ }
+
/**
* @param string $verb
* @param string $fullUrl
diff --git a/tests/php/Chat/ChatManagerTest.php b/tests/php/Chat/ChatManagerTest.php
index 628b6d3ab4f..72d844199dd 100644
--- a/tests/php/Chat/ChatManagerTest.php
+++ b/tests/php/Chat/ChatManagerTest.php
@@ -428,6 +428,7 @@ public function testDeleteMessage(): void {
'state' => Invitation::STATE_ACCEPTED,
'unread_messages' => 0,
'last_attendee_activity' => 0,
+ 'archived' => 0,
]);
$chat = $this->createMock(Room::class);
$chat->expects($this->any())
@@ -490,6 +491,7 @@ public function testDeleteMessageFileShare(): void {
'state' => Invitation::STATE_ACCEPTED,
'unread_messages' => 0,
'last_attendee_activity' => 0,
+ 'archived' => 0,
]);
$chat = $this->createMock(Room::class);
$chat->expects($this->any())
@@ -574,6 +576,7 @@ public function testDeleteMessageFileShareNotFound(): void {
'state' => Invitation::STATE_ACCEPTED,
'unread_messages' => 0,
'last_attendee_activity' => 0,
+ 'archived' => 0,
]);
$chat = $this->createMock(Room::class);
$chat->expects($this->any())