Merge branch 'redesign-profile-page' into develop
This commit is contained in:
commit
db9a10b1cb
18 changed files with 2477 additions and 96 deletions
|
@ -6,7 +6,7 @@
|
|||
* @author Jay Trees <github.jay@grandel.anonaddy.me>
|
||||
*/
|
||||
|
||||
define('VERSION', '0.4.0');
|
||||
define('VERSION', '0.5.0');
|
||||
define('ROOT', __DIR__);
|
||||
define('DEFAULT_LOCALE', 'en_GB');
|
||||
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
"popup",
|
||||
"message",
|
||||
"list",
|
||||
"tab",
|
||||
|
||||
"api",
|
||||
"transition"
|
||||
|
|
5
semantic/dist/components/menu.css
vendored
5
semantic/dist/components/menu.css
vendored
|
@ -1969,6 +1969,11 @@ Floated Menu / Item
|
|||
border-top: 1px solid #D4D4D5;
|
||||
border-right: 1px solid #D4D4D5;
|
||||
}
|
||||
@media only screen and (max-width: 767.98px) {
|
||||
.stackable .ui.vertical.pointing.menu .item::after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.ui.pointing.menu .ui.dropdown .menu .item:after,
|
||||
.ui.vertical.pointing.menu .ui.dropdown .menu .item:after {
|
||||
display: none;
|
||||
|
|
2
semantic/dist/components/menu.min.css
vendored
2
semantic/dist/components/menu.min.css
vendored
File diff suppressed because one or more lines are too long
88
semantic/dist/components/tab.css
vendored
Normal file
88
semantic/dist/components/tab.css
vendored
Normal file
|
@ -0,0 +1,88 @@
|
|||
/*!
|
||||
* # Fomantic-UI 2.8.8 - Tab
|
||||
* http://github.com/fomantic/Fomantic-UI/
|
||||
*
|
||||
*
|
||||
* Released under the MIT license
|
||||
* http://opensource.org/licenses/MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/*******************************
|
||||
UI Tabs
|
||||
*******************************/
|
||||
|
||||
.ui.tab {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
/*******************************
|
||||
States
|
||||
*******************************/
|
||||
|
||||
|
||||
/*--------------------
|
||||
Active
|
||||
---------------------*/
|
||||
|
||||
.ui.tab.active,
|
||||
.ui.tab.open {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/*--------------------
|
||||
Loading
|
||||
---------------------*/
|
||||
|
||||
.ui.tab.loading {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
display: block;
|
||||
min-height: 250px;
|
||||
}
|
||||
.ui.tab.loading * {
|
||||
position: relative !important;
|
||||
left: -10000px !important;
|
||||
}
|
||||
.ui.tab.loading:before,
|
||||
.ui.tab.loading.segment:before {
|
||||
position: absolute;
|
||||
content: '';
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
margin: -1.25em 0 0 -1.25em;
|
||||
width: 2.5em;
|
||||
height: 2.5em;
|
||||
border-radius: 500rem;
|
||||
border: 0.2em solid rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
.ui.tab.loading:after,
|
||||
.ui.tab.loading.segment:after {
|
||||
position: absolute;
|
||||
content: '';
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
margin: -1.25em 0 0 -1.25em;
|
||||
width: 2.5em;
|
||||
height: 2.5em;
|
||||
-webkit-animation: loader 0.6s infinite linear;
|
||||
animation: loader 0.6s infinite linear;
|
||||
border: 0.2em solid #767676;
|
||||
border-radius: 500rem;
|
||||
-webkit-box-shadow: 0 0 0 1px transparent;
|
||||
box-shadow: 0 0 0 1px transparent;
|
||||
}
|
||||
|
||||
|
||||
/*******************************
|
||||
Tab Overrides
|
||||
*******************************/
|
||||
|
||||
|
||||
|
||||
/*******************************
|
||||
User Overrides
|
||||
*******************************/
|
||||
|
1001
semantic/dist/components/tab.js
vendored
Normal file
1001
semantic/dist/components/tab.js
vendored
Normal file
File diff suppressed because it is too large
Load diff
9
semantic/dist/components/tab.min.css
vendored
Normal file
9
semantic/dist/components/tab.min.css
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
/*!
|
||||
* # Fomantic-UI 2.8.8 - Tab
|
||||
* http://github.com/fomantic/Fomantic-UI/
|
||||
*
|
||||
*
|
||||
* Released under the MIT license
|
||||
* http://opensource.org/licenses/MIT
|
||||
*
|
||||
*/.ui.tab{display:none}.ui.tab.active,.ui.tab.open{display:block}.ui.tab.loading{position:relative;overflow:hidden;display:block;min-height:250px}.ui.tab.loading *{position:relative!important;left:-10000px!important}.ui.tab.loading.segment:before,.ui.tab.loading:before{position:absolute;content:'';top:50%;left:50%;margin:-1.25em 0 0 -1.25em;width:2.5em;height:2.5em;border-radius:500rem;border:.2em solid rgba(0,0,0,.1)}.ui.tab.loading.segment:after,.ui.tab.loading:after{position:absolute;content:'';top:50%;left:50%;margin:-1.25em 0 0 -1.25em;width:2.5em;height:2.5em;-webkit-animation:loader .6s infinite linear;animation:loader .6s infinite linear;border:.2em solid #767676;border-radius:500rem;-webkit-box-shadow:0 0 0 1px transparent;box-shadow:0 0 0 1px transparent}
|
11
semantic/dist/components/tab.min.js
vendored
Normal file
11
semantic/dist/components/tab.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
90
semantic/dist/semantic.css
vendored
90
semantic/dist/semantic.css
vendored
|
@ -38184,6 +38184,12 @@ Floated Menu / Item
|
|||
border-right: 1px solid #D4D4D5;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 767.98px) {
|
||||
.stackable .ui.vertical.pointing.menu .item::after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.ui.pointing.menu .ui.dropdown .menu .item:after,
|
||||
.ui.vertical.pointing.menu .ui.dropdown .menu .item:after {
|
||||
display: none;
|
||||
|
@ -40404,6 +40410,90 @@ Floated Menu / Item
|
|||
/*******************************
|
||||
Site Overrides
|
||||
*******************************/
|
||||
/*!
|
||||
* # Fomantic-UI 2.8.8 - Tab
|
||||
* http://github.com/fomantic/Fomantic-UI/
|
||||
*
|
||||
*
|
||||
* Released under the MIT license
|
||||
* http://opensource.org/licenses/MIT
|
||||
*
|
||||
*/
|
||||
|
||||
/*******************************
|
||||
UI Tabs
|
||||
*******************************/
|
||||
|
||||
.ui.tab {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/*******************************
|
||||
States
|
||||
*******************************/
|
||||
|
||||
/*--------------------
|
||||
Active
|
||||
---------------------*/
|
||||
|
||||
.ui.tab.active,
|
||||
.ui.tab.open {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/*--------------------
|
||||
Loading
|
||||
---------------------*/
|
||||
|
||||
.ui.tab.loading {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
display: block;
|
||||
min-height: 250px;
|
||||
}
|
||||
|
||||
.ui.tab.loading * {
|
||||
position: relative !important;
|
||||
left: -10000px !important;
|
||||
}
|
||||
|
||||
.ui.tab.loading:before,
|
||||
.ui.tab.loading.segment:before {
|
||||
position: absolute;
|
||||
content: '';
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
margin: -1.25em 0 0 -1.25em;
|
||||
width: 2.5em;
|
||||
height: 2.5em;
|
||||
border-radius: 500rem;
|
||||
border: 0.2em solid rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.ui.tab.loading:after,
|
||||
.ui.tab.loading.segment:after {
|
||||
position: absolute;
|
||||
content: '';
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
margin: -1.25em 0 0 -1.25em;
|
||||
width: 2.5em;
|
||||
height: 2.5em;
|
||||
-webkit-animation: loader 0.6s infinite linear;
|
||||
animation: loader 0.6s infinite linear;
|
||||
border: 0.2em solid #767676;
|
||||
border-radius: 500rem;
|
||||
-webkit-box-shadow: 0 0 0 1px transparent;
|
||||
box-shadow: 0 0 0 1px transparent;
|
||||
}
|
||||
|
||||
/*******************************
|
||||
Tab Overrides
|
||||
*******************************/
|
||||
|
||||
/*******************************
|
||||
User Overrides
|
||||
*******************************/
|
||||
/*!
|
||||
* # Fomantic-UI 2.8.8 - Transition
|
||||
* http://github.com/fomantic/Fomantic-UI/
|
||||
|
|
1002
semantic/dist/semantic.js
vendored
1002
semantic/dist/semantic.js
vendored
File diff suppressed because it is too large
Load diff
2
semantic/dist/semantic.min.css
vendored
2
semantic/dist/semantic.min.css
vendored
File diff suppressed because one or more lines are too long
2
semantic/dist/semantic.min.js
vendored
2
semantic/dist/semantic.min.js
vendored
File diff suppressed because one or more lines are too long
|
@ -1757,6 +1757,11 @@ each(@colors, {
|
|||
border-top: @arrowBorder;
|
||||
border-right: @arrowBorder;
|
||||
}
|
||||
@media only screen and (max-width: @largestMobileScreen) {
|
||||
.stackable .ui.vertical.pointing.menu .item::after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
.ui.pointing.menu .ui.dropdown .menu .item:after,
|
||||
.ui.vertical.pointing.menu .ui.dropdown .menu .item:after {
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
$(function() {
|
||||
$('.menu.profile .item').tab();
|
||||
|
||||
$('.ui.calendar').calendar({
|
||||
type : 'date',
|
||||
firstDayOfWeek : 1,
|
||||
|
|
|
@ -133,7 +133,10 @@ switch ($step) {
|
|||
`last_login` DATETIME NOT NULL DEFAULT NOW(),
|
||||
`power` INT NOT NULL DEFAULT 0,
|
||||
`birthdate` DATE NULL DEFAULT NULL,
|
||||
`locale` VARCHAR(5) NOT NULL DEFAULT "' . DEFAULT_LOCALE . '"
|
||||
`locale` VARCHAR(5) NOT NULL DEFAULT "' . DEFAULT_LOCALE . '",
|
||||
`name_first` VARCHAR(32) NULL DEFAULT NULL,
|
||||
`name_last` VARCHAR(32) NULL DEFAULT NULL,
|
||||
`name_nick` VARCHAR(32) NULL DEFAULT NULL
|
||||
);');
|
||||
$database->query('CREATE INDEX `idx_password` ON `users` (`password`);');
|
||||
|
||||
|
|
|
@ -8,49 +8,96 @@
|
|||
|
||||
use wishthis\{Page, User};
|
||||
|
||||
if (isset($_POST['user-id'])) {
|
||||
$set = array();
|
||||
$page = new Page(__FILE__, __('Profile'));
|
||||
|
||||
if (isset($_POST['user-id'], $_POST['section'])) {
|
||||
$set = array();
|
||||
$formFieldsString = array(
|
||||
array(
|
||||
'column' => 'name_first',
|
||||
'key' => 'user-name-first',
|
||||
'label' => __('First name'),
|
||||
),
|
||||
array(
|
||||
'column' => 'name_last',
|
||||
'key' => 'user-name-last',
|
||||
'label' => __('Last name'),
|
||||
),
|
||||
array(
|
||||
'column' => 'name_nick',
|
||||
'key' => 'user-name-nick',
|
||||
'label' => __('Nickname'),
|
||||
),
|
||||
array(
|
||||
'column' => 'email',
|
||||
'key' => 'user-email',
|
||||
'label' => __('Email'),
|
||||
),
|
||||
array(
|
||||
'column' => 'locale',
|
||||
'key' => 'user-locale',
|
||||
'label' => __('Language'),
|
||||
),
|
||||
);
|
||||
$loginRequired = false;
|
||||
|
||||
if (!empty($_POST['user-email'])) {
|
||||
$set[] = '`email` = "' . $_POST['user-email'] . '"';
|
||||
foreach ($formFieldsString as $field) {
|
||||
if (!empty($_POST[$field['key']]) && $_POST[$field['key']] !== $user->{$field['column']}) {
|
||||
$set[] = '`' . $field['column'] . '` = "' . $_POST[$field['key']] . '"';
|
||||
|
||||
$user->{$field['column']} = $_POST[$field['key']];
|
||||
|
||||
$page->messages[] = Page::success(
|
||||
sprintf(
|
||||
__('%s successfully updated!'),
|
||||
'<strong>' . $field['label'] . '</strong>'
|
||||
),
|
||||
__('Success')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($_POST['user-password']) && !empty($_POST['user-password-repeat'])) {
|
||||
$set[] = '`password` = "' . User::generatePassword($_POST['user-password']) . '"';
|
||||
if (!empty($_POST['user-email']) && $_POST['user-email'] !== $user->email) {
|
||||
$loginRequired = true;
|
||||
}
|
||||
|
||||
if ($_POST['user-birthdate']) {
|
||||
$user->birthdate = date('Y-m-d', strtotime($_POST['user-birthdate']));
|
||||
|
||||
$set[] = '`birthdate` = "' . $user->birthdate . '"';
|
||||
} else {
|
||||
if (isset($_POST['user-birthdate'])) {
|
||||
if (empty($_POST['user-birthdate'])) {
|
||||
$user->birthdate = null;
|
||||
|
||||
$set[] = '`birthdate` = NULL';
|
||||
} else {
|
||||
$user->birthdate = date('Y-m-d', strtotime($_POST['user-birthdate']));
|
||||
|
||||
$set[] = '`birthdate` = "' . $user->birthdate . '"';
|
||||
}
|
||||
}
|
||||
|
||||
$set[] = '`locale` = "' . $_POST['user-locale'] . '"';
|
||||
if (
|
||||
!empty($_POST['user-password'])
|
||||
&& !empty($_POST['user-password-repeat'])
|
||||
&& $_POST['user-password'] === $_POST['user-password-repeat']
|
||||
) {
|
||||
$set[] = '`password` = "' . User::generatePassword($_POST['user-password']) . '"';
|
||||
|
||||
$loginRequired = true;
|
||||
}
|
||||
|
||||
$database
|
||||
->query('UPDATE `users`
|
||||
SET ' . implode(',', $set) . '
|
||||
WHERE `id` = ' . $_POST['user-id']);
|
||||
|
||||
|
||||
if ($_POST['user-email'] !== $_SESSION['user']['email']) {
|
||||
$loginRequired = true;
|
||||
}
|
||||
|
||||
if ($loginRequired) {
|
||||
session_destroy();
|
||||
|
||||
$page->messages[] = Page::warning(
|
||||
__('It is required for you to login again.'),
|
||||
__('Success')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
redirect('/?page=profile');
|
||||
}
|
||||
|
||||
$page = new Page(__FILE__, __('Profile'));
|
||||
$page->header();
|
||||
$page->bodyStart();
|
||||
$page->navigation();
|
||||
|
@ -60,16 +107,96 @@ $page->navigation();
|
|||
<div class="ui container">
|
||||
<h1 class="ui header"><?= $page->title ?></h1>
|
||||
|
||||
<?= $page->messages() ?>
|
||||
|
||||
<div class="ui stackable grid">
|
||||
<div class="four wide column">
|
||||
<div class="ui vertical pointing fluid menu profile">
|
||||
<div class="item" data-tab="personal">
|
||||
<h4 class="ui header"><?= __('Personal') ?></h4>
|
||||
<p><?= __('Information regarding yourself') ?></p>
|
||||
</div>
|
||||
<div class="item" data-tab="password">
|
||||
<h4 class="ui header"><?= __('Password') ?></h4>
|
||||
<p><?= __('Change your password') ?></p>
|
||||
</div>
|
||||
<div class="item" data-tab="preferences">
|
||||
<h4 class="ui header"><?= __('Preferences') ?></h4>
|
||||
<p><?= __('Improve your withthis experience') ?></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="twelve wide stretched column">
|
||||
<div class="ui tab" data-tab="personal">
|
||||
<div class="ui segment">
|
||||
|
||||
<form class="ui form" method="POST">
|
||||
<input type="hidden" name="user-id" value="<?= $user->id ?>" />
|
||||
<input type="hidden" name="section" value="personal" />
|
||||
|
||||
<div class="three fields">
|
||||
<div class="field">
|
||||
<label><?= __('First name') ?></label>
|
||||
|
||||
<input type="text" name="user-name-first" value="<?= $user->name_first ?>" />
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label><?= __('Last name') ?></label>
|
||||
|
||||
<input type="text" name="user-name-last" value="<?= $user->name_last ?>" />
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label><?= __('Nickname') ?></label>
|
||||
|
||||
<input type="text" name="user-name-nick" value="<?= $user->name_nick ?>" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="two fields">
|
||||
<div class="field">
|
||||
<label><?= __('Email') ?></label>
|
||||
|
||||
<input type="email" name="user-email" value="<?= $user->email ?>" />
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label><?= __('Birthdate') ?></label>
|
||||
|
||||
<div class="ui calendar">
|
||||
<div class="ui input left icon">
|
||||
<i class="calendar icon"></i>
|
||||
<input type="text"
|
||||
name="user-birthdate"
|
||||
placeholder="<?= __('Pick a date') ?>"
|
||||
value="<?= $user->birthdate ?>"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ui error message"></div>
|
||||
|
||||
<input class="ui primary button"
|
||||
type="submit"
|
||||
value="<?= __('Save') ?>"
|
||||
title="<?= __('Save') ?>"
|
||||
/>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ui tab" data-tab="password">
|
||||
<div class="ui segment">
|
||||
|
||||
<form class="ui form" method="POST">
|
||||
<input type="hidden" name="user-id" value="<?= $user->id ?>" />
|
||||
<input type="hidden" name="section" value="password" />
|
||||
|
||||
<div class="two fields">
|
||||
<div class="field">
|
||||
<label><?= __('Password') ?></label>
|
||||
|
@ -84,22 +211,26 @@ $page->navigation();
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="two fields">
|
||||
<div class="field">
|
||||
<label><?= __('Birthdate') ?></label>
|
||||
<div class="ui error message"></div>
|
||||
|
||||
<div class="ui calendar">
|
||||
<div class="ui input left icon">
|
||||
<i class="calendar icon"></i>
|
||||
<input type="text"
|
||||
name="user-birthdate"
|
||||
placeholder="<?= __('Pick a date') ?>"
|
||||
value="<?= $user->birthdate ?>"
|
||||
<input class="ui primary button"
|
||||
type="submit"
|
||||
value="<?= __('Save') ?>"
|
||||
title="<?= __('Save') ?>"
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ui tab" data-tab="preferences">
|
||||
<div class="ui segment">
|
||||
|
||||
<form class="ui form" method="POST">
|
||||
<input type="hidden" name="user-id" value="<?= $user->id ?>" />
|
||||
<input type="hidden" name="section" value="preferences" />
|
||||
|
||||
<div class="two fields">
|
||||
<div class="field">
|
||||
<label><?= __('Language') ?></label>
|
||||
|
||||
|
@ -127,6 +258,11 @@ $page->navigation();
|
|||
title="<?= __('Save') ?>"
|
||||
/>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
|
|
@ -8,29 +8,50 @@
|
|||
|
||||
use wishthis\{Page, User};
|
||||
|
||||
$page = new Page(__FILE__, __('Update'), 100);
|
||||
|
||||
/**
|
||||
* Update
|
||||
*/
|
||||
if ('POST' === $_SERVER['REQUEST_METHOD']) {
|
||||
/**
|
||||
* Database
|
||||
*/
|
||||
$versions_directory = ROOT . '/src/update';
|
||||
$versions_contents = scandir($versions_directory);
|
||||
$versions = array();
|
||||
|
||||
/** 0.5.0 *//*
|
||||
if (-1 === version_compare($options->version, '0.5.0')) {
|
||||
$database->query('ALTER TABLE `users`
|
||||
ADD `status` VARCHAR(32) NOT NULL AFTER `url`
|
||||
;');
|
||||
}*/
|
||||
foreach ($versions_contents as $filename) {
|
||||
$filepath = $versions_directory . '/' . $filename;
|
||||
$pathinfo = pathinfo($filepath);
|
||||
|
||||
if ('sql' === $pathinfo['extension']) {
|
||||
$versions[] = array(
|
||||
'version' => str_replace('-', '.', $pathinfo['filename']),
|
||||
'filepath' => $filepath,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($versions as $version) {
|
||||
if (-1 !== version_compare(VERSION, $version['version'])) {
|
||||
$sql = file_get_contents($version['filepath']);
|
||||
|
||||
if ($sql) {
|
||||
$database->query($sql);
|
||||
|
||||
$page->messages[] = Page::info(
|
||||
sprintf(
|
||||
__('Database successfully migrated to %s.'),
|
||||
'v' . $version['version']
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Update version */
|
||||
$options->setOption('version', VERSION);
|
||||
$options->setOption('updateAvailable', false);
|
||||
|
||||
redirect('/?page=home');
|
||||
}
|
||||
|
||||
$page = new Page(__FILE__, __('Update'), 100);
|
||||
$page->header();
|
||||
$page->bodyStart();
|
||||
$page->navigation();
|
||||
|
@ -40,6 +61,8 @@ $page->navigation();
|
|||
<div class="ui container">
|
||||
<h1 class="ui header"><?= $page->title ?></h1>
|
||||
|
||||
<?= $page->messages() ?>
|
||||
|
||||
<div class="ui segment">
|
||||
<h2 class="ui header"><?= __('Database migration') ?></h2>
|
||||
<p><?= __('Thank you for updating withthis! To complete this update, some changes are required to the database structure.') ?></p>
|
||||
|
|
5
src/update/0-5-0.sql
Normal file
5
src/update/0-5-0.sql
Normal file
|
@ -0,0 +1,5 @@
|
|||
ALTER TABLE `users`
|
||||
ADD COLUMN `name_first` VARCHAR(32) NULL DEFAULT NULL,
|
||||
ADD COLUMN `name_last` VARCHAR(32) NULL DEFAULT NULL,
|
||||
ADD COLUMN `name_nick` VARCHAR(32) NULL DEFAULT NULL
|
||||
;
|
Loading…
Reference in a new issue