Allow to revert the user status of multiple users in 3 queries instead of 3*n

Signed-off-by: Joas Schilling <coding@schilljs.com>
pull/31106/head
Joas Schilling 4 years ago
parent 194338cca3
commit deec4f31db
No known key found for this signature in database
GPG Key ID: 7076EA9751AACDDA
  1. 4
      apps/user_status/lib/Connector/UserStatusProvider.php
  2. 19
      apps/user_status/lib/Db/UserStatusMapper.php
  3. 38
      apps/user_status/lib/Service/StatusService.php
  4. 52
      apps/user_status/tests/Unit/Db/UserStatusMapperTest.php
  5. 58
      apps/user_status/tests/Unit/Service/StatusServiceTest.php
  6. 11
      lib/private/UserStatus/ISettableProvider.php
  7. 8
      lib/private/UserStatus/Manager.php
  8. 15
      lib/public/UserStatus/IManager.php

@ -70,4 +70,8 @@ class UserStatusProvider implements IProvider, ISettableProvider {
public function revertUserStatus(string $userId, string $messageId, string $status): void {
$this->service->revertUserStatus($userId, $messageId, $status);
}
public function revertMultipleUserStatus(array $userIds, string $messageId, string $status): void {
$this->service->revertMultipleUserStatus($userIds, $messageId, $status);
}
}

@ -111,7 +111,7 @@ class UserStatusMapper extends QBMapper {
* @param array $userIds
* @return array
*/
public function findByUserIds(array $userIds):array {
public function findByUserIds(array $userIds): array {
$qb = $this->db->getQueryBuilder();
$qb
->select('*')
@ -177,4 +177,21 @@ class UserStatusMapper extends QBMapper {
->andWhere($qb->expr()->eq('is_backup', $qb->createNamedParameter(false, IQueryBuilder::PARAM_BOOL)));
return $qb->executeStatement() > 0;
}
public function deleteByIds(array $ids): void {
$qb = $this->db->getQueryBuilder();
$qb->delete($this->tableName)
->where($qb->expr()->in('id', $qb->createNamedParameter($ids, IQueryBuilder::PARAM_INT_ARRAY)));
$qb->executeStatement();
}
public function restoreBackupStatuses(array $ids): void {
$qb = $this->db->getQueryBuilder();
$qb->update($this->tableName)
->set('is_backup', $qb->createNamedParameter(false, IQueryBuilder::PARAM_BOOL))
->set('user_id', $qb->func()->substring('user_id', $qb->createNamedParameter(2, IQueryBuilder::PARAM_INT)))
->where($qb->expr()->in('id', $qb->createNamedParameter($ids, IQueryBuilder::PARAM_INT_ARRAY)));
$qb->executeStatement();
}
}

@ -36,6 +36,7 @@ use OCA\UserStatus\Exception\StatusMessageTooLongException;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\IConfig;
use OCP\IUser;
use OCP\UserStatus\IUserStatus;
/**
@ -460,7 +461,7 @@ class StatusService {
return true;
}
public function revertUserStatus(string $userId, ?string $messageId, string $status): void {
public function revertUserStatus(string $userId, string $messageId, string $status): void {
try {
/** @var UserStatus $userStatus */
$backupUserStatus = $this->mapper->findByUserId($userId, true);
@ -469,7 +470,7 @@ class StatusService {
return;
}
$deleted = $this->mapper->deleteCurrentStatusToRestoreBackup($userId, $messageId ?? '', $status);
$deleted = $this->mapper->deleteCurrentStatusToRestoreBackup($userId, $messageId, $status);
if (!$deleted) {
// Another status is set automatically or no status, do nothing
return;
@ -480,4 +481,37 @@ class StatusService {
$backupUserStatus->setUserId(substr($backupUserStatus->getUserId(), 1));
$this->mapper->update($backupUserStatus);
}
public function revertMultipleUserStatus(array $userIds, string $messageId, string $status): void {
// Get all user statuses and the backups
$findById = $userIds;
foreach ($userIds as $userId) {
$findById[] = '_' . $userId;
}
$userStatuses = $this->mapper->findByUserIds($findById);
$backups = $restoreIds = $statuesToDelete = [];
foreach ($userStatuses as $userStatus) {
if (!$userStatus->getIsBackup()
&& $userStatus->getMessageId() === $messageId
&& $userStatus->getStatus() === $status) {
$statuesToDelete[$userStatus->getUserId()] = $userStatus->getId();
} else if ($userStatus->getIsBackup()) {
$backups[$userStatus->getUserId()] = $userStatus->getId();
}
}
// For users with both (normal and backup) delete the status when matching
foreach ($statuesToDelete as $userId => $statusId) {
$backupUserId = '_' . $userId;
if (isset($backups[$backupUserId])) {
$restoreIds[] = $backups[$backupUserId];
}
}
$this->mapper->deleteByIds(array_values($statuesToDelete));
// For users that matched restore the previous status
$this->mapper->restoreBackupStatuses($restoreIds);
}
}

@ -251,4 +251,56 @@ class UserStatusMapperTest extends TestCase {
$this->mapper->insert($userStatus2);
$this->mapper->insert($userStatus3);
}
public function testRestoreBackupStatuses(): void {
$userStatus1 = new UserStatus();
$userStatus1->setUserId('_user1');
$userStatus1->setStatus('online');
$userStatus1->setStatusTimestamp(5000);
$userStatus1->setIsUserDefined(true);
$userStatus1->setIsBackup(true);
$userStatus1->setCustomIcon('🚀');
$userStatus1->setCustomMessage('Releasing');
$userStatus1->setClearAt(50000);
$userStatus1 = $this->mapper->insert($userStatus1);
$userStatus2 = new UserStatus();
$userStatus2->setUserId('_user2');
$userStatus2->setStatus('away');
$userStatus2->setStatusTimestamp(5000);
$userStatus2->setIsUserDefined(true);
$userStatus2->setIsBackup(true);
$userStatus2->setCustomIcon('💩');
$userStatus2->setCustomMessage('Do not disturb');
$userStatus2->setClearAt(50000);
$userStatus2 = $this->mapper->insert($userStatus2);
$userStatus3 = new UserStatus();
$userStatus3->setUserId('_user3');
$userStatus3->setStatus('away');
$userStatus3->setStatusTimestamp(5000);
$userStatus3->setIsUserDefined(true);
$userStatus3->setIsBackup(true);
$userStatus3->setCustomIcon('🏝');
$userStatus3->setCustomMessage('Vacationing');
$userStatus3->setClearAt(50000);
$this->mapper->insert($userStatus3);
$this->mapper->restoreBackupStatuses([$userStatus1->getId(), $userStatus2->getId()]);
$user1Status = $this->mapper->findByUserId('user1', false);
$this->assertEquals('user1', $user1Status->getUserId());
$this->assertEquals(false, $user1Status->getIsBackup());
$this->assertEquals('Releasing', $user1Status->getCustomMessage());
$user2Status = $this->mapper->findByUserId('user2', false);
$this->assertEquals('user2', $user2Status->getUserId());
$this->assertEquals(false, $user2Status->getIsBackup());
$this->assertEquals('Do not disturb', $user2Status->getCustomMessage());
$user3Status = $this->mapper->findByUserId('user3', true);
$this->assertEquals('_user3', $user3Status->getUserId());
$this->assertEquals(true, $user3Status->getIsBackup());
$this->assertEquals('Vacationing', $user3Status->getCustomMessage());
}
}

@ -771,4 +771,62 @@ class StatusServiceTest extends TestCase {
$this->service->backupCurrentStatus('john');
}
public function testRevertMultipleUserStatus(): void {
$john = new UserStatus();
$john->setId(1);
$john->setStatus(IUserStatus::AWAY);
$john->setStatusTimestamp(1337);
$john->setIsUserDefined(false);
$john->setMessageId('call');
$john->setUserId('john');
$john->setIsBackup(false);
$johnBackup = new UserStatus();
$johnBackup->setId(2);
$johnBackup->setStatus(IUserStatus::ONLINE);
$johnBackup->setStatusTimestamp(1337);
$johnBackup->setIsUserDefined(true);
$johnBackup->setMessageId('hello');
$johnBackup->setUserId('_john');
$johnBackup->setIsBackup(true);
$noBackup = new UserStatus();
$noBackup->setId(3);
$noBackup->setStatus(IUserStatus::AWAY);
$noBackup->setStatusTimestamp(1337);
$noBackup->setIsUserDefined(false);
$noBackup->setMessageId('call');
$noBackup->setUserId('nobackup');
$noBackup->setIsBackup(false);
$backupOnly = new UserStatus();
$backupOnly->setId(4);
$backupOnly->setStatus(IUserStatus::ONLINE);
$backupOnly->setStatusTimestamp(1337);
$backupOnly->setIsUserDefined(true);
$backupOnly->setMessageId('hello');
$backupOnly->setUserId('_backuponly');
$backupOnly->setIsBackup(true);
$this->mapper->expects($this->once())
->method('findByUserIds')
->with(['john', 'nobackup', 'backuponly', '_john', '_nobackup', '_backuponly'])
->willReturn([
$john,
$johnBackup,
$noBackup,
$backupOnly,
]);
$this->mapper->expects($this->once())
->method('deleteByIds')
->with([1, 3]);
$this->mapper->expects($this->once())
->method('restoreBackupStatuses')
->with([2]);
$this->service->revertMultipleUserStatus(['john', 'nobackup', 'backuponly'], 'call', IUserStatus::AWAY);
}
}

@ -52,4 +52,15 @@ interface ISettableProvider extends IProvider {
* @param string $status The expected current status.
*/
public function revertUserStatus(string $userId, string $messageId, string $status): void;
/**
* Revert an automatically set user status. For example after leaving a call,
* change back to the previously set status. If the user has already updated
* their status, this method does nothing.
*
* @param string[] $userIds The users for which we want to update the status.
* @param string $messageId The expected current messageId.
* @param string $status The expected current status.
*/
public function revertMultipleUserStatus(array $userIds, string $messageId, string $status): void;
}

@ -121,4 +121,12 @@ class Manager implements IManager {
}
$this->provider->revertUserStatus($userId, $messageId, $status);
}
public function revertMultipleUserStatus(array $userIds, string $messageId, string $status): void {
$this->setupProvider();
if (!$this->provider || !($this->provider instanceof ISettableProvider)) {
return;
}
$this->provider->revertMultipleUserStatus($userIds, $messageId, $status);
}
}

@ -39,7 +39,7 @@ interface IManager {
* @return IUserStatus[]
* @since 20.0.0
*/
public function getUserStatuses(array $userIds):array;
public function getUserStatuses(array $userIds): array;
/**
@ -47,6 +47,7 @@ interface IManager {
*
* @param string $userId The user for which we want to update the status.
* @param string $messageId The id of the predefined message.
* @param string $status The status to assign
* @param bool $createBackup If true, this will store the old status so that it is possible to revert it later (e.g. after a call).
* @since 23.0.0
*/
@ -58,7 +59,19 @@ interface IManager {
*
* @param string $userId The user for which we want to update the status.
* @param string $messageId The expected current messageId. If the user has already updated their status, this method does nothing.
* @param string $status The expected current status. If the user has already updated their status, this method does nothing.
* @since 23.0.0
*/
public function revertUserStatus(string $userId, string $messageId, string $status): void;
/**
* Revert an automatically set user status. For example after leaving a call,
* change back to the previously set status.
*
* @param string[] $userIds The user for which we want to update the status.
* @param string $messageId The expected current messageId. If the user has already updated their status, this method does nothing.
* @param string $status The expected current status. If the user has already updated their status, this method does nothing.
* @since 23.0.0
*/
public function revertMultipleUserStatus(array $userIds, string $messageId, string $status): void;
}

Loading…
Cancel
Save