Skip to content

Commit

Permalink
Merge branch 'master' into fix/issue-47879-property-serialization
Browse files Browse the repository at this point in the history
  • Loading branch information
SebastianKrupinski authored Dec 13, 2024
2 parents 6629d60 + 10852d3 commit 6151da2
Show file tree
Hide file tree
Showing 766 changed files with 5,165 additions and 1,787 deletions.
1 change: 1 addition & 0 deletions apps/dashboard/lib/Controller/DashboardController.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ public function index(): TemplateResponse {
$this->initialState->provideInitialState('layout', $this->service->getLayout());
$this->initialState->provideInitialState('appStoreEnabled', $this->config->getSystemValueBool('appstoreenabled', true));
$this->initialState->provideInitialState('firstRun', $this->config->getUserValue($this->userId, 'dashboard', 'firstRun', '1') === '1');
$this->initialState->provideInitialState('birthdate', $this->service->getBirthdate());
$this->config->setUserValue($this->userId, 'dashboard', 'firstRun', '0');

$response = new TemplateResponse('dashboard', 'index', [
Expand Down
26 changes: 26 additions & 0 deletions apps/dashboard/lib/Service/DashboardService.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,17 @@
namespace OCA\Dashboard\Service;

use JsonException;
use OCP\Accounts\IAccountManager;
use OCP\Accounts\PropertyDoesNotExistException;
use OCP\IConfig;
use OCP\IUserManager;

class DashboardService {
public function __construct(
private IConfig $config,
private ?string $userId,
private IUserManager $userManager,
private IAccountManager $accountManager,
) {

}
Expand Down Expand Up @@ -42,4 +47,25 @@ public function getStatuses() {
return array_values(array_filter(explode(',', $configStatuses), fn (string $value) => $value !== ''));
}
}

public function getBirthdate(): string {
if ($this->userId === null) {
return '';
}

$user = $this->userManager->get($this->userId);
if ($user === null) {
return '';
}

$account = $this->accountManager->getAccount($user);

try {
$birthdate = $account->getProperty(IAccountManager::PROPERTY_BIRTHDATE);
} catch (PropertyDoesNotExistException) {
return '';
}

return $birthdate->getValue();
}
}
13 changes: 12 additions & 1 deletion apps/dashboard/src/DashboardApp.vue
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ import ApiDashboardWidget from './components/ApiDashboardWidget.vue'

const panels = loadState('dashboard', 'panels')
const firstRun = loadState('dashboard', 'firstRun')
const birthdate = new Date(loadState('dashboard', 'birthdate'))

const statusInfo = {
weather: {
Expand Down Expand Up @@ -194,15 +195,21 @@ export default {
apiWidgets: [],
apiWidgetItems: {},
loadingItems: true,
birthdate,
}
},
computed: {
greeting() {
const time = this.timer.getHours()
const isBirthday = this.birthdate instanceof Date
&& this.birthdate.getMonth() === this.timer.getMonth()
&& this.birthdate.getDate() === this.timer.getDate()

// Determine part of the day
let partOfDay
if (time >= 22 || time < 5) {
if (isBirthday) {
partOfDay = 'birthday'
} else if (time >= 22 || time < 5) {
partOfDay = 'night'
} else if (time >= 18) {
partOfDay = 'evening'
Expand Down Expand Up @@ -231,6 +238,10 @@ export default {
generic: t('dashboard', 'Hello'),
withName: t('dashboard', 'Hello, {name}', { name: this.displayName }, undefined, { escape: false }),
},
birthday: {
generic: t('dashboard', 'Happy birthday 🥳🤩🎂🎉'),
withName: t('dashboard', 'Happy birthday, {name} 🥳🤩🎂🎉', { name: this.displayName }, undefined, { escape: false }),
},
}

// Figure out which greeting to show
Expand Down
100 changes: 100 additions & 0 deletions apps/dashboard/tests/DashboardServiceTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
<?php

declare(strict_types=1);

/**
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\Dashboard\Tests;

use OC\Accounts\Account;
use OCA\Dashboard\Service\DashboardService;
use OCP\Accounts\IAccountManager;
use OCP\IConfig;
use OCP\IUser;
use OCP\IUserManager;
use PHPUnit\Framework\MockObject\MockObject;
use Test\TestCase;

class DashboardServiceTest extends TestCase {

private IConfig&MockObject $config;
private IUserManager&MockObject $userManager;
private IAccountManager&MockObject $accountManager;
private DashboardService $service;

protected function setUp(): void {
parent::setUp();

$this->config = $this->createMock(IConfig::class);
$this->userManager = $this->createMock(IUserManager::class);
$this->accountManager = $this->createMock(IAccountManager::class);

$this->service = new DashboardService(
$this->config,
'alice',
$this->userManager,
$this->accountManager,
);
}

public function testGetBirthdate() {
$user = $this->createMock(IUser::class);
$this->userManager->method('get')
->willReturn($user);

$account = new Account($user);
$account->setProperty(
IAccountManager::PROPERTY_BIRTHDATE,
'2024-12-10T00:00:00.000Z',
IAccountManager::SCOPE_LOCAL,
IAccountManager::VERIFIED,
);

$this->accountManager->method('getAccount')
->willReturn($account);

$birthdate = $this->service->getBirthdate();

$this->assertEquals('2024-12-10T00:00:00.000Z', $birthdate);
}

public function testGetBirthdatePropertyDoesNotExist() {
$user = $this->createMock(IUser::class);
$this->userManager->method('get')
->willReturn($user);

$account = new Account($user);
$this->accountManager->method('getAccount')
->willReturn($account);

$birthdate = $this->service->getBirthdate();

$this->assertEquals('', $birthdate);
}

public function testGetBirthdateUserNotFound() {
$this->userManager->method('get')
->willReturn(null);

$birthdate = $this->service->getBirthdate();

$this->assertEquals('', $birthdate);
}

public function testGetBirthdateNoUserId() {
$service = new DashboardService(
$this->config,
null,
$this->userManager,
$this->accountManager,
);

$birthdate = $service->getBirthdate();

$this->assertEquals('', $birthdate);
}

}
1 change: 1 addition & 0 deletions apps/dav/composer/composer/autoload_classmap.php
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@
'OCA\\DAV\\CalDAV\\Sharing\\Backend' => $baseDir . '/../lib/CalDAV/Sharing/Backend.php',
'OCA\\DAV\\CalDAV\\Sharing\\Service' => $baseDir . '/../lib/CalDAV/Sharing/Service.php',
'OCA\\DAV\\CalDAV\\Status\\StatusService' => $baseDir . '/../lib/CalDAV/Status/StatusService.php',
'OCA\\DAV\\CalDAV\\TimeZoneFactory' => $baseDir . '/../lib/CalDAV/TimeZoneFactory.php',
'OCA\\DAV\\CalDAV\\TimezoneService' => $baseDir . '/../lib/CalDAV/TimezoneService.php',
'OCA\\DAV\\CalDAV\\TipBroker' => $baseDir . '/../lib/CalDAV/TipBroker.php',
'OCA\\DAV\\CalDAV\\Trashbin\\DeletedCalendarObject' => $baseDir . '/../lib/CalDAV/Trashbin/DeletedCalendarObject.php',
Expand Down
1 change: 1 addition & 0 deletions apps/dav/composer/composer/autoload_static.php
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ class ComposerStaticInitDAV
'OCA\\DAV\\CalDAV\\Sharing\\Backend' => __DIR__ . '/..' . '/../lib/CalDAV/Sharing/Backend.php',
'OCA\\DAV\\CalDAV\\Sharing\\Service' => __DIR__ . '/..' . '/../lib/CalDAV/Sharing/Service.php',
'OCA\\DAV\\CalDAV\\Status\\StatusService' => __DIR__ . '/..' . '/../lib/CalDAV/Status/StatusService.php',
'OCA\\DAV\\CalDAV\\TimeZoneFactory' => __DIR__ . '/..' . '/../lib/CalDAV/TimeZoneFactory.php',
'OCA\\DAV\\CalDAV\\TimezoneService' => __DIR__ . '/..' . '/../lib/CalDAV/TimezoneService.php',
'OCA\\DAV\\CalDAV\\TipBroker' => __DIR__ . '/..' . '/../lib/CalDAV/TipBroker.php',
'OCA\\DAV\\CalDAV\\Trashbin\\DeletedCalendarObject' => __DIR__ . '/..' . '/../lib/CalDAV/Trashbin/DeletedCalendarObject.php',
Expand Down
2 changes: 2 additions & 0 deletions apps/dav/l10n/ar.js
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,8 @@ OC.L10N.register(
"Could not rename part file to final file, canceled by hook" : "تعذّرت إعادة تسمية ملف جزئي إلى ملف نهائي. تمّ الإلغاء من قِبَل الخطّاف hook.",
"Could not rename part file to final file" : "تعذّرت إعادة تسمية ملف جزئي إلى ملف نهائي",
"Failed to check file size: %1$s" : "فشل في تحديد حجم الملف: %1$s",
"Could not open file: %1$s, file does seem to exist" : "يتعذّر فتح الملف: %1$s, يبدو أن الملف غير موجود",
"Could not open file: %1$s, file doesn't seem to exist" : "يتعذّر فتح الملف: %1$s, يبدو أن الملف غير موجود",
"Encryption not ready: %1$s" : "التشفير غير جاهز: %1$s",
"Failed to open file: %1$s" : "تعذّر فتح الملف: %1$s",
"Failed to unlink: %1$s" : "تعذّر فك الارتباط: %1$s",
Expand Down
2 changes: 2 additions & 0 deletions apps/dav/l10n/ar.json
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,8 @@
"Could not rename part file to final file, canceled by hook" : "تعذّرت إعادة تسمية ملف جزئي إلى ملف نهائي. تمّ الإلغاء من قِبَل الخطّاف hook.",
"Could not rename part file to final file" : "تعذّرت إعادة تسمية ملف جزئي إلى ملف نهائي",
"Failed to check file size: %1$s" : "فشل في تحديد حجم الملف: %1$s",
"Could not open file: %1$s, file does seem to exist" : "يتعذّر فتح الملف: %1$s, يبدو أن الملف غير موجود",
"Could not open file: %1$s, file doesn't seem to exist" : "يتعذّر فتح الملف: %1$s, يبدو أن الملف غير موجود",
"Encryption not ready: %1$s" : "التشفير غير جاهز: %1$s",
"Failed to open file: %1$s" : "تعذّر فتح الملف: %1$s",
"Failed to unlink: %1$s" : "تعذّر فك الارتباط: %1$s",
Expand Down
2 changes: 2 additions & 0 deletions apps/dav/l10n/de.js
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,8 @@ OC.L10N.register(
"Could not rename part file to final file, canceled by hook" : "Konnte temporäre Datei nicht in die endgültige Datei umbenennen, wurde durch einen Hook abgebrochen",
"Could not rename part file to final file" : "Konnte temporäre Datei nicht in die endgültige Datei umbenennen",
"Failed to check file size: %1$s" : "Dateigröße konnte nicht überprüft werden: %1$s",
"Could not open file: %1$s, file does seem to exist" : "Datei konnte nicht geöffnet werden: %1$s, Datei scheint aber zu existieren.",
"Could not open file: %1$s, file doesn't seem to exist" : "Datei konnte nicht geöffnet werden: %1$s, Datei scheint nicht zu existieren.",
"Encryption not ready: %1$s" : "Verschlüsselung nicht bereit: %1$s",
"Failed to open file: %1$s" : "Datei konnte nicht geöffnet werden: %1$s",
"Failed to unlink: %1$s" : "Fehler beim Aufheben der Verknüpfung: %1$s",
Expand Down
2 changes: 2 additions & 0 deletions apps/dav/l10n/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,8 @@
"Could not rename part file to final file, canceled by hook" : "Konnte temporäre Datei nicht in die endgültige Datei umbenennen, wurde durch einen Hook abgebrochen",
"Could not rename part file to final file" : "Konnte temporäre Datei nicht in die endgültige Datei umbenennen",
"Failed to check file size: %1$s" : "Dateigröße konnte nicht überprüft werden: %1$s",
"Could not open file: %1$s, file does seem to exist" : "Datei konnte nicht geöffnet werden: %1$s, Datei scheint aber zu existieren.",
"Could not open file: %1$s, file doesn't seem to exist" : "Datei konnte nicht geöffnet werden: %1$s, Datei scheint nicht zu existieren.",
"Encryption not ready: %1$s" : "Verschlüsselung nicht bereit: %1$s",
"Failed to open file: %1$s" : "Datei konnte nicht geöffnet werden: %1$s",
"Failed to unlink: %1$s" : "Fehler beim Aufheben der Verknüpfung: %1$s",
Expand Down
2 changes: 2 additions & 0 deletions apps/dav/l10n/en_GB.js
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,8 @@ OC.L10N.register(
"Could not rename part file to final file, canceled by hook" : "Could not rename part file to final file, cancelled by hook",
"Could not rename part file to final file" : "Could not rename part file to final file",
"Failed to check file size: %1$s" : "Failed to check file size: %1$s",
"Could not open file: %1$s, file does seem to exist" : "Could not open file: %1$s, file does seem to exist",
"Could not open file: %1$s, file doesn't seem to exist" : "Could not open file: %1$s, file doesn't seem to exist",
"Encryption not ready: %1$s" : "Encryption not ready: %1$s",
"Failed to open file: %1$s" : "Failed to open file: %1$s",
"Failed to unlink: %1$s" : "Failed to unlink: %1$s",
Expand Down
2 changes: 2 additions & 0 deletions apps/dav/l10n/en_GB.json
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,8 @@
"Could not rename part file to final file, canceled by hook" : "Could not rename part file to final file, cancelled by hook",
"Could not rename part file to final file" : "Could not rename part file to final file",
"Failed to check file size: %1$s" : "Failed to check file size: %1$s",
"Could not open file: %1$s, file does seem to exist" : "Could not open file: %1$s, file does seem to exist",
"Could not open file: %1$s, file doesn't seem to exist" : "Could not open file: %1$s, file doesn't seem to exist",
"Encryption not ready: %1$s" : "Encryption not ready: %1$s",
"Failed to open file: %1$s" : "Failed to open file: %1$s",
"Failed to unlink: %1$s" : "Failed to unlink: %1$s",
Expand Down
2 changes: 2 additions & 0 deletions apps/dav/l10n/fr.js
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,8 @@ OC.L10N.register(
"Could not rename part file to final file, canceled by hook" : "Impossible de renommer le fichier partiel en fichier final, annulé par le hook",
"Could not rename part file to final file" : "Impossible de renommer le fichier partiel en fichier définitif.",
"Failed to check file size: %1$s" : "Échec à la vérification de la taille du fichier : %1$s",
"Could not open file: %1$s, file does seem to exist" : "Impossible d'ouvrir le fichier %1$s, le fichier semble présent.",
"Could not open file: %1$s, file doesn't seem to exist" : "Impossible d'ouvrir le fichier %1$s, le fichier ne semble pas présent.",
"Encryption not ready: %1$s" : "Encryption pas prête : %1$s",
"Failed to open file: %1$s" : "Échec à l'ouverture du fichier : %1$s",
"Failed to unlink: %1$s" : "Échec à la suppression :%1$s",
Expand Down
2 changes: 2 additions & 0 deletions apps/dav/l10n/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,8 @@
"Could not rename part file to final file, canceled by hook" : "Impossible de renommer le fichier partiel en fichier final, annulé par le hook",
"Could not rename part file to final file" : "Impossible de renommer le fichier partiel en fichier définitif.",
"Failed to check file size: %1$s" : "Échec à la vérification de la taille du fichier : %1$s",
"Could not open file: %1$s, file does seem to exist" : "Impossible d'ouvrir le fichier %1$s, le fichier semble présent.",
"Could not open file: %1$s, file doesn't seem to exist" : "Impossible d'ouvrir le fichier %1$s, le fichier ne semble pas présent.",
"Encryption not ready: %1$s" : "Encryption pas prête : %1$s",
"Failed to open file: %1$s" : "Échec à l'ouverture du fichier : %1$s",
"Failed to unlink: %1$s" : "Échec à la suppression :%1$s",
Expand Down
2 changes: 2 additions & 0 deletions apps/dav/l10n/gl.js
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,8 @@ OC.L10N.register(
"Could not rename part file to final file, canceled by hook" : "Non foi posíbel cambiar o nome do ficheiro parcial ao ficheiro final, foi cancelado polo sistema",
"Could not rename part file to final file" : "Non foi posíbel cambiar o nome do ficheiro parcial ao ficheiro final",
"Failed to check file size: %1$s" : "Produciuse un erro ao comprobar o tamaño do ficheiro: %1$s",
"Could not open file: %1$s, file does seem to exist" : "Non foi posíbel abrir o ficheiro: %1$s, semella o ficheiro existe",
"Could not open file: %1$s, file doesn't seem to exist" : "Non foi posíbel abrir o ficheiro: %1$s, semella o ficheiro non existe",
"Encryption not ready: %1$s" : "O cifrado non está preparado: %1$s",
"Failed to open file: %1$s" : "Produciuse un erro ao abrir o ficheiro: %1$s",
"Failed to unlink: %1$s" : "Produciuse un erro ao desligar: %1$s",
Expand Down
2 changes: 2 additions & 0 deletions apps/dav/l10n/gl.json
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,8 @@
"Could not rename part file to final file, canceled by hook" : "Non foi posíbel cambiar o nome do ficheiro parcial ao ficheiro final, foi cancelado polo sistema",
"Could not rename part file to final file" : "Non foi posíbel cambiar o nome do ficheiro parcial ao ficheiro final",
"Failed to check file size: %1$s" : "Produciuse un erro ao comprobar o tamaño do ficheiro: %1$s",
"Could not open file: %1$s, file does seem to exist" : "Non foi posíbel abrir o ficheiro: %1$s, semella o ficheiro existe",
"Could not open file: %1$s, file doesn't seem to exist" : "Non foi posíbel abrir o ficheiro: %1$s, semella o ficheiro non existe",
"Encryption not ready: %1$s" : "O cifrado non está preparado: %1$s",
"Failed to open file: %1$s" : "Produciuse un erro ao abrir o ficheiro: %1$s",
"Failed to unlink: %1$s" : "Produciuse un erro ao desligar: %1$s",
Expand Down
2 changes: 1 addition & 1 deletion apps/dav/l10n/hu.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ OC.L10N.register(
"Where: %s" : "Hely: %s",
"%1$s via %2$s" : "%1$s – %2$s",
"In %1$s %2$s on %3$s for the entire day" : "%1$s-en %2$s %3$s-kor az teljes napra",
"In %1$s %2$s on %3$s between %4$s - %5$s" : "%1$s-en %2$s %3$s-kor %4$s - %5$sközött",
"In %1$s %2$s on %3$s between %4$s - %5$s" : "%1$s %2$s múlva, %3$s napon %4$s - %5$s",
"Could not generate when statement" : "Nem sikerlt létrehozni a mikor állítást",
"Every Day for the entire day" : "Minden Nap a teljes napra",
"Every Day for the entire day until %1$s" : "Minden Nap a teljes napon eddig %1$s",
Expand Down
2 changes: 1 addition & 1 deletion apps/dav/l10n/hu.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@
"Where: %s" : "Hely: %s",
"%1$s via %2$s" : "%1$s – %2$s",
"In %1$s %2$s on %3$s for the entire day" : "%1$s-en %2$s %3$s-kor az teljes napra",
"In %1$s %2$s on %3$s between %4$s - %5$s" : "%1$s-en %2$s %3$s-kor %4$s - %5$sközött",
"In %1$s %2$s on %3$s between %4$s - %5$s" : "%1$s %2$s múlva, %3$s napon %4$s - %5$s",
"Could not generate when statement" : "Nem sikerlt létrehozni a mikor állítást",
"Every Day for the entire day" : "Minden Nap a teljes napra",
"Every Day for the entire day until %1$s" : "Minden Nap a teljes napon eddig %1$s",
Expand Down
2 changes: 2 additions & 0 deletions apps/dav/l10n/ja.js
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,8 @@ OC.L10N.register(
"Could not rename part file to final file, canceled by hook" : "最終ファイルの名前の変更が出来なかったため、フックによりキャンセルされました",
"Could not rename part file to final file" : "最終ファイルの名前の変更が出来ませんでした",
"Failed to check file size: %1$s" : "ファイルサイズの確認に失敗: %1$s",
"Could not open file: %1$s, file does seem to exist" : "ファイルを開けませんでした: %1$s、ファイルは存在するようです",
"Could not open file: %1$s, file doesn't seem to exist" : "ファイルを開けませんでした: %1$s ファイルが存在しないようです。",
"Encryption not ready: %1$s" : "暗号化の準備が出来ていません: %1$s",
"Failed to open file: %1$s" : "ファイルを開くのに失敗: %1$s",
"Failed to unlink: %1$s" : "リンクの解除に失敗: %1$s",
Expand Down
2 changes: 2 additions & 0 deletions apps/dav/l10n/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,8 @@
"Could not rename part file to final file, canceled by hook" : "最終ファイルの名前の変更が出来なかったため、フックによりキャンセルされました",
"Could not rename part file to final file" : "最終ファイルの名前の変更が出来ませんでした",
"Failed to check file size: %1$s" : "ファイルサイズの確認に失敗: %1$s",
"Could not open file: %1$s, file does seem to exist" : "ファイルを開けませんでした: %1$s、ファイルは存在するようです",
"Could not open file: %1$s, file doesn't seem to exist" : "ファイルを開けませんでした: %1$s ファイルが存在しないようです。",
"Encryption not ready: %1$s" : "暗号化の準備が出来ていません: %1$s",
"Failed to open file: %1$s" : "ファイルを開くのに失敗: %1$s",
"Failed to unlink: %1$s" : "リンクの解除に失敗: %1$s",
Expand Down
1 change: 1 addition & 0 deletions apps/dav/l10n/nl.js
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ OC.L10N.register(
"Delete slot" : "Verwijder slot",
"No working hours set" : "Geen werkuren ingesteld",
"Add slot" : "Voeg slot toe",
"Weekdays" : "Weekdagen",
"Automatically set user status to \"Do not disturb\" outside of availability to mute all notifications." : "Stel de gebruikersstatus automatisch in op \"Niet storen\" buiten de beschikbaarheid om alle meldingen te dempen.",
"Failed to load availability" : "Kon beschikbaarheid niet laden",
"Availability" : "Beschikbaarheid",
Expand Down
1 change: 1 addition & 0 deletions apps/dav/l10n/nl.json
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@
"Delete slot" : "Verwijder slot",
"No working hours set" : "Geen werkuren ingesteld",
"Add slot" : "Voeg slot toe",
"Weekdays" : "Weekdagen",
"Automatically set user status to \"Do not disturb\" outside of availability to mute all notifications." : "Stel de gebruikersstatus automatisch in op \"Niet storen\" buiten de beschikbaarheid om alle meldingen te dempen.",
"Failed to load availability" : "Kon beschikbaarheid niet laden",
"Availability" : "Beschikbaarheid",
Expand Down
Loading

0 comments on commit 6151da2

Please sign in to comment.