Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
3 changes: 3 additions & 0 deletions docs/api-v1.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ Base endpoint is: `/ocs/v2.php/apps/spreed/api/v1`
* `notification-levels` - Users can select when they want to be notified in conversations
* `invite-groups-and-mails` - Groups can be added to existing conversations via the add participant endpoint

### 6.0
* `locked-one-to-one-rooms` - One-to-one conversations are now locked to the users. Neither guests nor other participants can be added, so the options to do that should be hidden as well. Also a user can only leave a one-to-one room (not delete). It will be deleted when the other participant left too. If the other participant posts a new chat message or starts a call, the left-participant will be re-added.

## Room management

### Creating a new room
Expand Down
2 changes: 1 addition & 1 deletion js/views/callinfoview.js
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@
},

_canModerate: function() {
return this._canFullModerate() || this.model.get('participantType') === 6;
return this.model.get('type') !== 1 && (this._canFullModerate() || this.model.get('participantType') === 6);
},

_canFullModerate: function() {
Expand Down
2 changes: 1 addition & 1 deletion js/views/participantview.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@
* the room; otherwise the form is hidden.
*/
_updateAddParticipantFormVisibility: function() {
if (!this.room ||
if (!this.room || this.room.get('type') === 1 ||
(this.room.get('participantType') !== OCA.SpreedMe.app.OWNER &&
this.room.get('participantType') !== OCA.SpreedMe.app.MODERATOR)) {
this.ui.addParticipantForm.hide();
Expand Down
2 changes: 1 addition & 1 deletion js/views/roomlistview.js
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@
icon = 'icon icon-public';
}

var isDeletable = this.model.get('participantType') === 1 || this.model.get('participantType') === 2;
var isDeletable = this.model.get('type') !== 1 && (this.model.get('participantType') === 1 || this.model.get('participantType') === 2);
var isLeavable = !isDeletable || (this.model.get('type') !== 1 && Object.keys(this.model.get('participants')).length > 1);

return {
Expand Down
1 change: 1 addition & 0 deletions lib/Capabilities.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ public function getCapabilities(): array {
'in-call-flags',
'notification-levels',
'invite-groups-and-mails',
'locked-one-to-one-rooms',
],
],
];
Expand Down
9 changes: 8 additions & 1 deletion lib/Chat/AutoComplete/SearchPlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,15 @@ public function setContext(array $context): void {
*/
public function search($search, $limit, $offset, ISearchResult $searchResult) {

$userIds = $this->room->getParticipantUserIds();
if ($this->room->getType() === Room::ONE_TO_ONE_CALL
&& $this->room->getName() !== '') {
// Add potential leavers of one-to-one rooms again.
$userIds[] = $this->room->getName();
}

// FIXME Handle guests
$this->searchUsers($search, $this->room->getParticipantUserIds(), $searchResult);
$this->searchUsers($search, $userIds, $searchResult);

if ($this->room->getObjectType() === 'file') {
$usersWithFileAccess = $this->util->getUsersWithAccessFile($this->room->getObjectId());
Expand Down
14 changes: 14 additions & 0 deletions lib/Chat/SystemMessage/Listener.php
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ public static function register(EventDispatcherInterface $dispatcher): void {
$listener->sendSystemMessage($room, 'conversation_created');
});
$dispatcher->addListener(Room::class . '::postSetName', function(GenericEvent $event) {
if ($event->getArgument('oldName') === '' ||
$event->getArgument('newName') === '') {
return;
}

/** @var Room $room */
$room = $event->getSubject();
/** @var self $listener */
Expand Down Expand Up @@ -141,6 +146,11 @@ public static function register(EventDispatcherInterface $dispatcher): void {

/** @var Room $room */
$room = $event->getSubject();

if ($room->getType() === Room::ONE_TO_ONE_CALL) {
return;
}

/** @var self $listener */
$listener = \OC::$server->query(self::class);
foreach ($participants as $participant) {
Expand All @@ -155,6 +165,10 @@ public static function register(EventDispatcherInterface $dispatcher): void {
/** @var Room $room */
$room = $event->getSubject();

if ($room->getType() === Room::ONE_TO_ONE_CALL) {
return;
}

/** @var self $listener */
$listener = \OC::$server->query(self::class);
$listener->sendSystemMessage($room, 'user_removed', ['user' => $user->getUID()]);
Expand Down
2 changes: 2 additions & 0 deletions lib/Controller/CallController.php
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@ public function joinCall(string $token, ?int $flags): DataResponse {
}
}

$room->ensureOneToOneRoomIsFilled();

$sessionId = $participant->getSessionId();
if ($sessionId === '0') {
return new DataResponse([], Http::STATUS_NOT_FOUND);
Expand Down
1 change: 1 addition & 0 deletions lib/Controller/ChatController.php
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ public function sendMessage(string $token, string $message, string $actorDisplay
return new DataResponse([], Http::STATUS_NOT_FOUND);
}

$room->ensureOneToOneRoomIsFilled();
$creationDateTime = $this->timeFactory->getDateTime('now', new \DateTimeZone('UTC'));

try {
Expand Down
75 changes: 42 additions & 33 deletions lib/Controller/RoomController.php
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,7 @@ protected function createOneToOneRoom(string $targetUserName): DataResponse {
// If room exists: Reuse that one, otherwise create a new one.
try {
$room = $this->manager->getOne2OneRoom($this->userId, $targetUser->getUID());
$room->ensureOneToOneRoomIsFilled();
return new DataResponse(['token' => $room->getToken()], Http::STATUS_OK);
} catch (RoomNotFoundException $e) {
$room = $this->manager->createOne2OneRoom();
Expand Down Expand Up @@ -560,17 +561,18 @@ public function renameRoom(string $token, string $roomName): DataResponse {
return new DataResponse([], Http::STATUS_FORBIDDEN);
}

if ($room->getType() === Room::ONE_TO_ONE_CALL) {
return new DataResponse([], Http::STATUS_BAD_REQUEST);
}

$roomName = trim($roomName);

if ($roomName === '' || strlen($roomName) > 200) {
return new DataResponse([], Http::STATUS_BAD_REQUEST);
}

if (!$room->setName($roomName)) {
return new DataResponse([], Http::STATUS_METHOD_NOT_ALLOWED);
}

return new DataResponse([]);
$room->setName($roomName);
return new DataResponse();
}

/**
Expand Down Expand Up @@ -598,6 +600,10 @@ public function deleteRoom(string $token): DataResponse {
return new DataResponse([], Http::STATUS_FORBIDDEN);
}

if ($room->getType() === Room::ONE_TO_ONE_CALL) {
return new DataResponse([], Http::STATUS_BAD_REQUEST);
}

$room->deleteRoom();

return new DataResponse([]);
Expand Down Expand Up @@ -682,9 +688,12 @@ public function addParticipantToRoom(string $token, string $newParticipant, stri
return new DataResponse([], Http::STATUS_FORBIDDEN);
}

if ($room->getType() === Room::ONE_TO_ONE_CALL) {
return new DataResponse([], Http::STATUS_BAD_REQUEST);
}

$participants = $room->getParticipantUserIds();

$updateRoomType = $room->getType() === Room::ONE_TO_ONE_CALL ? Room::GROUP_CALL : false;
$participantsToAdd = [];
if ($source === 'users') {
$newUser = $this->userManager->get($newParticipant);
Expand Down Expand Up @@ -722,20 +731,18 @@ public function addParticipantToRoom(string $token, string $newParticipant, stri

\call_user_func_array([$room, 'addUsers'], $participantsToAdd);
} else if ($source === 'emails') {
$data = [];
if ($room->changeType(Room::PUBLIC_CALL)) {
$data = ['type' => $room->getType()];
}

$this->guestManager->inviteByEmail($room, $newParticipant);
$updateRoomType = $room->getType() !== Room::PUBLIC_CALL ? Room::PUBLIC_CALL : false;

return new DataResponse($data);
} else {
return new DataResponse([], Http::STATUS_BAD_REQUEST);
}

if ($updateRoomType !== false) {
// In case a user is added to a one2one room, we change the call to a group room
// In case an email is added to a closed room, we change the call to a public room
$room->changeType($updateRoomType);

return new DataResponse(['type' => $room->getType()]);
}

return new DataResponse();
}

Expand Down Expand Up @@ -765,12 +772,13 @@ public function inviteEmailToRoom(string $token, string $newParticipant): DataRe
return new DataResponse([], Http::STATUS_NOT_FOUND);
}

$data = [];
if ($room->getType() !== Room::PUBLIC_CALL) {
// In case a user is added to a one2one call, we change the call to a group call
// In case a guest is added to a non-public call, we change the call to a public call
$room->changeType(Room::PUBLIC_CALL);
if ($room->getType() === Room::ONE_TO_ONE_CALL) {
return new DataResponse([], Http::STATUS_BAD_REQUEST);
}

$data = [];
// In case a guest is added to a non-public call, we change the call to a public call
if ($room->changeType(Room::PUBLIC_CALL)) {
$data = ['type' => $room->getType()];
}

Expand Down Expand Up @@ -811,8 +819,7 @@ public function removeParticipantFromRoom(string $token, string $participant): D
}

if ($room->getType() === Room::ONE_TO_ONE_CALL) {
$room->deleteRoom();
return new DataResponse([]);
return new DataResponse([], Http::STATUS_BAD_REQUEST);
}

try {
Expand Down Expand Up @@ -854,13 +861,15 @@ public function removeSelfFromRoom(string $token): DataResponse {
}

protected function removeSelfFromRoomLogic(Room $room, Participant $participant): DataResponse {
if ($room->getType() === Room::ONE_TO_ONE_CALL || $room->getNumberOfParticipants() === 1) {
if ($room->getType() !== Room::ONE_TO_ONE_CALL) {
if ($participant->hasModeratorPermissions(false)
&& $room->getNumberOfParticipants() > 1
&& $room->getNumberOfModerators() === 1) {
return new DataResponse([], Http::STATUS_BAD_REQUEST);
}
} else if ($room->getNumberOfParticipants() === 1) {
$room->deleteRoom();
return new DataResponse([]);
}

if ($participant->hasModeratorPermissions(false) && $room->getNumberOfModerators() === 1) {
return new DataResponse([], Http::STATUS_BAD_REQUEST);
return new DataResponse();
}

$currentUser = $this->userManager->get($participant->getUser());
Expand All @@ -870,7 +879,7 @@ protected function removeSelfFromRoomLogic(Room $room, Participant $participant)

$room->removeUser($currentUser, Room::PARTICIPANT_LEFT);

return new DataResponse([]);
return new DataResponse();
}

/**
Expand Down Expand Up @@ -937,8 +946,8 @@ public function makePublic(string $token): DataResponse {
return new DataResponse([], Http::STATUS_FORBIDDEN);
}

if ($room->getType() !== Room::PUBLIC_CALL) {
$room->changeType(Room::PUBLIC_CALL);
if (!$room->changeType(Room::PUBLIC_CALL)) {
return new DataResponse([], Http::STATUS_BAD_REQUEST);
}

return new DataResponse();
Expand All @@ -964,8 +973,8 @@ public function makePrivate(string $token): DataResponse {
return new DataResponse([], Http::STATUS_FORBIDDEN);
}

if ($room->getType() === Room::PUBLIC_CALL) {
$room->changeType(Room::GROUP_CALL);
if (!$room->changeType(Room::GROUP_CALL)) {
return new DataResponse([], Http::STATUS_BAD_REQUEST);
}

return new DataResponse();
Expand Down
39 changes: 30 additions & 9 deletions lib/Manager.php
Original file line number Diff line number Diff line change
Expand Up @@ -384,18 +384,30 @@ public function getRoomForSession(?string $userId, ?string $sessionId): Room {
public function getOne2OneRoom(string $participant1, string $participant2): Room {
$query = $this->db->getQueryBuilder();
$query->select('*')
->from('talk_rooms', 'r1')
->leftJoin('r1', 'talk_participants', 'p1', $query->expr()->andX(
->from('talk_rooms', 'r')
->leftJoin('r', 'talk_participants', 'p1', $query->expr()->andX(
$query->expr()->eq('p1.user_id', $query->createNamedParameter($participant1)),
$query->expr()->eq('p1.room_id', 'r1.id')
$query->expr()->eq('p1.room_id', 'r.id')
))
->leftJoin('r1', 'talk_participants', 'p2', $query->expr()->andX(
->leftJoin('r', 'talk_participants', 'p2', $query->expr()->andX(
$query->expr()->eq('p2.user_id', $query->createNamedParameter($participant2)),
$query->expr()->eq('p2.room_id', 'r1.id')
$query->expr()->eq('p2.room_id', 'r.id')
))
->where($query->expr()->eq('r1.type', $query->createNamedParameter(Room::ONE_TO_ONE_CALL, IQueryBuilder::PARAM_INT)))
->andWhere($query->expr()->isNotNull('p1.user_id'))
->andWhere($query->expr()->isNotNull('p2.user_id'));
->where($query->expr()->eq('r.type', $query->createNamedParameter(Room::ONE_TO_ONE_CALL, IQueryBuilder::PARAM_INT)))
->andWhere($query->expr()->orX(
$query->expr()->andX(
$query->expr()->isNotNull('p1.user_id'),
$query->expr()->isNotNull('p2.user_id')
),
$query->expr()->andX(
$query->expr()->eq('r.name', $query->createNamedParameter($participant1)),
$query->expr()->isNotNull('p2.user_id')
),
$query->expr()->andX(
$query->expr()->isNotNull('p1.user_id'),
$query->expr()->eq('r.name', $query->createNamedParameter($participant2))
)
));

$result = $query->execute();
$row = $result->fetch();
Expand Down Expand Up @@ -532,7 +544,7 @@ public function resolveRoomDisplayName(Room $room, string $userId): string {
return $this->l->t('Password request: %s', [$room->getName()]);
}

if ($room->getName() === '') {
if ($room->getType() !== Room::ONE_TO_ONE_CALL && $room->getName() === '') {
$room->setName($this->getRoomNameByParticipants($room));
}

Expand All @@ -556,6 +568,11 @@ public function resolveRoomDisplayName(Room $room, string $userId): string {
return $this->l->t('Private conversation');
}

if ($otherParticipant === '' && $room->getName() !== '') {
$user = $this->userManager->get($room->getName());
$otherParticipant = $user instanceof IUser ? $user->getDisplayName() : $participantId;
}

return $otherParticipant;
}

Expand Down Expand Up @@ -648,6 +665,10 @@ protected function generateNewToken(IQueryBuilder $query, int $entropy, string $
return $token;
}

public function isValidParticipant(string $userId): bool {
return $this->userManager->userExists($userId);
}

protected function loadLastMessageInfo(IQueryBuilder $query): void {
$query->leftJoin('r','comments', 'c', $query->expr()->eq('r.last_message', 'c.id'));
$query->selectAlias('c.id', 'comment_id');
Expand Down
Loading