Add Status Dashboard
Signed-off-by: Georg Ehrke <developer@georgehrke.com>
This commit is contained in:
parent
03603db486
commit
bd6a6cf3bf
|
@ -15,6 +15,7 @@ return array(
|
|||
'OCA\\UserStatus\\Controller\\PredefinedStatusController' => $baseDir . '/../lib/Controller/PredefinedStatusController.php',
|
||||
'OCA\\UserStatus\\Controller\\StatusesController' => $baseDir . '/../lib/Controller/StatusesController.php',
|
||||
'OCA\\UserStatus\\Controller\\UserStatusController' => $baseDir . '/../lib/Controller/UserStatusController.php',
|
||||
'OCA\\UserStatus\\Dashboard\\UserStatusWidget' => $baseDir . '/../lib/Dashboard/UserStatusWidget.php',
|
||||
'OCA\\UserStatus\\Db\\UserStatus' => $baseDir . '/../lib/Db/UserStatus.php',
|
||||
'OCA\\UserStatus\\Db\\UserStatusMapper' => $baseDir . '/../lib/Db/UserStatusMapper.php',
|
||||
'OCA\\UserStatus\\Exception\\InvalidClearAtException' => $baseDir . '/../lib/Exception/InvalidClearAtException.php',
|
||||
|
|
|
@ -30,6 +30,7 @@ class ComposerStaticInitUserStatus
|
|||
'OCA\\UserStatus\\Controller\\PredefinedStatusController' => __DIR__ . '/..' . '/../lib/Controller/PredefinedStatusController.php',
|
||||
'OCA\\UserStatus\\Controller\\StatusesController' => __DIR__ . '/..' . '/../lib/Controller/StatusesController.php',
|
||||
'OCA\\UserStatus\\Controller\\UserStatusController' => __DIR__ . '/..' . '/../lib/Controller/UserStatusController.php',
|
||||
'OCA\\UserStatus\\Dashboard\\UserStatusWidget' => __DIR__ . '/..' . '/../lib/Dashboard/UserStatusWidget.php',
|
||||
'OCA\\UserStatus\\Db\\UserStatus' => __DIR__ . '/..' . '/../lib/Db/UserStatus.php',
|
||||
'OCA\\UserStatus\\Db\\UserStatusMapper' => __DIR__ . '/..' . '/../lib/Db/UserStatusMapper.php',
|
||||
'OCA\\UserStatus\\Exception\\InvalidClearAtException' => __DIR__ . '/..' . '/../lib/Exception/InvalidClearAtException.php',
|
||||
|
|
|
@ -20,6 +20,10 @@
|
|||
*
|
||||
*/
|
||||
|
||||
.icon-user-status {
|
||||
@include icon-color('app', 'user_status', $color-black, 1);
|
||||
}
|
||||
|
||||
.icon-user-status-away {
|
||||
@include icon-color('user-status-away', 'user_status', '#F4A331', 2);
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -30,6 +30,7 @@ use OCA\UserStatus\Connector\UserStatusProvider;
|
|||
use OCA\UserStatus\Listener\BeforeTemplateRenderedListener;
|
||||
use OCA\UserStatus\Listener\UserDeletedListener;
|
||||
use OCA\UserStatus\Listener\UserLiveStatusListener;
|
||||
use OCA\UserStatus\Dashboard\UserStatusWidget;
|
||||
use OCP\AppFramework\App;
|
||||
use OCP\AppFramework\Bootstrap\IBootContext;
|
||||
use OCP\AppFramework\Bootstrap\IBootstrap;
|
||||
|
@ -69,6 +70,9 @@ class Application extends App implements IBootstrap {
|
|||
$context->registerEventListener(UserDeletedEvent::class, UserDeletedListener::class);
|
||||
$context->registerEventListener(UserLiveStatusEvent::class, UserLiveStatusListener::class);
|
||||
$context->registerEventListener(BeforeTemplateRenderedEvent::class, BeforeTemplateRenderedListener::class);
|
||||
|
||||
// Register the Dashboard panel
|
||||
$context->registerDashboardWidget(UserStatusWidget::class);
|
||||
}
|
||||
|
||||
public function boot(IBootContext $context): void {
|
||||
|
|
|
@ -0,0 +1,156 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @copyright Copyright (c) 2020, Georg Ehrke
|
||||
*
|
||||
* @author Georg Ehrke <oc.list@georgehrke.com>
|
||||
*
|
||||
* @license AGPL-3.0
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License, version 3,
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
namespace OCA\UserStatus\Dashboard;
|
||||
|
||||
use OCA\UserStatus\AppInfo\Application;
|
||||
use OCA\UserStatus\Db\UserStatus;
|
||||
use OCA\UserStatus\Service\StatusService;
|
||||
use OCP\Dashboard\IWidget;
|
||||
use OCP\IInitialStateService;
|
||||
use OCP\IL10N;
|
||||
use OCP\IUserManager;
|
||||
use OCP\IUserSession;
|
||||
|
||||
/**
|
||||
* Class UserStatusWidget
|
||||
*
|
||||
* @package OCA\UserStatus
|
||||
*/
|
||||
class UserStatusWidget implements IWidget {
|
||||
|
||||
/** @var IL10N */
|
||||
private $l10n;
|
||||
|
||||
/** @var IInitialStateService */
|
||||
private $initialStateService;
|
||||
|
||||
/** @var IUserManager */
|
||||
private $userManager;
|
||||
|
||||
/** @var IUserSession */
|
||||
private $userSession;
|
||||
|
||||
/** @var StatusService */
|
||||
private $service;
|
||||
|
||||
/**
|
||||
* UserStatusWidget constructor
|
||||
*
|
||||
* @param IL10N $l10n
|
||||
* @param IInitialStateService $initialStateService
|
||||
* @param IUserManager $userManager
|
||||
* @param IUserSession $userSession
|
||||
* @param StatusService $service
|
||||
*/
|
||||
public function __construct(IL10N $l10n,
|
||||
IInitialStateService $initialStateService,
|
||||
IUserManager $userManager,
|
||||
IUserSession $userSession,
|
||||
StatusService $service) {
|
||||
$this->l10n = $l10n;
|
||||
$this->initialStateService = $initialStateService;
|
||||
$this->userManager = $userManager;
|
||||
$this->userSession = $userSession;
|
||||
$this->service = $service;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getId(): string {
|
||||
return Application::APP_ID;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getTitle(): string {
|
||||
return $this->l10n->t('Recent statuses');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getOrder(): int {
|
||||
return 5;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getIconClass(): string {
|
||||
return 'icon-user-status';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getUrl(): ?string {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function load(): void {
|
||||
\OCP\Util::addScript(Application::APP_ID, 'dashboard');
|
||||
|
||||
$currentUser = $this->userSession->getUser();
|
||||
if ($currentUser === null) {
|
||||
$this->initialStateService->provideInitialState(Application::APP_ID, 'dashboard_data', []);
|
||||
return;
|
||||
}
|
||||
$currentUserId = $currentUser->getUID();
|
||||
|
||||
// Fetch status updates and filter current user
|
||||
$recentStatusUpdates = array_slice(
|
||||
array_filter(
|
||||
$this->service->findAllRecentStatusChanges(8, 0),
|
||||
static function (UserStatus $status) use ($currentUserId): bool {
|
||||
return $status->getUserId() !== $currentUserId;
|
||||
}
|
||||
),
|
||||
0,
|
||||
7
|
||||
);
|
||||
|
||||
$this->initialStateService->provideInitialState(Application::APP_ID, 'dashboard_data', array_map(function (UserStatus $status): array {
|
||||
$user = $this->userManager->get($status->getUserId());
|
||||
$displayName = $status->getUserId();
|
||||
if ($user !== null) {
|
||||
$displayName = $user->getDisplayName();
|
||||
}
|
||||
|
||||
return [
|
||||
'userId' => $status->getUserId(),
|
||||
'displayName' => $displayName,
|
||||
'status' => $status->getStatus() === 'invisible' ? 'offline' : $status->getStatus(),
|
||||
'icon' => $status->getCustomIcon(),
|
||||
'message' => $status->getCustomMessage(),
|
||||
'timestamp' => $status->getStatusTimestamp(),
|
||||
];
|
||||
}, $recentStatusUpdates));
|
||||
}
|
||||
}
|
|
@ -69,6 +69,33 @@ class UserStatusMapper extends QBMapper {
|
|||
return $this->findEntities($qb);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int|null $limit
|
||||
* @param int|null $offset
|
||||
* @return array
|
||||
*/
|
||||
public function findAllRecent(?int $limit = null, ?int $offset = null): array {
|
||||
$qb = $this->db->getQueryBuilder();
|
||||
|
||||
$qb
|
||||
->select('*')
|
||||
->from($this->tableName)
|
||||
->orderBy('status_timestamp', 'DESC')
|
||||
->where($qb->expr()->notIn('status', $qb->createNamedParameter(['online', 'away'], IQueryBuilder::PARAM_STR_ARRAY)))
|
||||
->orWhere($qb->expr()->isNotNull('message_id'))
|
||||
->orWhere($qb->expr()->isNotNull('custom_icon'))
|
||||
->orWhere($qb->expr()->isNotNull('custom_message'));
|
||||
|
||||
if ($limit !== null) {
|
||||
$qb->setMaxResults($limit);
|
||||
}
|
||||
if ($offset !== null) {
|
||||
$qb->setFirstResult($offset);
|
||||
}
|
||||
|
||||
return $this->findEntities($qb);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $userId
|
||||
* @return UserStatus
|
||||
|
|
|
@ -95,6 +95,17 @@ class StatusService {
|
|||
}, $this->mapper->findAll($limit, $offset));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int|null $limit
|
||||
* @param int|null $offset
|
||||
* @return array
|
||||
*/
|
||||
public function findAllRecentStatusChanges(?int $limit = null, ?int $offset = null): array {
|
||||
return array_map(function ($status) {
|
||||
return $this->processStatus($status);
|
||||
}, $this->mapper->findAllRecent($limit, $offset));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $userId
|
||||
* @return UserStatus
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
/**
|
||||
* @copyright Copyright (c) 2020 Georg Ehrke
|
||||
*
|
||||
* @author Georg Ehrke <oc.list@georgehrke.com>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
import Vue from 'vue'
|
||||
import { generateFilePath } from '@nextcloud/router'
|
||||
import { getRequestToken } from '@nextcloud/auth'
|
||||
import { translate, translatePlural } from '@nextcloud/l10n'
|
||||
import Dashboard from './views/Dashboard'
|
||||
|
||||
// eslint-disable-next-line
|
||||
__webpack_nonce__ = btoa(getRequestToken())
|
||||
|
||||
// eslint-disable-next-line
|
||||
__webpack_public_path__ = generateFilePath('user_status', '', 'js/')
|
||||
|
||||
Vue.prototype.t = translate
|
||||
Vue.prototype.n = translatePlural
|
||||
Vue.prototype.OC = OC
|
||||
Vue.prototype.OCA = OCA
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
OCA.Dashboard.register('user_status', (el) => {
|
||||
const View = Vue.extend(Dashboard)
|
||||
new View({
|
||||
propsData: {},
|
||||
}).$mount(el)
|
||||
})
|
||||
|
||||
})
|
|
@ -1,3 +1,24 @@
|
|||
/**
|
||||
* @copyright Copyright (c) 2020 Georg Ehrke
|
||||
*
|
||||
* @author Georg Ehrke <oc.list@georgehrke.com>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
import Vue from 'vue'
|
||||
import { getRequestToken } from '@nextcloud/auth'
|
||||
import App from './App'
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
<!--
|
||||
- @copyright Copyright (c) 2020 Georg Ehrke <oc.list@georgehrke.com>
|
||||
- @author Georg Ehrke <oc.list@georgehrke.com>
|
||||
-
|
||||
- @license GNU AGPL version 3 or any later version
|
||||
-
|
||||
- This program is free software: you can redistribute it and/or modify
|
||||
- it under the terms of the GNU Affero General Public License as
|
||||
- published by the Free Software Foundation, either version 3 of the
|
||||
- License, or (at your option) any later version.
|
||||
-
|
||||
- This program is distributed in the hope that it will be useful,
|
||||
- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
- GNU Affero General Public License for more details.
|
||||
-
|
||||
- You should have received a copy of the GNU Affero General Public License
|
||||
- along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-
|
||||
-->
|
||||
|
||||
<template>
|
||||
<DashboardWidget
|
||||
id="user-status_panel"
|
||||
:items="items"
|
||||
:loading="loading">
|
||||
<template v-slot:empty-content>
|
||||
<EmptyContent
|
||||
id="user_status-widget-empty-content"
|
||||
icon="icon-user-status">
|
||||
{{ t('user_status', 'No recent status changes') }}
|
||||
</EmptyContent>
|
||||
</template>
|
||||
</DashboardWidget>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { DashboardWidget } from '@nextcloud/vue-dashboard'
|
||||
import EmptyContent from '@nextcloud/vue/dist/Components/EmptyContent'
|
||||
import { loadState } from '@nextcloud/initial-state'
|
||||
import moment from '@nextcloud/moment'
|
||||
|
||||
export default {
|
||||
name: 'Dashboard',
|
||||
components: {
|
||||
DashboardWidget,
|
||||
EmptyContent,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
statuses: [],
|
||||
loading: true,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
items() {
|
||||
return this.statuses.map((item) => {
|
||||
const icon = item.icon || ''
|
||||
const message = item.message || ''
|
||||
const status = `${icon} ${message}`
|
||||
|
||||
let subText
|
||||
if (item.icon === null && item.message === null && item.timestamp === null) {
|
||||
subText = ''
|
||||
} else if (item.icon === null && item.message === null && item.timestamp !== null) {
|
||||
subText = moment(item.timestamp, 'X').fromNow()
|
||||
} else if (item.timestamp !== null) {
|
||||
subText = this.t('user_status', '{status}, {timestamp}', {
|
||||
status,
|
||||
timestamp: moment(item.timestamp, 'X').fromNow(),
|
||||
})
|
||||
} else {
|
||||
subText = status
|
||||
}
|
||||
|
||||
return {
|
||||
mainText: item.displayName,
|
||||
subText,
|
||||
avatarUsername: item.userId,
|
||||
}
|
||||
})
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
try {
|
||||
this.statuses = loadState('user_status', 'dashboard_data')
|
||||
this.loading = false
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
#user_status-widget-empty-content {
|
||||
text-align: center;
|
||||
margin-top: 5vh;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,261 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* @copyright Copyright (c) 2020, Georg Ehrke
|
||||
*
|
||||
* @author Georg Ehrke <oc.list@georgehrke.com>
|
||||
*
|
||||
* @license AGPL-3.0
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License, version 3,
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OCA\UserStatus\Tests\Dashboard;
|
||||
|
||||
use OCA\UserStatus\Dashboard\UserStatusWidget;
|
||||
use OCA\UserStatus\Db\UserStatus;
|
||||
use OCA\UserStatus\Service\StatusService;
|
||||
use OCP\IInitialStateService;
|
||||
use OCP\IL10N;
|
||||
use OCP\IUser;
|
||||
use OCP\IUserManager;
|
||||
use OCP\IUserSession;
|
||||
use Test\TestCase;
|
||||
|
||||
class UserStatusWidgetTest extends TestCase {
|
||||
|
||||
/** @var IL10N|\PHPUnit\Framework\MockObject\MockObject */
|
||||
private $l10n;
|
||||
|
||||
/** @var IInitialStateService|\PHPUnit\Framework\MockObject\MockObject */
|
||||
private $initialState;
|
||||
|
||||
/** @var IUserManager|\PHPUnit\Framework\MockObject\MockObject */
|
||||
private $userManager;
|
||||
|
||||
/** @var IUserSession|\PHPUnit\Framework\MockObject\MockObject */
|
||||
private $userSession;
|
||||
|
||||
/** @var StatusService|\PHPUnit\Framework\MockObject\MockObject */
|
||||
private $service;
|
||||
|
||||
/** @var UserStatusWidget */
|
||||
private $widget;
|
||||
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->l10n = $this->createMock(IL10N::class);
|
||||
$this->initialState = $this->createMock(IInitialStateService::class);
|
||||
$this->userManager = $this->createMock(IUserManager::class);
|
||||
$this->userSession = $this->createMock(IUserSession::class);
|
||||
$this->service = $this->createMock(StatusService::class);
|
||||
|
||||
$this->widget = new UserStatusWidget($this->l10n, $this->initialState, $this->userManager, $this->userSession, $this->service);
|
||||
}
|
||||
|
||||
public function testGetId(): void {
|
||||
$this->assertEquals('user_status', $this->widget->getId());
|
||||
}
|
||||
|
||||
public function testGetTitle(): void {
|
||||
$this->l10n->expects($this->exactly(1))
|
||||
->method('t')
|
||||
->willReturnArgument(0);
|
||||
|
||||
$this->assertEquals('Recent statuses', $this->widget->getTitle());
|
||||
}
|
||||
|
||||
public function testGetOrder(): void {
|
||||
$this->assertEquals(5, $this->widget->getOrder());
|
||||
}
|
||||
|
||||
public function testGetIconClass(): void {
|
||||
$this->assertEquals('icon-user-status', $this->widget->getIconClass());
|
||||
}
|
||||
|
||||
public function testGetUrl(): void {
|
||||
$this->assertNull($this->widget->getUrl());
|
||||
}
|
||||
|
||||
public function testLoadNoUserSession(): void {
|
||||
$this->userSession->expects($this->once())
|
||||
->method('getUser')
|
||||
->willReturn(null);
|
||||
|
||||
$this->initialState->expects($this->once())
|
||||
->method('provideInitialState')
|
||||
->with('user_status', 'dashboard_data', []);
|
||||
|
||||
$this->service->expects($this->never())
|
||||
->method('findAllRecentStatusChanges');
|
||||
|
||||
$this->widget->load();
|
||||
}
|
||||
|
||||
public function testLoadWithCurrentUser(): void {
|
||||
$user = $this->createMock(IUser::class);
|
||||
$user->method('getUid')->willReturn('john.doe');
|
||||
$this->userSession->expects($this->once())
|
||||
->method('getUser')
|
||||
->willReturn($user);
|
||||
|
||||
$user1 = $this->createMock(IUser::class);
|
||||
$user1->method('getDisplayName')->willReturn('User No. 1');
|
||||
|
||||
$this->userManager
|
||||
->method('get')
|
||||
->willReturnMap([
|
||||
['user_1', $user1],
|
||||
['user_2', null],
|
||||
['user_3', null],
|
||||
['user_4', null],
|
||||
['user_5', null],
|
||||
['user_6', null],
|
||||
['user_7', null],
|
||||
]);
|
||||
|
||||
$userStatuses = [
|
||||
UserStatus::fromParams([
|
||||
'userId' => 'user_1',
|
||||
'status' => 'online',
|
||||
'customIcon' => '💻',
|
||||
'customMessage' => 'Working',
|
||||
'statusTimestamp' => 5000,
|
||||
]),
|
||||
UserStatus::fromParams([
|
||||
'userId' => 'user_2',
|
||||
'status' => 'away',
|
||||
'customIcon' => '☕️',
|
||||
'customMessage' => 'Office Hangout',
|
||||
'statusTimestamp' => 6000,
|
||||
]),
|
||||
UserStatus::fromParams([
|
||||
'userId' => 'user_3',
|
||||
'status' => 'dnd',
|
||||
'customIcon' => null,
|
||||
'customMessage' => null,
|
||||
'statusTimestamp' => 7000,
|
||||
]),
|
||||
UserStatus::fromParams([
|
||||
'userId' => 'john.doe',
|
||||
'status' => 'away',
|
||||
'customIcon' => '☕️',
|
||||
'customMessage' => 'Office Hangout',
|
||||
'statusTimestamp' => 90000,
|
||||
]),
|
||||
UserStatus::fromParams([
|
||||
'userId' => 'user_4',
|
||||
'status' => 'dnd',
|
||||
'customIcon' => null,
|
||||
'customMessage' => null,
|
||||
'statusTimestamp' => 7000,
|
||||
]),
|
||||
UserStatus::fromParams([
|
||||
'userId' => 'user_5',
|
||||
'status' => 'invisible',
|
||||
'customIcon' => '🏝',
|
||||
'customMessage' => 'On vacation',
|
||||
'statusTimestamp' => 7000,
|
||||
]),
|
||||
UserStatus::fromParams([
|
||||
'userId' => 'user_6',
|
||||
'status' => 'offline',
|
||||
'customIcon' => null,
|
||||
'customMessage' => null,
|
||||
'statusTimestamp' => 7000,
|
||||
]),
|
||||
UserStatus::fromParams([
|
||||
'userId' => 'user_7',
|
||||
'status' => 'invisible',
|
||||
'customIcon' => null,
|
||||
'customMessage' => null,
|
||||
'statusTimestamp' => 7000,
|
||||
]),
|
||||
];
|
||||
|
||||
$this->service->expects($this->once())
|
||||
->method('findAllRecentStatusChanges')
|
||||
->with(8, 0)
|
||||
->willReturn($userStatuses);
|
||||
|
||||
$this->initialState->expects($this->once())
|
||||
->method('provideInitialState')
|
||||
->with('user_status', 'dashboard_data', $this->callback(function ($data): bool {
|
||||
$this->assertEquals([
|
||||
[
|
||||
'userId' => 'user_1',
|
||||
'displayName' => 'User No. 1',
|
||||
'status' => 'online',
|
||||
'icon' => '💻',
|
||||
'message' => 'Working',
|
||||
'timestamp' => 5000,
|
||||
],
|
||||
[
|
||||
'userId' => 'user_2',
|
||||
'displayName' => 'user_2',
|
||||
'status' => 'away',
|
||||
'icon' => '☕️',
|
||||
'message' => 'Office Hangout',
|
||||
'timestamp' => 6000,
|
||||
],
|
||||
[
|
||||
'userId' => 'user_3',
|
||||
'displayName' => 'user_3',
|
||||
'status' => 'dnd',
|
||||
'icon' => null,
|
||||
'message' => null,
|
||||
'timestamp' => 7000,
|
||||
],
|
||||
[
|
||||
'userId' => 'user_4',
|
||||
'displayName' => 'user_4',
|
||||
'status' => 'dnd',
|
||||
'icon' => null,
|
||||
'message' => null,
|
||||
'timestamp' => 7000,
|
||||
],
|
||||
[
|
||||
'userId' => 'user_5',
|
||||
'displayName' => 'user_5',
|
||||
'status' => 'offline',
|
||||
'icon' => '🏝',
|
||||
'message' => 'On vacation',
|
||||
'timestamp' => 7000,
|
||||
],
|
||||
[
|
||||
'userId' => 'user_6',
|
||||
'displayName' => 'user_6',
|
||||
'status' => 'offline',
|
||||
'icon' => null,
|
||||
'message' => null,
|
||||
'timestamp' => 7000,
|
||||
],
|
||||
[
|
||||
'userId' => 'user_7',
|
||||
'displayName' => 'user_7',
|
||||
'status' => 'offline',
|
||||
'icon' => null,
|
||||
'message' => null,
|
||||
'timestamp' => 7000,
|
||||
],
|
||||
], $data);
|
||||
return true;
|
||||
}));
|
||||
|
||||
$this->widget->load();
|
||||
}
|
||||
}
|
|
@ -65,6 +65,15 @@ class UserStatusMapperTest extends TestCase {
|
|||
$this->assertEquals('user2', $offsetResults[0]->getUserId());
|
||||
}
|
||||
|
||||
public function testFindAllRecent(): void {
|
||||
$this->insertSampleStatuses();
|
||||
|
||||
$allResults = $this->mapper->findAllRecent(2, 0);
|
||||
$this->assertCount(2, $allResults);
|
||||
$this->assertEquals('user1', $allResults[0]->getUserId());
|
||||
$this->assertEquals('user2', $allResults[1]->getUserId());
|
||||
}
|
||||
|
||||
public function testGetFind(): void {
|
||||
$this->insertSampleStatuses();
|
||||
|
||||
|
|
|
@ -84,6 +84,21 @@ class StatusServiceTest extends TestCase {
|
|||
], $this->service->findAll(20, 50));
|
||||
}
|
||||
|
||||
public function testFindAllRecentStatusChanges(): void {
|
||||
$status1 = $this->createMock(UserStatus::class);
|
||||
$status2 = $this->createMock(UserStatus::class);
|
||||
|
||||
$this->mapper->expects($this->once())
|
||||
->method('findAllRecent')
|
||||
->with(20, 50)
|
||||
->willReturn([$status1, $status2]);
|
||||
|
||||
$this->assertEquals([
|
||||
$status1,
|
||||
$status2,
|
||||
], $this->service->findAllRecentStatusChanges(20, 50));
|
||||
}
|
||||
|
||||
public function testFindByUserId(): void {
|
||||
$status = $this->createMock(UserStatus::class);
|
||||
$this->mapper->expects($this->once())
|
||||
|
|
|
@ -2,6 +2,7 @@ const path = require('path')
|
|||
|
||||
module.exports = {
|
||||
entry: {
|
||||
'dashboard': path.join(__dirname, 'src', 'dashboard'),
|
||||
'user-status-menu': path.join(__dirname, 'src', 'main-user-status-menu')
|
||||
},
|
||||
output: {
|
||||
|
|
|
@ -1684,6 +1684,16 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"@nextcloud/vue-dashboard": {
|
||||
"version": "0.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/vue-dashboard/-/vue-dashboard-0.1.3.tgz",
|
||||
"integrity": "sha512-7b02zkarX7b18IRQmZEW1NM+dvtcUih2M0+CZyuQfcvfyMQudOz+BdA/oD1p7PmdBds1IR8OvY1+CnpmgAzfQg==",
|
||||
"requires": {
|
||||
"@nextcloud/vue": "^2.3.0",
|
||||
"core-js": "^3.6.4",
|
||||
"vue": "^2.6.11"
|
||||
}
|
||||
},
|
||||
"@nodelib/fs.scandir": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz",
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
"@nextcloud/paths": "^1.1.2",
|
||||
"@nextcloud/router": "^1.1.0",
|
||||
"@nextcloud/vue": "^2.3.0",
|
||||
"@nextcloud/vue-dashboard": "^0.1.3",
|
||||
"autosize": "^4.0.2",
|
||||
"backbone": "^1.4.0",
|
||||
"blueimp-md5": "^2.16.0",
|
||||
|
|
Loading…
Reference in New Issue