aboutsummaryrefslogtreecommitdiffstats
path: root/apps/user_status/lib
diff options
context:
space:
mode:
Diffstat (limited to 'apps/user_status/lib')
-rw-r--r--apps/user_status/lib/AppInfo/Application.php4
-rw-r--r--apps/user_status/lib/BackgroundJob/ClearOldStatusesBackgroundJob.php11
-rw-r--r--apps/user_status/lib/Capabilities.php10
-rw-r--r--apps/user_status/lib/Connector/UserStatus.php24
-rw-r--r--apps/user_status/lib/Connector/UserStatusProvider.php8
-rw-r--r--apps/user_status/lib/ContactsMenu/StatusProvider.php4
-rw-r--r--apps/user_status/lib/Controller/HeartbeatController.php35
-rw-r--r--apps/user_status/lib/Controller/PredefinedStatusController.php20
-rw-r--r--apps/user_status/lib/Controller/StatusesController.php25
-rw-r--r--apps/user_status/lib/Controller/UserStatusController.php28
-rw-r--r--apps/user_status/lib/Dashboard/UserStatusWidget.php41
-rw-r--r--apps/user_status/lib/Db/UserStatus.php7
-rw-r--r--apps/user_status/lib/Db/UserStatusMapper.php7
-rw-r--r--apps/user_status/lib/Listener/BeforeTemplateRenderedListener.php23
-rw-r--r--apps/user_status/lib/Listener/OutOfOfficeStatusListener.php17
-rw-r--r--apps/user_status/lib/Listener/UserDeletedListener.php8
-rw-r--r--apps/user_status/lib/Listener/UserLiveStatusListener.php23
-rw-r--r--apps/user_status/lib/Migration/Version1008Date20230921144701.php4
-rw-r--r--apps/user_status/lib/ResponseDefinitions.php1
-rw-r--r--apps/user_status/lib/Service/JSDataService.php14
-rw-r--r--apps/user_status/lib/Service/PredefinedStatusService.php25
-rw-r--r--apps/user_status/lib/Service/StatusService.php58
22 files changed, 200 insertions, 197 deletions
diff --git a/apps/user_status/lib/AppInfo/Application.php b/apps/user_status/lib/AppInfo/Application.php
index 31b7342e40b..5199c3fdbf0 100644
--- a/apps/user_status/lib/AppInfo/Application.php
+++ b/apps/user_status/lib/AppInfo/Application.php
@@ -23,7 +23,9 @@ use OCP\AppFramework\Http\Events\BeforeTemplateRenderedEvent;
use OCP\IConfig;
use OCP\User\Events\OutOfOfficeChangedEvent;
use OCP\User\Events\OutOfOfficeClearedEvent;
+use OCP\User\Events\OutOfOfficeEndedEvent;
use OCP\User\Events\OutOfOfficeScheduledEvent;
+use OCP\User\Events\OutOfOfficeStartedEvent;
use OCP\User\Events\UserDeletedEvent;
use OCP\User\Events\UserLiveStatusEvent;
use OCP\UserStatus\IManager;
@@ -61,6 +63,8 @@ class Application extends App implements IBootstrap {
$context->registerEventListener(OutOfOfficeChangedEvent::class, OutOfOfficeStatusListener::class);
$context->registerEventListener(OutOfOfficeScheduledEvent::class, OutOfOfficeStatusListener::class);
$context->registerEventListener(OutOfOfficeClearedEvent::class, OutOfOfficeStatusListener::class);
+ $context->registerEventListener(OutOfOfficeStartedEvent::class, OutOfOfficeStatusListener::class);
+ $context->registerEventListener(OutOfOfficeEndedEvent::class, OutOfOfficeStatusListener::class);
$config = $this->getContainer()->query(IConfig::class);
$shareeEnumeration = $config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes';
diff --git a/apps/user_status/lib/BackgroundJob/ClearOldStatusesBackgroundJob.php b/apps/user_status/lib/BackgroundJob/ClearOldStatusesBackgroundJob.php
index 1810f7aa118..51a9c623a03 100644
--- a/apps/user_status/lib/BackgroundJob/ClearOldStatusesBackgroundJob.php
+++ b/apps/user_status/lib/BackgroundJob/ClearOldStatusesBackgroundJob.php
@@ -20,21 +20,18 @@ use OCP\BackgroundJob\TimedJob;
*/
class ClearOldStatusesBackgroundJob extends TimedJob {
- /** @var UserStatusMapper */
- private $mapper;
-
/**
* ClearOldStatusesBackgroundJob constructor.
*
* @param ITimeFactory $time
* @param UserStatusMapper $mapper
*/
- public function __construct(ITimeFactory $time,
- UserStatusMapper $mapper) {
+ public function __construct(
+ ITimeFactory $time,
+ private UserStatusMapper $mapper,
+ ) {
parent::__construct($time);
- $this->mapper = $mapper;
- // Run every time the cron is run
$this->setInterval(60);
}
diff --git a/apps/user_status/lib/Capabilities.php b/apps/user_status/lib/Capabilities.php
index 9a1ac4b47ab..c3edbc032d6 100644
--- a/apps/user_status/lib/Capabilities.php
+++ b/apps/user_status/lib/Capabilities.php
@@ -17,14 +17,13 @@ use OCP\IEmojiHelper;
* @package OCA\UserStatus
*/
class Capabilities implements ICapability {
- private IEmojiHelper $emojiHelper;
-
- public function __construct(IEmojiHelper $emojiHelper) {
- $this->emojiHelper = $emojiHelper;
+ public function __construct(
+ private IEmojiHelper $emojiHelper,
+ ) {
}
/**
- * @return array{user_status: array{enabled: bool, restore: bool, supports_emoji: bool}}
+ * @return array{user_status: array{enabled: bool, restore: bool, supports_emoji: bool, supports_busy: bool}}
*/
public function getCapabilities() {
return [
@@ -32,6 +31,7 @@ class Capabilities implements ICapability {
'enabled' => true,
'restore' => true,
'supports_emoji' => $this->emojiHelper->doesPlatformSupportEmoji(),
+ 'supports_busy' => true,
],
];
}
diff --git a/apps/user_status/lib/Connector/UserStatus.php b/apps/user_status/lib/Connector/UserStatus.php
index 7fbfd62f223..04467a99e5e 100644
--- a/apps/user_status/lib/Connector/UserStatus.php
+++ b/apps/user_status/lib/Connector/UserStatus.php
@@ -29,21 +29,19 @@ class UserStatus implements IUserStatus {
/** @var DateTimeImmutable|null */
private $clearAt;
- /** @var Db\UserStatus */
- private $internalStatus;
-
- public function __construct(Db\UserStatus $status) {
- $this->internalStatus = $status;
- $this->userId = $status->getUserId();
- $this->status = $status->getStatus();
- $this->message = $status->getCustomMessage();
- $this->icon = $status->getCustomIcon();
-
- if ($status->getStatus() === IUserStatus::INVISIBLE) {
+ public function __construct(
+ private Db\UserStatus $internalStatus,
+ ) {
+ $this->userId = $this->internalStatus->getUserId();
+ $this->status = $this->internalStatus->getStatus();
+ $this->message = $this->internalStatus->getCustomMessage();
+ $this->icon = $this->internalStatus->getCustomIcon();
+
+ if ($this->internalStatus->getStatus() === IUserStatus::INVISIBLE) {
$this->status = IUserStatus::OFFLINE;
}
- if ($status->getClearAt() !== null) {
- $this->clearAt = DateTimeImmutable::createFromFormat('U', (string)$status->getClearAt());
+ if ($this->internalStatus->getClearAt() !== null) {
+ $this->clearAt = DateTimeImmutable::createFromFormat('U', (string)$this->internalStatus->getClearAt());
}
}
diff --git a/apps/user_status/lib/Connector/UserStatusProvider.php b/apps/user_status/lib/Connector/UserStatusProvider.php
index a85223dcf2a..e84d69d1eb2 100644
--- a/apps/user_status/lib/Connector/UserStatusProvider.php
+++ b/apps/user_status/lib/Connector/UserStatusProvider.php
@@ -14,16 +14,14 @@ use OCP\UserStatus\IProvider;
class UserStatusProvider implements IProvider, ISettableProvider {
- /** @var StatusService */
- private $service;
-
/**
* UserStatusProvider constructor.
*
* @param StatusService $service
*/
- public function __construct(StatusService $service) {
- $this->service = $service;
+ public function __construct(
+ private StatusService $service,
+ ) {
}
/**
diff --git a/apps/user_status/lib/ContactsMenu/StatusProvider.php b/apps/user_status/lib/ContactsMenu/StatusProvider.php
index 023b4402fc2..6a6949b46ba 100644
--- a/apps/user_status/lib/ContactsMenu/StatusProvider.php
+++ b/apps/user_status/lib/ContactsMenu/StatusProvider.php
@@ -19,7 +19,9 @@ use function array_map;
class StatusProvider implements IBulkProvider {
- public function __construct(private StatusService $statusService) {
+ public function __construct(
+ private StatusService $statusService,
+ ) {
}
public function process(array $entries): void {
diff --git a/apps/user_status/lib/Controller/HeartbeatController.php b/apps/user_status/lib/Controller/HeartbeatController.php
index e8325617557..30f4af6572a 100644
--- a/apps/user_status/lib/Controller/HeartbeatController.php
+++ b/apps/user_status/lib/Controller/HeartbeatController.php
@@ -13,6 +13,7 @@ use OCA\UserStatus\ResponseDefinitions;
use OCA\UserStatus\Service\StatusService;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\ApiRoute;
+use OCP\AppFramework\Http\Attribute\NoAdminRequired;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCSController;
use OCP\AppFramework\Utility\ITimeFactory;
@@ -27,43 +28,29 @@ use OCP\UserStatus\IUserStatus;
*/
class HeartbeatController extends OCSController {
- /** @var IEventDispatcher */
- private $eventDispatcher;
-
- /** @var IUserSession */
- private $userSession;
-
- /** @var ITimeFactory */
- private $timeFactory;
-
- /** @var StatusService */
- private $service;
-
- public function __construct(string $appName,
+ public function __construct(
+ string $appName,
IRequest $request,
- IEventDispatcher $eventDispatcher,
- IUserSession $userSession,
- ITimeFactory $timeFactory,
- StatusService $service) {
+ private IEventDispatcher $eventDispatcher,
+ private IUserSession $userSession,
+ private ITimeFactory $timeFactory,
+ private StatusService $service,
+ ) {
parent::__construct($appName, $request);
- $this->eventDispatcher = $eventDispatcher;
- $this->userSession = $userSession;
- $this->timeFactory = $timeFactory;
- $this->service = $service;
}
/**
* Keep the status alive
*
- * @NoAdminRequired
- *
* @param string $status Only online, away
*
- * @return DataResponse<Http::STATUS_OK, UserStatusPrivate, array{}>|DataResponse<Http::STATUS_BAD_REQUEST|Http::STATUS_INTERNAL_SERVER_ERROR|Http::STATUS_NO_CONTENT, array<empty>, array{}>
+ * @return DataResponse<Http::STATUS_OK, UserStatusPrivate, array{}>|DataResponse<Http::STATUS_BAD_REQUEST|Http::STATUS_INTERNAL_SERVER_ERROR|Http::STATUS_NO_CONTENT, list<empty>, array{}>
+ *
* 200: Status successfully updated
* 204: User has no status to keep alive
* 400: Invalid status to update
*/
+ #[NoAdminRequired]
#[ApiRoute(verb: 'PUT', url: '/api/v1/heartbeat')]
public function heartbeat(string $status): DataResponse {
if (!\in_array($status, [IUserStatus::ONLINE, IUserStatus::AWAY], true)) {
diff --git a/apps/user_status/lib/Controller/PredefinedStatusController.php b/apps/user_status/lib/Controller/PredefinedStatusController.php
index 884bc1d2baa..70262d1108a 100644
--- a/apps/user_status/lib/Controller/PredefinedStatusController.php
+++ b/apps/user_status/lib/Controller/PredefinedStatusController.php
@@ -12,6 +12,7 @@ use OCA\UserStatus\ResponseDefinitions;
use OCA\UserStatus\Service\PredefinedStatusService;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\ApiRoute;
+use OCP\AppFramework\Http\Attribute\NoAdminRequired;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCSController;
use OCP\IRequest;
@@ -23,9 +24,6 @@ use OCP\IRequest;
*/
class PredefinedStatusController extends OCSController {
- /** @var PredefinedStatusService */
- private $predefinedStatusService;
-
/**
* AStatusController constructor.
*
@@ -33,27 +31,27 @@ class PredefinedStatusController extends OCSController {
* @param IRequest $request
* @param PredefinedStatusService $predefinedStatusService
*/
- public function __construct(string $appName,
+ public function __construct(
+ string $appName,
IRequest $request,
- PredefinedStatusService $predefinedStatusService) {
+ private PredefinedStatusService $predefinedStatusService,
+ ) {
parent::__construct($appName, $request);
- $this->predefinedStatusService = $predefinedStatusService;
}
/**
* Get all predefined messages
*
- * @NoAdminRequired
- *
- * @return DataResponse<Http::STATUS_OK, UserStatusPredefined[], array{}>
+ * @return DataResponse<Http::STATUS_OK, list<UserStatusPredefined>, array{}>
*
* 200: Predefined statuses returned
*/
+ #[NoAdminRequired]
#[ApiRoute(verb: 'GET', url: '/api/v1/predefined_statuses/')]
public function findAll():DataResponse {
// Filtering out the invisible one, that should only be set by API
- return new DataResponse(array_filter($this->predefinedStatusService->getDefaultStatuses(), function (array $status) {
+ return new DataResponse(array_values(array_filter($this->predefinedStatusService->getDefaultStatuses(), function (array $status) {
return !array_key_exists('visible', $status) || $status['visible'] === true;
- }));
+ })));
}
}
diff --git a/apps/user_status/lib/Controller/StatusesController.php b/apps/user_status/lib/Controller/StatusesController.php
index da942ed7d7c..44688c39023 100644
--- a/apps/user_status/lib/Controller/StatusesController.php
+++ b/apps/user_status/lib/Controller/StatusesController.php
@@ -14,6 +14,7 @@ use OCA\UserStatus\Service\StatusService;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\ApiRoute;
+use OCP\AppFramework\Http\Attribute\NoAdminRequired;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCS\OCSNotFoundException;
use OCP\AppFramework\OCSController;
@@ -26,9 +27,6 @@ use OCP\UserStatus\IUserStatus;
*/
class StatusesController extends OCSController {
- /** @var StatusService */
- private $service;
-
/**
* StatusesController constructor.
*
@@ -36,44 +34,43 @@ class StatusesController extends OCSController {
* @param IRequest $request
* @param StatusService $service
*/
- public function __construct(string $appName,
+ public function __construct(
+ string $appName,
IRequest $request,
- StatusService $service) {
+ private StatusService $service,
+ ) {
parent::__construct($appName, $request);
- $this->service = $service;
}
/**
* Find statuses of users
*
- * @NoAdminRequired
- *
* @param int|null $limit Maximum number of statuses to find
- * @param int|null $offset Offset for finding statuses
- * @return DataResponse<Http::STATUS_OK, UserStatusPublic[], array{}>
+ * @param non-negative-int|null $offset Offset for finding statuses
+ * @return DataResponse<Http::STATUS_OK, list<UserStatusPublic>, array{}>
*
* 200: Statuses returned
*/
+ #[NoAdminRequired]
#[ApiRoute(verb: 'GET', url: '/api/v1/statuses')]
public function findAll(?int $limit = null, ?int $offset = null): DataResponse {
$allStatuses = $this->service->findAll($limit, $offset);
- return new DataResponse(array_map(function ($userStatus) {
+ return new DataResponse(array_values(array_map(function ($userStatus) {
return $this->formatStatus($userStatus);
- }, $allStatuses));
+ }, $allStatuses)));
}
/**
* Find the status of a user
*
- * @NoAdminRequired
- *
* @param string $userId ID of the user
* @return DataResponse<Http::STATUS_OK, UserStatusPublic, array{}>
* @throws OCSNotFoundException The user was not found
*
* 200: Status returned
*/
+ #[NoAdminRequired]
#[ApiRoute(verb: 'GET', url: '/api/v1/statuses/{userId}')]
public function find(string $userId): DataResponse {
try {
diff --git a/apps/user_status/lib/Controller/UserStatusController.php b/apps/user_status/lib/Controller/UserStatusController.php
index 70bf619253b..9b3807ce86e 100644
--- a/apps/user_status/lib/Controller/UserStatusController.php
+++ b/apps/user_status/lib/Controller/UserStatusController.php
@@ -20,6 +20,7 @@ use OCA\UserStatus\Service\StatusService;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\ApiRoute;
+use OCP\AppFramework\Http\Attribute\NoAdminRequired;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCS\OCSBadRequestException;
use OCP\AppFramework\OCS\OCSNotFoundException;
@@ -35,7 +36,7 @@ class UserStatusController extends OCSController {
public function __construct(
string $appName,
IRequest $request,
- private string $userId,
+ private ?string $userId,
private LoggerInterface $logger,
private StatusService $service,
private CalendarStatusService $calendarStatusService,
@@ -46,13 +47,12 @@ class UserStatusController extends OCSController {
/**
* Get the status of the current user
*
- * @NoAdminRequired
- *
* @return DataResponse<Http::STATUS_OK, UserStatusPrivate, array{}>
* @throws OCSNotFoundException The user was not found
*
* 200: The status was found successfully
*/
+ #[NoAdminRequired]
#[ApiRoute(verb: 'GET', url: '/api/v1/user_status')]
public function getStatus(): DataResponse {
try {
@@ -68,14 +68,13 @@ class UserStatusController extends OCSController {
/**
* Update the status type of the current user
*
- * @NoAdminRequired
- *
* @param string $statusType The new status type
* @return DataResponse<Http::STATUS_OK, UserStatusPrivate, array{}>
* @throws OCSBadRequestException The status type is invalid
*
* 200: The status was updated successfully
*/
+ #[NoAdminRequired]
#[ApiRoute(verb: 'PUT', url: '/api/v1/user_status/status')]
public function setStatus(string $statusType): DataResponse {
try {
@@ -92,8 +91,6 @@ class UserStatusController extends OCSController {
/**
* Set the message to a predefined message for the current user
*
- * @NoAdminRequired
- *
* @param string $messageId ID of the predefined message
* @param int|null $clearAt When the message should be cleared
* @return DataResponse<Http::STATUS_OK, UserStatusPrivate, array{}>
@@ -101,6 +98,7 @@ class UserStatusController extends OCSController {
*
* 200: The message was updated successfully
*/
+ #[NoAdminRequired]
#[ApiRoute(verb: 'PUT', url: '/api/v1/user_status/message/predefined')]
public function setPredefinedMessage(string $messageId,
?int $clearAt): DataResponse {
@@ -120,16 +118,16 @@ class UserStatusController extends OCSController {
/**
* Set the message to a custom message for the current user
*
- * @NoAdminRequired
- *
* @param string|null $statusIcon Icon of the status
* @param string|null $message Message of the status
* @param int|null $clearAt When the message should be cleared
* @return DataResponse<Http::STATUS_OK, UserStatusPrivate, array{}>
* @throws OCSBadRequestException The clearAt or icon is invalid or the message is too long
+ * @throws OCSNotFoundException No status for the current user
*
* 200: The message was updated successfully
*/
+ #[NoAdminRequired]
#[ApiRoute(verb: 'PUT', url: '/api/v1/user_status/message/custom')]
public function setCustomMessage(?string $statusIcon,
?string $message,
@@ -152,18 +150,19 @@ class UserStatusController extends OCSController {
} catch (StatusMessageTooLongException $ex) {
$this->logger->debug('New user-status for "' . $this->userId . '" was rejected due to a too long status message.');
throw new OCSBadRequestException($ex->getMessage(), $ex);
+ } catch (DoesNotExistException $ex) {
+ throw new OCSNotFoundException('No status for the current user');
}
}
/**
* Clear the message of the current user
*
- * @NoAdminRequired
- *
- * @return DataResponse<Http::STATUS_OK, array<empty>, array{}>
+ * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
*
* 200: Message cleared successfully
*/
+ #[NoAdminRequired]
#[ApiRoute(verb: 'DELETE', url: '/api/v1/user_status/message')]
public function clearMessage(): DataResponse {
$this->service->clearMessage($this->userId);
@@ -173,14 +172,13 @@ class UserStatusController extends OCSController {
/**
* Revert the status to the previous status
*
- * @NoAdminRequired
- *
* @param string $messageId ID of the message to delete
*
- * @return DataResponse<Http::STATUS_OK, UserStatusPrivate|array<empty>, array{}>
+ * @return DataResponse<Http::STATUS_OK, UserStatusPrivate|list<empty>, array{}>
*
* 200: Status reverted
*/
+ #[NoAdminRequired]
#[ApiRoute(verb: 'DELETE', url: '/api/v1/user_status/revert/{messageId}')]
public function revertStatus(string $messageId): DataResponse {
$backupStatus = $this->service->revertUserStatus($this->userId, $messageId, true);
diff --git a/apps/user_status/lib/Dashboard/UserStatusWidget.php b/apps/user_status/lib/Dashboard/UserStatusWidget.php
index 71f5145e283..2870a2c1907 100644
--- a/apps/user_status/lib/Dashboard/UserStatusWidget.php
+++ b/apps/user_status/lib/Dashboard/UserStatusWidget.php
@@ -32,14 +32,6 @@ use OCP\UserStatus\IUserStatus;
* @package OCA\UserStatus
*/
class UserStatusWidget implements IAPIWidget, IAPIWidgetV2, IIconWidget, IOptionWidget {
- private IL10N $l10n;
- private IDateTimeFormatter $dateTimeFormatter;
- private IURLGenerator $urlGenerator;
- private IInitialState $initialStateService;
- private IUserManager $userManager;
- private IUserSession $userSession;
- private StatusService $service;
-
/**
* UserStatusWidget constructor
*
@@ -51,20 +43,15 @@ class UserStatusWidget implements IAPIWidget, IAPIWidgetV2, IIconWidget, IOption
* @param IUserSession $userSession
* @param StatusService $service
*/
- public function __construct(IL10N $l10n,
- IDateTimeFormatter $dateTimeFormatter,
- IURLGenerator $urlGenerator,
- IInitialState $initialStateService,
- IUserManager $userManager,
- IUserSession $userSession,
- StatusService $service) {
- $this->l10n = $l10n;
- $this->dateTimeFormatter = $dateTimeFormatter;
- $this->urlGenerator = $urlGenerator;
- $this->initialStateService = $initialStateService;
- $this->userManager = $userManager;
- $this->userSession = $userSession;
- $this->service = $service;
+ public function __construct(
+ private IL10N $l10n,
+ private IDateTimeFormatter $dateTimeFormatter,
+ private IURLGenerator $urlGenerator,
+ private IInitialState $initialStateService,
+ private IUserManager $userManager,
+ private IUserSession $userSession,
+ private StatusService $service,
+ ) {
}
/**
@@ -124,7 +111,7 @@ class UserStatusWidget implements IAPIWidget, IAPIWidgetV2, IIconWidget, IOption
$this->service->findAllRecentStatusChanges($limit + 1, 0),
static function (UserStatus $status) use ($userId, $since): bool {
return $status->getUserId() !== $userId
- && ($since === null || $status->getStatusTimestamp() > (int) $since);
+ && ($since === null || $status->getStatusTimestamp() > (int)$since);
}
),
0,
@@ -156,21 +143,21 @@ class UserStatusWidget implements IAPIWidget, IAPIWidgetV2, IIconWidget, IOption
public function getItems(string $userId, ?string $since = null, int $limit = 7): array {
$widgetItemsData = $this->getWidgetData($userId, $since, $limit);
- return array_map(function (array $widgetData) {
+ return array_values(array_map(function (array $widgetData) {
$formattedDate = $this->dateTimeFormatter->formatTimeSpan($widgetData['timestamp']);
return new WidgetItem(
$widgetData['displayName'],
$widgetData['icon'] . ($widgetData['icon'] ? ' ' : '') . $widgetData['message'] . ', ' . $formattedDate,
// https://nextcloud.local/index.php/u/julien
$this->urlGenerator->getAbsoluteURL(
- $this->urlGenerator->linkToRoute('core.ProfilePage.index', ['targetUserId' => $widgetData['userId']])
+ $this->urlGenerator->linkToRoute('profile.ProfilePage.index', ['targetUserId' => $widgetData['userId']])
),
$this->urlGenerator->getAbsoluteURL(
$this->urlGenerator->linkToRoute('core.avatar.getAvatar', ['userId' => $widgetData['userId'], 'size' => 44])
),
- (string) $widgetData['timestamp']
+ (string)$widgetData['timestamp']
);
- }, $widgetItemsData);
+ }, $widgetItemsData));
}
/**
diff --git a/apps/user_status/lib/Db/UserStatus.php b/apps/user_status/lib/Db/UserStatus.php
index 1be35830853..b2da4a9e07a 100644
--- a/apps/user_status/lib/Db/UserStatus.php
+++ b/apps/user_status/lib/Db/UserStatus.php
@@ -9,6 +9,7 @@ declare(strict_types=1);
namespace OCA\UserStatus\Db;
use OCP\AppFramework\Db\Entity;
+use OCP\DB\Types;
/**
* Class UserStatus
@@ -73,13 +74,13 @@ class UserStatus extends Entity {
public function __construct() {
$this->addType('userId', 'string');
$this->addType('status', 'string');
- $this->addType('statusTimestamp', 'int');
+ $this->addType('statusTimestamp', Types::INTEGER);
$this->addType('isUserDefined', 'boolean');
$this->addType('messageId', 'string');
$this->addType('customIcon', 'string');
$this->addType('customMessage', 'string');
- $this->addType('clearAt', 'int');
+ $this->addType('clearAt', Types::INTEGER);
$this->addType('isBackup', 'boolean');
- $this->addType('statusMessageTimestamp', 'int');
+ $this->addType('statusMessageTimestamp', Types::INTEGER);
}
}
diff --git a/apps/user_status/lib/Db/UserStatusMapper.php b/apps/user_status/lib/Db/UserStatusMapper.php
index c98f0bf817f..15982d44fd8 100644
--- a/apps/user_status/lib/Db/UserStatusMapper.php
+++ b/apps/user_status/lib/Db/UserStatusMapper.php
@@ -9,6 +9,7 @@ declare(strict_types=1);
namespace OCA\UserStatus\Db;
+use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Db\QBMapper;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IDBConnection;
@@ -83,7 +84,7 @@ class UserStatusMapper extends QBMapper {
/**
* @param string $userId
* @return UserStatus
- * @throws \OCP\AppFramework\Db\DoesNotExistException
+ * @throws DoesNotExistException
*/
public function findByUserId(string $userId, bool $isBackup = false): UserStatus {
$qb = $this->db->getQueryBuilder();
@@ -126,7 +127,7 @@ class UserStatusMapper extends QBMapper {
$qb->expr()->eq('status', $qb->createNamedParameter(IUserStatus::ONLINE))
));
- $qb->execute();
+ $qb->executeStatement();
}
/**
@@ -140,7 +141,7 @@ class UserStatusMapper extends QBMapper {
->where($qb->expr()->isNotNull('clear_at'))
->andWhere($qb->expr()->lte('clear_at', $qb->createNamedParameter($timestamp, IQueryBuilder::PARAM_INT)));
- $qb->execute();
+ $qb->executeStatement();
}
diff --git a/apps/user_status/lib/Listener/BeforeTemplateRenderedListener.php b/apps/user_status/lib/Listener/BeforeTemplateRenderedListener.php
index 8b639169b07..ab3a1e62beb 100644
--- a/apps/user_status/lib/Listener/BeforeTemplateRenderedListener.php
+++ b/apps/user_status/lib/Listener/BeforeTemplateRenderedListener.php
@@ -18,6 +18,7 @@ use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener;
use OCP\IInitialStateService;
use OCP\IUserSession;
+use OCP\Util;
/** @template-implements IEventListener<BeforeTemplateRenderedEvent> */
class BeforeTemplateRenderedListener implements IEventListener {
@@ -25,15 +26,6 @@ class BeforeTemplateRenderedListener implements IEventListener {
/** @var ProfileManager */
private $profileManager;
- /** @var IUserSession */
- private $userSession;
-
- /** @var IInitialStateService */
- private $initialState;
-
- /** @var JSDataService */
- private $jsDataService;
-
/**
* BeforeTemplateRenderedListener constructor.
*
@@ -44,14 +36,11 @@ class BeforeTemplateRenderedListener implements IEventListener {
*/
public function __construct(
ProfileManager $profileManager,
- IUserSession $userSession,
- IInitialStateService $initialState,
- JSDataService $jsDataService
+ private IUserSession $userSession,
+ private IInitialStateService $initialState,
+ private JSDataService $jsDataService,
) {
$this->profileManager = $profileManager;
- $this->userSession = $userSession;
- $this->initialState = $initialState;
- $this->jsDataService = $jsDataService;
}
/**
@@ -80,7 +69,7 @@ class BeforeTemplateRenderedListener implements IEventListener {
return ['profileEnabled' => $this->profileManager->isProfileEnabled($user)];
});
- \OCP\Util::addScript('user_status', 'menu');
- \OCP\Util::addStyle('user_status', 'user-status-menu');
+ Util::addScript('user_status', 'menu');
+ Util::addStyle('user_status', 'user-status-menu');
}
}
diff --git a/apps/user_status/lib/Listener/OutOfOfficeStatusListener.php b/apps/user_status/lib/Listener/OutOfOfficeStatusListener.php
index 7b1a91ead8c..6337d637896 100644
--- a/apps/user_status/lib/Listener/OutOfOfficeStatusListener.php
+++ b/apps/user_status/lib/Listener/OutOfOfficeStatusListener.php
@@ -15,34 +15,41 @@ use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener;
use OCP\User\Events\OutOfOfficeChangedEvent;
use OCP\User\Events\OutOfOfficeClearedEvent;
+use OCP\User\Events\OutOfOfficeEndedEvent;
use OCP\User\Events\OutOfOfficeScheduledEvent;
+use OCP\User\Events\OutOfOfficeStartedEvent;
use OCP\UserStatus\IManager;
use OCP\UserStatus\IUserStatus;
/**
* Class UserDeletedListener
*
- * @template-implements IEventListener<OutOfOfficeScheduledEvent|OutOfOfficeChangedEvent|OutOfOfficeClearedEvent>
+ * @template-implements IEventListener<OutOfOfficeScheduledEvent|OutOfOfficeChangedEvent|OutOfOfficeClearedEvent|OutOfOfficeStartedEvent|OutOfOfficeEndedEvent>
*
*/
class OutOfOfficeStatusListener implements IEventListener {
- public function __construct(private IJobList $jobsList,
+ public function __construct(
+ private IJobList $jobsList,
private ITimeFactory $time,
- private IManager $manager) {
+ private IManager $manager,
+ ) {
}
/**
* @inheritDoc
*/
public function handle(Event $event): void {
- if($event instanceof OutOfOfficeClearedEvent) {
+ if ($event instanceof OutOfOfficeClearedEvent) {
$this->manager->revertUserStatus($event->getData()->getUser()->getUID(), IUserStatus::MESSAGE_OUT_OF_OFFICE, IUserStatus::DND);
$this->jobsList->scheduleAfter(UserStatusAutomation::class, $this->time->getTime(), ['userId' => $event->getData()->getUser()->getUID()]);
return;
}
if ($event instanceof OutOfOfficeScheduledEvent
- || $event instanceof OutOfOfficeChangedEvent) {
+ || $event instanceof OutOfOfficeChangedEvent
+ || $event instanceof OutOfOfficeStartedEvent
+ || $event instanceof OutOfOfficeEndedEvent
+ ) {
// This might be overwritten by the office hours automation, but that is ok. This is just in case no office hours are set
$this->jobsList->scheduleAfter(UserStatusAutomation::class, $this->time->getTime(), ['userId' => $event->getData()->getUser()->getUID()]);
}
diff --git a/apps/user_status/lib/Listener/UserDeletedListener.php b/apps/user_status/lib/Listener/UserDeletedListener.php
index 55ec5fe13ff..bf021635156 100644
--- a/apps/user_status/lib/Listener/UserDeletedListener.php
+++ b/apps/user_status/lib/Listener/UserDeletedListener.php
@@ -21,16 +21,14 @@ use OCP\User\Events\UserDeletedEvent;
*/
class UserDeletedListener implements IEventListener {
- /** @var StatusService */
- private $service;
-
/**
* UserDeletedListener constructor.
*
* @param StatusService $service
*/
- public function __construct(StatusService $service) {
- $this->service = $service;
+ public function __construct(
+ private StatusService $service,
+ ) {
}
diff --git a/apps/user_status/lib/Listener/UserLiveStatusListener.php b/apps/user_status/lib/Listener/UserLiveStatusListener.php
index fa4ff8e4aba..2db999d3712 100644
--- a/apps/user_status/lib/Listener/UserLiveStatusListener.php
+++ b/apps/user_status/lib/Listener/UserLiveStatusListener.php
@@ -29,18 +29,13 @@ use Psr\Log\LoggerInterface;
* @template-implements IEventListener<UserLiveStatusEvent>
*/
class UserLiveStatusListener implements IEventListener {
- private UserStatusMapper $mapper;
- private StatusService $statusService;
- private ITimeFactory $timeFactory;
-
- public function __construct(UserStatusMapper $mapper,
- StatusService $statusService,
- ITimeFactory $timeFactory,
+ public function __construct(
+ private UserStatusMapper $mapper,
+ private StatusService $statusService,
+ private ITimeFactory $timeFactory,
private CalendarStatusService $calendarStatusService,
- private LoggerInterface $logger) {
- $this->mapper = $mapper;
- $this->statusService = $statusService;
- $this->timeFactory = $timeFactory;
+ private LoggerInterface $logger,
+ ) {
}
/**
@@ -66,13 +61,13 @@ class UserLiveStatusListener implements IEventListener {
// If the status is user-defined and one of the persistent status, we
// will not override it.
- if ($userStatus->getIsUserDefined() &&
- \in_array($userStatus->getStatus(), StatusService::PERSISTENT_STATUSES, true)) {
+ if ($userStatus->getIsUserDefined()
+ && \in_array($userStatus->getStatus(), StatusService::PERSISTENT_STATUSES, true)) {
return;
}
// Don't overwrite the "away" calendar status if it's set
- if($userStatus->getMessageId() === IUserStatus::MESSAGE_CALENDAR_BUSY) {
+ if ($userStatus->getMessageId() === IUserStatus::MESSAGE_CALENDAR_BUSY) {
$event->setUserStatus(new ConnectorUserStatus($userStatus));
return;
}
diff --git a/apps/user_status/lib/Migration/Version1008Date20230921144701.php b/apps/user_status/lib/Migration/Version1008Date20230921144701.php
index 561dfd343cf..30ebbf37b0e 100644
--- a/apps/user_status/lib/Migration/Version1008Date20230921144701.php
+++ b/apps/user_status/lib/Migration/Version1008Date20230921144701.php
@@ -18,7 +18,9 @@ use OCP\Migration\SimpleMigrationStep;
class Version1008Date20230921144701 extends SimpleMigrationStep {
- public function __construct(private IDBConnection $connection) {
+ public function __construct(
+ private IDBConnection $connection,
+ ) {
}
public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper {
diff --git a/apps/user_status/lib/ResponseDefinitions.php b/apps/user_status/lib/ResponseDefinitions.php
index 6668c40b917..82f606dd301 100644
--- a/apps/user_status/lib/ResponseDefinitions.php
+++ b/apps/user_status/lib/ResponseDefinitions.php
@@ -22,7 +22,6 @@ namespace OCA\UserStatus;
* icon: string,
* message: string,
* clearAt: ?UserStatusClearAt,
- * visible: ?bool,
* }
*
* @psalm-type UserStatusType = "online"|"away"|"dnd"|"busy"|"offline"|"invisible"
diff --git a/apps/user_status/lib/Service/JSDataService.php b/apps/user_status/lib/Service/JSDataService.php
index a6b9b0b4056..a777e97fe57 100644
--- a/apps/user_status/lib/Service/JSDataService.php
+++ b/apps/user_status/lib/Service/JSDataService.php
@@ -14,22 +14,16 @@ use OCP\UserStatus\IUserStatus;
class JSDataService implements \JsonSerializable {
- /** @var IUserSession */
- private $userSession;
-
- /** @var StatusService */
- private $statusService;
-
/**
* JSDataService constructor.
*
* @param IUserSession $userSession
* @param StatusService $statusService
*/
- public function __construct(IUserSession $userSession,
- StatusService $statusService) {
- $this->userSession = $userSession;
- $this->statusService = $statusService;
+ public function __construct(
+ private IUserSession $userSession,
+ private StatusService $statusService,
+ ) {
}
public function jsonSerialize(): array {
diff --git a/apps/user_status/lib/Service/PredefinedStatusService.php b/apps/user_status/lib/Service/PredefinedStatusService.php
index b17442a0caa..599d5b8b52f 100644
--- a/apps/user_status/lib/Service/PredefinedStatusService.php
+++ b/apps/user_status/lib/Service/PredefinedStatusService.php
@@ -20,6 +20,7 @@ use OCP\UserStatus\IUserStatus;
* @package OCA\UserStatus\Service
*/
class PredefinedStatusService {
+ private const BE_RIGHT_BACK = 'be-right-back';
private const MEETING = 'meeting';
private const COMMUTING = 'commuting';
private const SICK_LEAVE = 'sick-leave';
@@ -31,16 +32,14 @@ class PredefinedStatusService {
public const CALL = 'call';
public const OUT_OF_OFFICE = 'out-of-office';
- /** @var IL10N */
- private $l10n;
-
/**
* DefaultStatusService constructor.
*
* @param IL10N $l10n
*/
- public function __construct(IL10N $l10n) {
- $this->l10n = $l10n;
+ public function __construct(
+ private IL10N $l10n,
+ ) {
}
/**
@@ -67,6 +66,15 @@ class PredefinedStatusService {
],
],
[
+ 'id' => self::BE_RIGHT_BACK,
+ 'icon' => '⏳',
+ 'message' => $this->getTranslatedStatusForId(self::BE_RIGHT_BACK),
+ 'clearAt' => [
+ 'type' => 'period',
+ 'time' => 900,
+ ],
+ ],
+ [
'id' => self::REMOTE_WORK,
'icon' => '🏡',
'message' => $this->getTranslatedStatusForId(self::REMOTE_WORK),
@@ -145,6 +153,9 @@ class PredefinedStatusService {
case self::REMOTE_WORK:
return '🏡';
+ case self::BE_RIGHT_BACK:
+ return '⏳';
+
case self::CALL:
return '💬';
@@ -181,6 +192,9 @@ class PredefinedStatusService {
case self::CALL:
return $this->l10n->t('In a call');
+ case self::BE_RIGHT_BACK:
+ return $this->l10n->t('Be right back');
+
default:
return null;
}
@@ -197,6 +211,7 @@ class PredefinedStatusService {
self::SICK_LEAVE,
self::VACATIONING,
self::OUT_OF_OFFICE,
+ self::BE_RIGHT_BACK,
self::REMOTE_WORK,
IUserStatus::MESSAGE_CALL,
IUserStatus::MESSAGE_AVAILABILITY,
diff --git a/apps/user_status/lib/Service/StatusService.php b/apps/user_status/lib/Service/StatusService.php
index 3246777b46b..188eb26d1d7 100644
--- a/apps/user_status/lib/Service/StatusService.php
+++ b/apps/user_status/lib/Service/StatusService.php
@@ -22,6 +22,7 @@ use OCP\IConfig;
use OCP\IEmojiHelper;
use OCP\IUserManager;
use OCP\UserStatus\IUserStatus;
+use Psr\Log\LoggerInterface;
use function in_array;
/**
@@ -63,12 +64,15 @@ class StatusService {
/** @var int */
public const MAXIMUM_MESSAGE_LENGTH = 80;
- public function __construct(private UserStatusMapper $mapper,
+ public function __construct(
+ private UserStatusMapper $mapper,
private ITimeFactory $timeFactory,
private PredefinedStatusService $predefinedStatusService,
private IEmojiHelper $emojiHelper,
private IConfig $config,
- private IUserManager $userManager) {
+ private IUserManager $userManager,
+ private LoggerInterface $logger,
+ ) {
$this->shareeEnumeration = $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes';
$this->shareeEnumerationInGroupOnly = $this->shareeEnumeration && $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_group', 'no') === 'yes';
$this->shareeEnumerationPhone = $this->shareeEnumeration && $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_phone', 'no') === 'yes';
@@ -163,7 +167,7 @@ class StatusService {
$userStatus->setIsBackup(false);
if ($userStatus->getId() === null) {
- return $this->mapper->insert($userStatus);
+ return $this->insertWithoutThrowingUniqueConstrain($userStatus);
}
return $this->mapper->update($userStatus);
@@ -207,7 +211,7 @@ class StatusService {
$userStatus->setStatusMessageTimestamp($this->timeFactory->now()->getTimestamp());
if ($userStatus->getId() === null) {
- return $this->mapper->insert($userStatus);
+ return $this->insertWithoutThrowingUniqueConstrain($userStatus);
}
return $this->mapper->update($userStatus);
@@ -244,8 +248,28 @@ class StatusService {
$userStatus->setUserId($userId);
}
- // CALL trumps CALENDAR status, but we don't need to do anything but overwrite the message
- if ($userStatus->getMessageId() === IUserStatus::MESSAGE_CALENDAR_BUSY && $messageId === IUserStatus::MESSAGE_CALL) {
+ $updateStatus = false;
+ if ($messageId === IUserStatus::MESSAGE_OUT_OF_OFFICE) {
+ // OUT_OF_OFFICE trumps AVAILABILITY, CALL and CALENDAR status
+ $updateStatus = $userStatus->getMessageId() === IUserStatus::MESSAGE_AVAILABILITY || $userStatus->getMessageId() === IUserStatus::MESSAGE_CALL || $userStatus->getMessageId() === IUserStatus::MESSAGE_CALENDAR_BUSY;
+ } elseif ($messageId === IUserStatus::MESSAGE_AVAILABILITY) {
+ // AVAILABILITY trumps CALL and CALENDAR status
+ $updateStatus = $userStatus->getMessageId() === IUserStatus::MESSAGE_CALL || $userStatus->getMessageId() === IUserStatus::MESSAGE_CALENDAR_BUSY;
+ } elseif ($messageId === IUserStatus::MESSAGE_CALL) {
+ // CALL trumps CALENDAR status
+ $updateStatus = $userStatus->getMessageId() === IUserStatus::MESSAGE_CALENDAR_BUSY;
+ }
+
+ if ($messageId === IUserStatus::MESSAGE_OUT_OF_OFFICE || $messageId === IUserStatus::MESSAGE_AVAILABILITY || $messageId === IUserStatus::MESSAGE_CALL || $messageId === IUserStatus::MESSAGE_CALENDAR_BUSY) {
+ if ($updateStatus) {
+ $this->logger->debug('User ' . $userId . ' is currently NOT available, overwriting status [status: ' . $userStatus->getStatus() . ', messageId: ' . json_encode($userStatus->getMessageId()) . ']', ['app' => 'dav']);
+ } else {
+ $this->logger->debug('User ' . $userId . ' is currently NOT available, but we are NOT overwriting status [status: ' . $userStatus->getStatus() . ', messageId: ' . json_encode($userStatus->getMessageId()) . ']', ['app' => 'dav']);
+ }
+ }
+
+ // There should be a backup already or none is needed. So we take a shortcut.
+ if ($updateStatus) {
$userStatus->setStatus($status);
$userStatus->setStatusTimestamp($this->timeFactory->getTime());
$userStatus->setIsUserDefined(true);
@@ -265,7 +289,7 @@ class StatusService {
// If we just created the backup
// we need to create a new status to insert
- // Unfortunatley there's no way to unset the DB ID on an Entity
+ // Unfortunately there's no way to unset the DB ID on an Entity
$userStatus = new UserStatus();
$userStatus->setUserId($userId);
}
@@ -289,7 +313,7 @@ class StatusService {
if ($userStatus->getId() !== null) {
return $this->mapper->update($userStatus);
}
- return $this->mapper->insert($userStatus);
+ return $this->insertWithoutThrowingUniqueConstrain($userStatus);
}
/**
@@ -336,7 +360,7 @@ class StatusService {
$userStatus->setStatusMessageTimestamp($this->timeFactory->now()->getTimestamp());
if ($userStatus->getId() === null) {
- return $this->mapper->insert($userStatus);
+ return $this->insertWithoutThrowingUniqueConstrain($userStatus);
}
return $this->mapper->update($userStatus);
@@ -475,10 +499,10 @@ class StatusService {
return;
}
// If there is a custom message, don't overwrite it
- if(empty($status->getCustomMessage())) {
+ if (empty($status->getCustomMessage())) {
$status->setCustomMessage($predefinedMessage['message']);
}
- if(empty($status->getCustomIcon())) {
+ if (empty($status->getCustomIcon())) {
$status->setCustomIcon($predefinedMessage['icon']);
}
}
@@ -560,4 +584,16 @@ class StatusService {
// For users that matched restore the previous status
$this->mapper->restoreBackupStatuses($restoreIds);
}
+
+ protected function insertWithoutThrowingUniqueConstrain(UserStatus $userStatus): UserStatus {
+ try {
+ return $this->mapper->insert($userStatus);
+ } catch (Exception $e) {
+ // Ignore if a parallel request already set the status
+ if ($e->getReason() !== Exception::REASON_UNIQUE_CONSTRAINT_VIOLATION) {
+ throw $e;
+ }
+ }
+ return $userStatus;
+ }
}