Added better console command handling.
This commit is contained in:
parent
f3b1c9f70a
commit
a176107bf8
19 changed files with 629 additions and 522 deletions
534
misuzu.php
534
misuzu.php
|
@ -32,15 +32,19 @@ date_default_timezone_set('utc');
|
||||||
set_include_path(get_include_path() . PATH_SEPARATOR . MSZ_ROOT);
|
set_include_path(get_include_path() . PATH_SEPARATOR . MSZ_ROOT);
|
||||||
|
|
||||||
set_exception_handler(function(\Throwable $ex) {
|
set_exception_handler(function(\Throwable $ex) {
|
||||||
http_response_code(500);
|
if(MSZ_CLI) {
|
||||||
ob_clean();
|
|
||||||
|
|
||||||
if(MSZ_CLI || MSZ_DEBUG) {
|
|
||||||
header('Content-Type: text/plain; charset=utf-8');
|
|
||||||
echo (string)$ex;
|
echo (string)$ex;
|
||||||
} else {
|
} else {
|
||||||
header('Content-Type: text/html; charset-utf-8');
|
http_response_code(500);
|
||||||
echo file_get_contents(MSZ_ROOT . '/templates/500.html');
|
ob_clean();
|
||||||
|
|
||||||
|
if(MSZ_DEBUG) {
|
||||||
|
header('Content-Type: text/plain; charset=utf-8');
|
||||||
|
echo (string)$ex;
|
||||||
|
} else {
|
||||||
|
header('Content-Type: text/html; charset-utf-8');
|
||||||
|
echo file_get_contents(MSZ_ROOT . '/templates/500.html');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
exit;
|
exit;
|
||||||
});
|
});
|
||||||
|
@ -113,418 +117,160 @@ Mailer::init(Config::get('mail.method', Config::TYPE_STR), [
|
||||||
define('MSZ_STORAGE', Config::get('storage.path', Config::TYPE_STR, MSZ_ROOT . '/store'));
|
define('MSZ_STORAGE', Config::get('storage.path', Config::TYPE_STR, MSZ_ROOT . '/store'));
|
||||||
mkdirs(MSZ_STORAGE, true);
|
mkdirs(MSZ_STORAGE, true);
|
||||||
|
|
||||||
if(MSZ_CLI) {
|
if(MSZ_CLI) { // Temporary backwards compatibility measure, remove this later
|
||||||
if(realpath($_SERVER['SCRIPT_FILENAME']) === __FILE__) {
|
if(realpath($_SERVER['SCRIPT_FILENAME']) === __FILE__) {
|
||||||
switch($argv[1] ?? null) {
|
if(($argv[1] ?? '') === 'cron' && ($argv[2] ?? '') === 'low')
|
||||||
case 'cron':
|
$argv[2] = '--slow';
|
||||||
$runLowFreq = (bool)(!empty($argv[2]) && $argv[2] == 'low');
|
array_shift($argv);
|
||||||
|
echo shell_exec(__DIR__ . '/msz ' . implode(' ', $argv));
|
||||||
$cronTasks = [
|
}
|
||||||
[
|
return;
|
||||||
'name' => 'Ensures main role exists.',
|
|
||||||
'type' => 'sql',
|
|
||||||
'run' => $runLowFreq,
|
|
||||||
'command' => "
|
|
||||||
INSERT IGNORE INTO `msz_roles`
|
|
||||||
(`role_id`, `role_name`, `role_hierarchy`, `role_colour`, `role_description`, `role_created`)
|
|
||||||
VALUES
|
|
||||||
(1, 'Member', 1, 1073741824, NULL, NOW())
|
|
||||||
",
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'name' => 'Ensures all users are in the main role.',
|
|
||||||
'type' => 'sql',
|
|
||||||
'run' => $runLowFreq,
|
|
||||||
'command' => "
|
|
||||||
INSERT INTO `msz_user_roles`
|
|
||||||
(`user_id`, `role_id`)
|
|
||||||
SELECT `user_id`, 1 FROM `msz_users` as u
|
|
||||||
WHERE NOT EXISTS (
|
|
||||||
SELECT 1
|
|
||||||
FROM `msz_user_roles` as ur
|
|
||||||
WHERE `role_id` = 1
|
|
||||||
AND u.`user_id` = ur.`user_id`
|
|
||||||
)
|
|
||||||
",
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'name' => 'Ensures all display_role values are correct with `msz_user_roles`.',
|
|
||||||
'type' => 'sql',
|
|
||||||
'run' => $runLowFreq,
|
|
||||||
'command' => "
|
|
||||||
UPDATE `msz_users` as u
|
|
||||||
SET `display_role` = (
|
|
||||||
SELECT ur.`role_id`
|
|
||||||
FROM `msz_user_roles` as ur
|
|
||||||
LEFT JOIN `msz_roles` as r
|
|
||||||
ON r.`role_id` = ur.`role_id`
|
|
||||||
WHERE ur.`user_id` = u.`user_id`
|
|
||||||
ORDER BY `role_hierarchy` DESC
|
|
||||||
LIMIT 1
|
|
||||||
)
|
|
||||||
WHERE NOT EXISTS (
|
|
||||||
SELECT 1
|
|
||||||
FROM `msz_user_roles` as ur
|
|
||||||
WHERE ur.`role_id` = u.`display_role`
|
|
||||||
AND `ur`.`user_id` = u.`user_id`
|
|
||||||
)
|
|
||||||
",
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'name' => 'Remove expired sessions.',
|
|
||||||
'type' => 'sql',
|
|
||||||
'run' => true,
|
|
||||||
'command' => "
|
|
||||||
DELETE FROM `msz_sessions`
|
|
||||||
WHERE `session_expires` < NOW()
|
|
||||||
",
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'name' => 'Remove old password reset records.',
|
|
||||||
'type' => 'sql',
|
|
||||||
'run' => true,
|
|
||||||
'command' => "
|
|
||||||
DELETE FROM `msz_users_password_resets`
|
|
||||||
WHERE `reset_requested` < NOW() - INTERVAL 1 WEEK
|
|
||||||
",
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'name' => 'Remove old chat login tokens.',
|
|
||||||
'type' => 'sql',
|
|
||||||
'run' => true,
|
|
||||||
'command' => "
|
|
||||||
DELETE FROM `msz_user_chat_tokens`
|
|
||||||
WHERE `token_created` < NOW() - INTERVAL 1 WEEK
|
|
||||||
",
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'name' => 'Clean up login history.',
|
|
||||||
'type' => 'sql',
|
|
||||||
'run' => true,
|
|
||||||
'command' => "
|
|
||||||
DELETE FROM `msz_login_attempts`
|
|
||||||
WHERE `attempt_created` < NOW() - INTERVAL 1 MONTH
|
|
||||||
",
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'name' => 'Clean up audit log.',
|
|
||||||
'type' => 'sql',
|
|
||||||
'run' => true,
|
|
||||||
'command' => "
|
|
||||||
DELETE FROM `msz_audit_log`
|
|
||||||
WHERE `log_created` < NOW() - INTERVAL 3 MONTH
|
|
||||||
",
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'name' => 'Remove stale forum tracking entries.',
|
|
||||||
'type' => 'sql',
|
|
||||||
'run' => true,
|
|
||||||
'command' => "
|
|
||||||
DELETE tt FROM `msz_forum_topics_track` as tt
|
|
||||||
LEFT JOIN `msz_forum_topics` as t
|
|
||||||
ON t.`topic_id` = tt.`topic_id`
|
|
||||||
WHERE t.`topic_bumped` < NOW() - INTERVAL 1 MONTH
|
|
||||||
",
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'name' => 'Synchronise forum_id.',
|
|
||||||
'type' => 'sql',
|
|
||||||
'run' => $runLowFreq,
|
|
||||||
'command' => "
|
|
||||||
UPDATE `msz_forum_posts` AS p
|
|
||||||
INNER JOIN `msz_forum_topics` AS t
|
|
||||||
ON t.`topic_id` = p.`topic_id`
|
|
||||||
SET p.`forum_id` = t.`forum_id`
|
|
||||||
",
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'name' => 'Recount forum topics and posts.',
|
|
||||||
'type' => 'func',
|
|
||||||
'run' => $runLowFreq,
|
|
||||||
'command' => 'forum_count_synchronise',
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'name' => 'Clean up expired tfa tokens.',
|
|
||||||
'type' => 'sql',
|
|
||||||
'run' => true,
|
|
||||||
'command' => "
|
|
||||||
DELETE FROM `msz_auth_tfa`
|
|
||||||
WHERE `tfa_created` < NOW() - INTERVAL 15 MINUTE
|
|
||||||
",
|
|
||||||
],
|
|
||||||
];
|
|
||||||
|
|
||||||
foreach($cronTasks as $cronTask) {
|
|
||||||
if($cronTask['run']) {
|
|
||||||
echo $cronTask['name'] . PHP_EOL;
|
|
||||||
|
|
||||||
switch($cronTask['type']) {
|
|
||||||
case 'sql':
|
|
||||||
DB::exec($cronTask['command']);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'func':
|
|
||||||
call_user_func($cronTask['command']);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'migrate':
|
|
||||||
$doRollback = !empty($argv[2]) && $argv[2] === 'rollback';
|
|
||||||
|
|
||||||
touch(MSZ_ROOT . '/.migrating');
|
|
||||||
|
|
||||||
echo "Creating migration manager.." . PHP_EOL;
|
|
||||||
$migrationManager = new DatabaseMigrationManager(DB::getPDO(), MSZ_ROOT . '/database');
|
|
||||||
$migrationManager->setLogger(function ($log) {
|
|
||||||
echo $log . PHP_EOL;
|
|
||||||
});
|
|
||||||
|
|
||||||
if($doRollback) {
|
|
||||||
$migrationManager->rollback();
|
|
||||||
} else {
|
|
||||||
$migrationManager->migrate();
|
|
||||||
}
|
|
||||||
|
|
||||||
$errors = $migrationManager->getErrors();
|
|
||||||
$errorCount = count($errors);
|
|
||||||
|
|
||||||
if($errorCount < 1) {
|
|
||||||
echo 'Completed with no errors!' . PHP_EOL;
|
|
||||||
} else {
|
|
||||||
echo PHP_EOL . "There were {$errorCount} errors during the migrations..." . PHP_EOL;
|
|
||||||
|
|
||||||
foreach($errors as $error) {
|
|
||||||
echo $error . PHP_EOL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unlink(MSZ_ROOT . '/.migrating');
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'new-mig':
|
|
||||||
if(empty($argv[2])) {
|
|
||||||
echo 'Specify a migration name.' . PHP_EOL;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!preg_match('#^([a-z_]+)$#', $argv[2])) {
|
|
||||||
echo 'Migration name may only contain alpha and _ characters.' . PHP_EOL;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$filename = date('Y_m_d_His_') . trim($argv[2], '_') . '.php';
|
|
||||||
$filepath = MSZ_ROOT . '/database/' . $filename;
|
|
||||||
$namespace = snake_to_camel($argv[2]);
|
|
||||||
$template = <<<MIG
|
|
||||||
<?php
|
|
||||||
namespace Misuzu\DatabaseMigrations\\$namespace;
|
|
||||||
|
|
||||||
use PDO;
|
|
||||||
|
|
||||||
function migrate_up(PDO \$conn): void {
|
|
||||||
\$conn->exec("
|
|
||||||
CREATE TABLE ...
|
|
||||||
");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function migrate_down(PDO \$conn): void {
|
// Everything below here should eventually be moved to index.php, probably only initialised when required.
|
||||||
\$conn->exec("
|
// Serving things like the css/js doesn't need to initialise sessions.
|
||||||
DROP TABLE ...
|
|
||||||
");
|
if(!mb_check_encoding()) {
|
||||||
|
http_response_code(415);
|
||||||
|
echo 'Invalid request encoding.';
|
||||||
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
MIG;
|
ob_start();
|
||||||
|
|
||||||
file_put_contents($filepath, $template);
|
if(!is_readable(MSZ_STORAGE) || !is_writable(MSZ_STORAGE)) {
|
||||||
|
echo 'Cannot access storage directory.';
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
echo "Template for '{$namespace}' has been created." . PHP_EOL;
|
GeoIP::init(Config::get('geoip.database', Config::TYPE_STR, '/var/lib/GeoIP/GeoLite2-Country.mmdb'));
|
||||||
break;
|
|
||||||
|
|
||||||
case 'twitter-auth':
|
if(!MSZ_DEBUG) {
|
||||||
$apiKey = Config::get('twitter.api.key', Config::TYPE_STR);
|
$twigCache = sys_get_temp_dir() . '/msz-tpl-cache-' . md5(MSZ_ROOT);
|
||||||
$apiSecret = Config::get('twitter.api.secret', Config::TYPE_STR);
|
mkdirs($twigCache, true);
|
||||||
|
}
|
||||||
|
|
||||||
if(empty($apiKey) || empty($apiSecret)) {
|
Template::init($twigCache ?? null, MSZ_DEBUG);
|
||||||
echo 'No Twitter api keys set in config.' . PHP_EOL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
Twitter::init($apiKey, $apiSecret);
|
Template::set('globals', [
|
||||||
echo 'Twitter Authentication' . PHP_EOL;
|
'site_name' => Config::get('site.name', Config::TYPE_STR, 'Misuzu'),
|
||||||
|
'site_description' => Config::get('site.desc', Config::TYPE_STR),
|
||||||
|
'site_url' => Config::get('site.url', Config::TYPE_STR),
|
||||||
|
'site_twitter' => Config::get('social.twitter', Config::TYPE_STR),
|
||||||
|
]);
|
||||||
|
|
||||||
$authPage = Twitter::createAuth();
|
Template::addPath(MSZ_ROOT . '/templates');
|
||||||
|
|
||||||
if(empty($authPage)) {
|
if(file_exists(MSZ_ROOT . '/.migrating')) {
|
||||||
echo 'Request to begin authentication failed.' . PHP_EOL;
|
http_response_code(503);
|
||||||
break;
|
Template::render('home.migration');
|
||||||
}
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
echo 'Go to the page below and paste the pin code displayed.' . PHP_EOL . $authPage . PHP_EOL;
|
if(isset($_COOKIE['msz_uid']) && isset($_COOKIE['msz_sid'])) {
|
||||||
|
$authToken = (new AuthToken)
|
||||||
|
->setUserId(filter_input(INPUT_COOKIE, 'msz_uid', FILTER_SANITIZE_NUMBER_INT) ?? 0)
|
||||||
|
->setSessionToken(filter_input(INPUT_COOKIE, 'msz_sid', FILTER_SANITIZE_STRING) ?? '');
|
||||||
|
|
||||||
$pin = readline('Pin: ');
|
if($authToken->isValid())
|
||||||
$authComplete = Twitter::completeAuth($pin);
|
setcookie('msz_auth', $authToken->pack(), strtotime('1 year'), '/', '.' . $_SERVER['HTTP_HOST'], !empty($_SERVER['HTTPS']), true);
|
||||||
|
|
||||||
if(empty($authComplete)) {
|
setcookie('msz_uid', '', -3600, '/', '', !empty($_SERVER['HTTPS']), true);
|
||||||
echo 'Invalid pin code.' . PHP_EOL;
|
setcookie('msz_sid', '', -3600, '/', '', !empty($_SERVER['HTTPS']), true);
|
||||||
break;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
echo 'Authentication successful!' . PHP_EOL
|
if(!isset($authToken))
|
||||||
. "Token: {$authComplete['token']}" . PHP_EOL
|
$authToken = AuthToken::unpack(filter_input(INPUT_COOKIE, 'msz_auth', FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH) ?? '');
|
||||||
. "Token Secret: {$authComplete['token_secret']}" . PHP_EOL;
|
if($authToken->isValid()) {
|
||||||
break;
|
try {
|
||||||
|
$sessionInfo = $authToken->getSession();
|
||||||
|
if($sessionInfo->hasExpired()) {
|
||||||
|
$sessionInfo->delete();
|
||||||
|
} elseif($sessionInfo->getUserId() === $authToken->getUserId()) {
|
||||||
|
$userInfo = $sessionInfo->getUser();
|
||||||
|
if(!$userInfo->isDeleted()) {
|
||||||
|
$sessionInfo->setCurrent();
|
||||||
|
$userInfo->setCurrent();
|
||||||
|
|
||||||
default:
|
$sessionInfo->bump();
|
||||||
echo 'Unknown command.' . PHP_EOL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if(!mb_check_encoding()) {
|
|
||||||
http_response_code(415);
|
|
||||||
echo 'Invalid request encoding.';
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
ob_start();
|
if($sessionInfo->shouldBumpExpire())
|
||||||
|
setcookie('msz_auth', $authToken->pack(), $sessionInfo->getExpiresTime(), '/', '.' . $_SERVER['HTTP_HOST'], !empty($_SERVER['HTTPS']), true);
|
||||||
if(!is_readable(MSZ_STORAGE) || !is_writable(MSZ_STORAGE)) {
|
|
||||||
echo 'Cannot access storage directory.';
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
GeoIP::init(Config::get('geoip.database', Config::TYPE_STR, '/var/lib/GeoIP/GeoLite2-Country.mmdb'));
|
|
||||||
|
|
||||||
if(!MSZ_DEBUG) {
|
|
||||||
$twigCache = sys_get_temp_dir() . '/msz-tpl-cache-' . md5(MSZ_ROOT);
|
|
||||||
mkdirs($twigCache, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
Template::init($twigCache ?? null, MSZ_DEBUG);
|
|
||||||
|
|
||||||
Template::set('globals', [
|
|
||||||
'site_name' => Config::get('site.name', Config::TYPE_STR, 'Misuzu'),
|
|
||||||
'site_description' => Config::get('site.desc', Config::TYPE_STR),
|
|
||||||
'site_url' => Config::get('site.url', Config::TYPE_STR),
|
|
||||||
'site_twitter' => Config::get('social.twitter', Config::TYPE_STR),
|
|
||||||
]);
|
|
||||||
|
|
||||||
Template::addPath(MSZ_ROOT . '/templates');
|
|
||||||
|
|
||||||
if(file_exists(MSZ_ROOT . '/.migrating')) {
|
|
||||||
http_response_code(503);
|
|
||||||
Template::render('home.migration');
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(isset($_COOKIE['msz_uid']) && isset($_COOKIE['msz_sid'])) {
|
|
||||||
$authToken = (new AuthToken)
|
|
||||||
->setUserId(filter_input(INPUT_COOKIE, 'msz_uid', FILTER_SANITIZE_NUMBER_INT) ?? 0)
|
|
||||||
->setSessionToken(filter_input(INPUT_COOKIE, 'msz_sid', FILTER_SANITIZE_STRING) ?? '');
|
|
||||||
|
|
||||||
if($authToken->isValid())
|
|
||||||
setcookie('msz_auth', $authToken->pack(), strtotime('1 year'), '/', '.' . $_SERVER['HTTP_HOST'], !empty($_SERVER['HTTPS']), true);
|
|
||||||
|
|
||||||
setcookie('msz_uid', '', -3600, '/', '', !empty($_SERVER['HTTPS']), true);
|
|
||||||
setcookie('msz_sid', '', -3600, '/', '', !empty($_SERVER['HTTPS']), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!isset($authToken))
|
|
||||||
$authToken = AuthToken::unpack(filter_input(INPUT_COOKIE, 'msz_auth', FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH) ?? '');
|
|
||||||
if($authToken->isValid()) {
|
|
||||||
try {
|
|
||||||
$sessionInfo = $authToken->getSession();
|
|
||||||
if($sessionInfo->hasExpired()) {
|
|
||||||
$sessionInfo->delete();
|
|
||||||
} elseif($sessionInfo->getUserId() === $authToken->getUserId()) {
|
|
||||||
$userInfo = $sessionInfo->getUser();
|
|
||||||
if(!$userInfo->isDeleted()) {
|
|
||||||
$sessionInfo->setCurrent();
|
|
||||||
$userInfo->setCurrent();
|
|
||||||
|
|
||||||
$sessionInfo->bump();
|
|
||||||
|
|
||||||
if($sessionInfo->shouldBumpExpire())
|
|
||||||
setcookie('msz_auth', $authToken->pack(), $sessionInfo->getExpiresTime(), '/', '.' . $_SERVER['HTTP_HOST'], !empty($_SERVER['HTTPS']), true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch(UserNotFoundException $ex) {
|
|
||||||
UserSession::unsetCurrent();
|
|
||||||
User::unsetCurrent();
|
|
||||||
} catch(UserSessionNotFoundException $ex) {
|
|
||||||
UserSession::unsetCurrent();
|
|
||||||
User::unsetCurrent();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!UserSession::hasCurrent()) {
|
|
||||||
setcookie('msz_auth', '', -9001, '/', '.' . $_SERVER['HTTP_HOST'], !empty($_SERVER['HTTPS']), true);
|
|
||||||
setcookie('msz_auth', '', -9001, '/', '', !empty($_SERVER['HTTPS']), true);
|
|
||||||
} else {
|
|
||||||
$userDisplayInfo = DB::prepare('
|
|
||||||
SELECT
|
|
||||||
u.`user_id`, u.`username`, u.`user_background_settings`, u.`user_deleted`,
|
|
||||||
COALESCE(u.`user_colour`, r.`role_colour`) AS `user_colour`
|
|
||||||
FROM `msz_users` AS u
|
|
||||||
LEFT JOIN `msz_roles` AS r
|
|
||||||
ON u.`display_role` = r.`role_id`
|
|
||||||
WHERE `user_id` = :user_id
|
|
||||||
') ->bind('user_id', $userInfo->getId())
|
|
||||||
->fetch();
|
|
||||||
|
|
||||||
user_bump_last_active($userInfo->getId());
|
|
||||||
|
|
||||||
$userDisplayInfo['perms'] = perms_get_user($userInfo->getId());
|
|
||||||
$userDisplayInfo['ban_expiration'] = user_warning_check_expiration($userInfo->getId(), MSZ_WARN_BAN);
|
|
||||||
$userDisplayInfo['silence_expiration'] = $userDisplayInfo['ban_expiration'] > 0 ? 0 : user_warning_check_expiration($userInfo->getId(), MSZ_WARN_SILENCE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CSRF::setGlobalSecretKey(Config::get('csrf.secret', Config::TYPE_STR, 'soup'));
|
|
||||||
CSRF::setGlobalIdentity(UserSession::hasCurrent() ? UserSession::getCurrent()->getToken() : IPAddress::remote());
|
|
||||||
|
|
||||||
if(Config::get('private.enabled', Config::TYPE_BOOL)) {
|
|
||||||
$onLoginPage = $_SERVER['PHP_SELF'] === url('auth-login');
|
|
||||||
$onPasswordPage = parse_url($_SERVER['PHP_SELF'], PHP_URL_PATH) === url('auth-forgot');
|
|
||||||
$misuzuBypassLockdown = !empty($misuzuBypassLockdown) || $onLoginPage;
|
|
||||||
|
|
||||||
if(!$misuzuBypassLockdown) {
|
|
||||||
if(UserSession::hasCurrent()) {
|
|
||||||
$privatePermCat = Config::get('private.perm.cat', Config::TYPE_STR);
|
|
||||||
$privatePermVal = Config::get('private.perm.val', Config::TYPE_INT);
|
|
||||||
|
|
||||||
if(!empty($privatePermCat) && $privatePermVal > 0) {
|
|
||||||
if(!perms_check_user($privatePermCat, User::getCurrent()->getId(), $privatePermVal)) {
|
|
||||||
// au revoir
|
|
||||||
unset($userDisplayInfo);
|
|
||||||
UserSession::unsetCurrent();
|
|
||||||
User::unsetCurrent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} elseif(!$onLoginPage && !($onPasswordPage && Config::get('private.allow_password_reset', Config::TYPE_BOOL, true))) {
|
|
||||||
url_redirect('auth-login');
|
|
||||||
exit;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch(UserNotFoundException $ex) {
|
||||||
|
UserSession::unsetCurrent();
|
||||||
|
User::unsetCurrent();
|
||||||
|
} catch(UserSessionNotFoundException $ex) {
|
||||||
|
UserSession::unsetCurrent();
|
||||||
|
User::unsetCurrent();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!empty($userDisplayInfo)) // delete this
|
if(!UserSession::hasCurrent()) {
|
||||||
Template::set('current_user', $userDisplayInfo);
|
setcookie('msz_auth', '', -9001, '/', '.' . $_SERVER['HTTP_HOST'], !empty($_SERVER['HTTPS']), true);
|
||||||
|
setcookie('msz_auth', '', -9001, '/', '', !empty($_SERVER['HTTPS']), true);
|
||||||
|
} else {
|
||||||
|
$userDisplayInfo = DB::prepare('
|
||||||
|
SELECT
|
||||||
|
u.`user_id`, u.`username`, u.`user_background_settings`, u.`user_deleted`,
|
||||||
|
COALESCE(u.`user_colour`, r.`role_colour`) AS `user_colour`
|
||||||
|
FROM `msz_users` AS u
|
||||||
|
LEFT JOIN `msz_roles` AS r
|
||||||
|
ON u.`display_role` = r.`role_id`
|
||||||
|
WHERE `user_id` = :user_id
|
||||||
|
') ->bind('user_id', $userInfo->getId())
|
||||||
|
->fetch();
|
||||||
|
|
||||||
$inManageMode = starts_with($_SERVER['REQUEST_URI'], '/manage');
|
user_bump_last_active($userInfo->getId());
|
||||||
$hasManageAccess = User::hasCurrent()
|
|
||||||
&& !user_warning_check_restriction(User::getCurrent()->getId())
|
|
||||||
&& perms_check_user(MSZ_PERMS_GENERAL, User::getCurrent()->getId(), MSZ_PERM_GENERAL_CAN_MANAGE);
|
|
||||||
Template::set('has_manage_access', $hasManageAccess);
|
|
||||||
|
|
||||||
if($inManageMode) {
|
$userDisplayInfo['perms'] = perms_get_user($userInfo->getId());
|
||||||
if(!$hasManageAccess) {
|
$userDisplayInfo['ban_expiration'] = user_warning_check_expiration($userInfo->getId(), MSZ_WARN_BAN);
|
||||||
echo render_error(403);
|
$userDisplayInfo['silence_expiration'] = $userDisplayInfo['ban_expiration'] > 0 ? 0 : user_warning_check_expiration($userInfo->getId(), MSZ_WARN_SILENCE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CSRF::setGlobalSecretKey(Config::get('csrf.secret', Config::TYPE_STR, 'soup'));
|
||||||
|
CSRF::setGlobalIdentity(UserSession::hasCurrent() ? UserSession::getCurrent()->getToken() : IPAddress::remote());
|
||||||
|
|
||||||
|
if(Config::get('private.enabled', Config::TYPE_BOOL)) {
|
||||||
|
$onLoginPage = $_SERVER['PHP_SELF'] === url('auth-login');
|
||||||
|
$onPasswordPage = parse_url($_SERVER['PHP_SELF'], PHP_URL_PATH) === url('auth-forgot');
|
||||||
|
$misuzuBypassLockdown = !empty($misuzuBypassLockdown) || $onLoginPage;
|
||||||
|
|
||||||
|
if(!$misuzuBypassLockdown) {
|
||||||
|
if(UserSession::hasCurrent()) {
|
||||||
|
$privatePermCat = Config::get('private.perm.cat', Config::TYPE_STR);
|
||||||
|
$privatePermVal = Config::get('private.perm.val', Config::TYPE_INT);
|
||||||
|
|
||||||
|
if(!empty($privatePermCat) && $privatePermVal > 0) {
|
||||||
|
if(!perms_check_user($privatePermCat, User::getCurrent()->getId(), $privatePermVal)) {
|
||||||
|
// au revoir
|
||||||
|
unset($userDisplayInfo);
|
||||||
|
UserSession::unsetCurrent();
|
||||||
|
User::unsetCurrent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} elseif(!$onLoginPage && !($onPasswordPage && Config::get('private.allow_password_reset', Config::TYPE_BOOL, true))) {
|
||||||
|
url_redirect('auth-login');
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
Template::set('manage_menu', manage_get_menu(User::getCurrent()->getId()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!empty($userDisplayInfo)) // delete this
|
||||||
|
Template::set('current_user', $userDisplayInfo);
|
||||||
|
|
||||||
|
$inManageMode = starts_with($_SERVER['REQUEST_URI'], '/manage');
|
||||||
|
$hasManageAccess = User::hasCurrent()
|
||||||
|
&& !user_warning_check_restriction(User::getCurrent()->getId())
|
||||||
|
&& perms_check_user(MSZ_PERMS_GENERAL, User::getCurrent()->getId(), MSZ_PERM_GENERAL_CAN_MANAGE);
|
||||||
|
Template::set('has_manage_access', $hasManageAccess);
|
||||||
|
|
||||||
|
if($inManageMode) {
|
||||||
|
if(!$hasManageAccess) {
|
||||||
|
echo render_error(403);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
Template::set('manage_menu', manage_get_menu(User::getCurrent()->getId()));
|
||||||
|
}
|
||||||
|
|
20
msz
Executable file
20
msz
Executable file
|
@ -0,0 +1,20 @@
|
||||||
|
#!/usr/bin/env php
|
||||||
|
<?php
|
||||||
|
namespace Misuzu;
|
||||||
|
|
||||||
|
use Misuzu\Console\CommandArgs;
|
||||||
|
use Misuzu\Console\CommandCollection;
|
||||||
|
|
||||||
|
require_once __DIR__ . '/misuzu.php';
|
||||||
|
|
||||||
|
if(!MSZ_CLI)
|
||||||
|
die('This tool is meant to be used through command line only.' . PHP_EOL);
|
||||||
|
|
||||||
|
$commands = new CommandCollection;
|
||||||
|
$commands->addCommands(
|
||||||
|
new \Misuzu\Console\Commands\CronCommand,
|
||||||
|
new \Misuzu\Console\Commands\MigrateCommand,
|
||||||
|
new \Misuzu\Console\Commands\NewMigrationCommand,
|
||||||
|
new \Misuzu\Console\Commands\TwitterAuthCommand,
|
||||||
|
);
|
||||||
|
$commands->dispatch(new CommandArgs($argv));
|
9
msz.php
9
msz.php
|
@ -1,9 +0,0 @@
|
||||||
<?php
|
|
||||||
namespace Misuzu;
|
|
||||||
|
|
||||||
require_once __DIR__ . '/misuzu.php';
|
|
||||||
|
|
||||||
if(!MSZ_CLI)
|
|
||||||
die('This tool is meant to be used through command line only.' . PHP_EOL);
|
|
||||||
|
|
||||||
// todo: make improved command line interface and remove the things in misuzu.php
|
|
45
src/Console/CommandArgs.php
Normal file
45
src/Console/CommandArgs.php
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
<?php
|
||||||
|
namespace Misuzu\Console;
|
||||||
|
|
||||||
|
class CommandArgs {
|
||||||
|
private $args = [];
|
||||||
|
|
||||||
|
public function __construct(array $args) {
|
||||||
|
$this->args = $args;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getArgs(): array {
|
||||||
|
return $this->args;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCommand(): string {
|
||||||
|
return $this->args[1] ?? '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getArg(int $index): string {
|
||||||
|
return $this->args[2 + $index] ?? '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function flagIndex(string $long, string $short = ''): int {
|
||||||
|
$long = '--' . $long;
|
||||||
|
$short = '-' . $short;
|
||||||
|
for($i = 2; $i < count($this->args); ++$i)
|
||||||
|
if(($long !== '--' && $this->args[$i] === $long) || ($short !== '-' && $short === $this->args[$i]))
|
||||||
|
return $i;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasFlag(string $long, string $short = ''): bool {
|
||||||
|
return $this->flagIndex($long, $short) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFlag(string $long, string $short = ''): string {
|
||||||
|
$index = $this->flagIndex($long, $short);
|
||||||
|
if($index < 0)
|
||||||
|
return '';
|
||||||
|
$arg = $this->args[$index + 1] ?? '';
|
||||||
|
if($arg[0] == '-')
|
||||||
|
return '';
|
||||||
|
return $arg;
|
||||||
|
}
|
||||||
|
}
|
33
src/Console/CommandCollection.php
Normal file
33
src/Console/CommandCollection.php
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
<?php
|
||||||
|
namespace Misuzu\Console;
|
||||||
|
|
||||||
|
class CommandManagerException extends ConsoleException {}
|
||||||
|
class CommandNotFoundException extends CommandManagerException {}
|
||||||
|
|
||||||
|
class CommandCollection implements CommandDispatchInterface {
|
||||||
|
private $commands = [];
|
||||||
|
|
||||||
|
public function addCommands(CommandInterface ...$commands): void {
|
||||||
|
foreach($commands as $command)
|
||||||
|
try {
|
||||||
|
$this->matchCommand($command->getName());
|
||||||
|
} catch(CommandNotFoundException $ex) {
|
||||||
|
$this->commands[] = $command;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function matchCommand(string $name): CommandInterface {
|
||||||
|
foreach($this->commands as $command)
|
||||||
|
if($command->getName() === $name)
|
||||||
|
return $command;
|
||||||
|
throw new CommandNotFoundException;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function dispatch(CommandArgs $args): void {
|
||||||
|
try {
|
||||||
|
$this->matchCommand($args->getCommand())->dispatch($args);
|
||||||
|
} catch(CommandNotFoundException $ex) {
|
||||||
|
echo 'Command not found.' . PHP_EOL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
6
src/Console/CommandDispatchInterface.php
Normal file
6
src/Console/CommandDispatchInterface.php
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?php
|
||||||
|
namespace Misuzu\Console;
|
||||||
|
|
||||||
|
interface CommandDispatchInterface {
|
||||||
|
public function dispatch(CommandArgs $args): void;
|
||||||
|
}
|
7
src/Console/CommandInterface.php
Normal file
7
src/Console/CommandInterface.php
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<?php
|
||||||
|
namespace Misuzu\Console;
|
||||||
|
|
||||||
|
interface CommandInterface extends CommandDispatchInterface {
|
||||||
|
public function getName(): string;
|
||||||
|
public function getSummary(): string;
|
||||||
|
}
|
163
src/Console/Commands/CronCommand.php
Normal file
163
src/Console/Commands/CronCommand.php
Normal file
|
@ -0,0 +1,163 @@
|
||||||
|
<?php
|
||||||
|
namespace Misuzu\Console\Commands;
|
||||||
|
|
||||||
|
use Misuzu\DB;
|
||||||
|
use Misuzu\Console\CommandArgs;
|
||||||
|
use Misuzu\Console\CommandInterface;
|
||||||
|
|
||||||
|
class CronCommand implements CommandInterface {
|
||||||
|
public function getName(): string {
|
||||||
|
return 'cron';
|
||||||
|
}
|
||||||
|
public function getSummary(): string {
|
||||||
|
return 'Runs scheduled tasks and cleanups.';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function dispatch(CommandArgs $args): void {
|
||||||
|
$runSlow = $args->hasFlag('slow');
|
||||||
|
|
||||||
|
foreach(self::TASKS as $task) {
|
||||||
|
if($runSlow || empty($task['slow'])) {
|
||||||
|
echo $task['name'] . PHP_EOL;
|
||||||
|
|
||||||
|
switch($task['type']) {
|
||||||
|
case 'sql':
|
||||||
|
DB::exec($task['command']);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'func':
|
||||||
|
call_user_func($task['command']);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private const TASKS = [
|
||||||
|
[
|
||||||
|
'name' => 'Ensures main role exists.',
|
||||||
|
'type' => 'sql',
|
||||||
|
'slow' => true,
|
||||||
|
'command' => "
|
||||||
|
INSERT IGNORE INTO `msz_roles`
|
||||||
|
(`role_id`, `role_name`, `role_hierarchy`, `role_colour`, `role_description`, `role_created`)
|
||||||
|
VALUES
|
||||||
|
(1, 'Member', 1, 1073741824, NULL, NOW())
|
||||||
|
",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'Ensures all users are in the main role.',
|
||||||
|
'type' => 'sql',
|
||||||
|
'slow' => true,
|
||||||
|
'command' => "
|
||||||
|
INSERT INTO `msz_user_roles`
|
||||||
|
(`user_id`, `role_id`)
|
||||||
|
SELECT `user_id`, 1 FROM `msz_users` as u
|
||||||
|
WHERE NOT EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM `msz_user_roles` as ur
|
||||||
|
WHERE `role_id` = 1
|
||||||
|
AND u.`user_id` = ur.`user_id`
|
||||||
|
)
|
||||||
|
",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'Ensures all display_role values are correct with `msz_user_roles`.',
|
||||||
|
'type' => 'sql',
|
||||||
|
'slow' => true,
|
||||||
|
'command' => "
|
||||||
|
UPDATE `msz_users` as u
|
||||||
|
SET `display_role` = (
|
||||||
|
SELECT ur.`role_id`
|
||||||
|
FROM `msz_user_roles` as ur
|
||||||
|
LEFT JOIN `msz_roles` as r
|
||||||
|
ON r.`role_id` = ur.`role_id`
|
||||||
|
WHERE ur.`user_id` = u.`user_id`
|
||||||
|
ORDER BY `role_hierarchy` DESC
|
||||||
|
LIMIT 1
|
||||||
|
)
|
||||||
|
WHERE NOT EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM `msz_user_roles` as ur
|
||||||
|
WHERE ur.`role_id` = u.`display_role`
|
||||||
|
AND `ur`.`user_id` = u.`user_id`
|
||||||
|
)
|
||||||
|
",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'Remove expired sessions.',
|
||||||
|
'type' => 'sql',
|
||||||
|
'command' => "
|
||||||
|
DELETE FROM `msz_sessions`
|
||||||
|
WHERE `session_expires` < NOW()
|
||||||
|
",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'Remove old password reset records.',
|
||||||
|
'type' => 'sql',
|
||||||
|
'command' => "
|
||||||
|
DELETE FROM `msz_users_password_resets`
|
||||||
|
WHERE `reset_requested` < NOW() - INTERVAL 1 WEEK
|
||||||
|
",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'Remove old chat login tokens.',
|
||||||
|
'type' => 'sql',
|
||||||
|
'command' => "
|
||||||
|
DELETE FROM `msz_user_chat_tokens`
|
||||||
|
WHERE `token_created` < NOW() - INTERVAL 1 WEEK
|
||||||
|
",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'Clean up login history.',
|
||||||
|
'type' => 'sql',
|
||||||
|
'command' => "
|
||||||
|
DELETE FROM `msz_login_attempts`
|
||||||
|
WHERE `attempt_created` < NOW() - INTERVAL 1 MONTH
|
||||||
|
",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'Clean up audit log.',
|
||||||
|
'type' => 'sql',
|
||||||
|
'command' => "
|
||||||
|
DELETE FROM `msz_audit_log`
|
||||||
|
WHERE `log_created` < NOW() - INTERVAL 3 MONTH
|
||||||
|
",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'Remove stale forum tracking entries.',
|
||||||
|
'type' => 'sql',
|
||||||
|
'command' => "
|
||||||
|
DELETE tt FROM `msz_forum_topics_track` as tt
|
||||||
|
LEFT JOIN `msz_forum_topics` as t
|
||||||
|
ON t.`topic_id` = tt.`topic_id`
|
||||||
|
WHERE t.`topic_bumped` < NOW() - INTERVAL 1 MONTH
|
||||||
|
",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'Synchronise forum_id.',
|
||||||
|
'type' => 'sql',
|
||||||
|
'slow' => true,
|
||||||
|
'command' => "
|
||||||
|
UPDATE `msz_forum_posts` AS p
|
||||||
|
INNER JOIN `msz_forum_topics` AS t
|
||||||
|
ON t.`topic_id` = p.`topic_id`
|
||||||
|
SET p.`forum_id` = t.`forum_id`
|
||||||
|
",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'Recount forum topics and posts.',
|
||||||
|
'type' => 'func',
|
||||||
|
'slow' => true,
|
||||||
|
'command' => 'forum_count_synchronise',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'Clean up expired tfa tokens.',
|
||||||
|
'type' => 'sql',
|
||||||
|
'command' => "
|
||||||
|
DELETE FROM `msz_auth_tfa`
|
||||||
|
WHERE `tfa_created` < NOW() - INTERVAL 15 MINUTE
|
||||||
|
",
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
45
src/Console/Commands/MigrateCommand.php
Normal file
45
src/Console/Commands/MigrateCommand.php
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
<?php
|
||||||
|
namespace Misuzu\Console\Commands;
|
||||||
|
|
||||||
|
use Misuzu\DB;
|
||||||
|
use Misuzu\Console\CommandArgs;
|
||||||
|
use Misuzu\Console\CommandInterface;
|
||||||
|
use Misuzu\Database\DatabaseMigrationManager;
|
||||||
|
|
||||||
|
class MigrateCommand implements CommandInterface {
|
||||||
|
public function getName(): string {
|
||||||
|
return 'migrate';
|
||||||
|
}
|
||||||
|
public function getSummary(): string {
|
||||||
|
return 'Runs database migrations.';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function dispatch(CommandArgs $args): void {
|
||||||
|
touch(MSZ_ROOT . '/.migrating');
|
||||||
|
chmod(MSZ_ROOT . '/.migrating', 0777);
|
||||||
|
|
||||||
|
echo "Creating migration manager.." . PHP_EOL;
|
||||||
|
$migrationManager = new DatabaseMigrationManager(DB::getPDO(), MSZ_ROOT . '/database');
|
||||||
|
$migrationManager->setLogger(function ($log) {
|
||||||
|
echo $log . PHP_EOL;
|
||||||
|
});
|
||||||
|
|
||||||
|
if($args->getArg(0) === 'rollback')
|
||||||
|
$migrationManager->rollback();
|
||||||
|
else
|
||||||
|
$migrationManager->migrate();
|
||||||
|
|
||||||
|
$errors = $migrationManager->getErrors();
|
||||||
|
$errorCount = count($errors);
|
||||||
|
|
||||||
|
if($errorCount < 1) {
|
||||||
|
echo 'Completed with no errors!' . PHP_EOL;
|
||||||
|
} else {
|
||||||
|
echo PHP_EOL . "There were {$errorCount} errors during the migrations..." . PHP_EOL;
|
||||||
|
foreach($errors as $error)
|
||||||
|
echo $error . PHP_EOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
unlink(MSZ_ROOT . '/.migrating');
|
||||||
|
}
|
||||||
|
}
|
56
src/Console/Commands/NewMigrationCommand.php
Normal file
56
src/Console/Commands/NewMigrationCommand.php
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
<?php
|
||||||
|
namespace Misuzu\Console\Commands;
|
||||||
|
|
||||||
|
use Misuzu\Console\CommandArgs;
|
||||||
|
use Misuzu\Console\CommandInterface;
|
||||||
|
|
||||||
|
class NewMigrationCommand implements CommandInterface {
|
||||||
|
private const TEMPLATE = <<<MIG
|
||||||
|
<?php
|
||||||
|
namespace Misuzu\DatabaseMigrations\\%s;
|
||||||
|
|
||||||
|
use PDO;
|
||||||
|
|
||||||
|
function migrate_up(PDO \$conn): void {
|
||||||
|
\$conn->exec("
|
||||||
|
CREATE TABLE ...
|
||||||
|
");
|
||||||
|
}
|
||||||
|
|
||||||
|
function migrate_down(PDO \$conn): void {
|
||||||
|
\$conn->exec("
|
||||||
|
DROP TABLE ...
|
||||||
|
");
|
||||||
|
}
|
||||||
|
|
||||||
|
MIG;
|
||||||
|
|
||||||
|
public function getName(): string {
|
||||||
|
return 'new-mig';
|
||||||
|
}
|
||||||
|
public function getSummary(): string {
|
||||||
|
return 'Creates a new database migration.';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function dispatch(CommandArgs $args): void {
|
||||||
|
$name = trim($args->getArg(0));
|
||||||
|
|
||||||
|
if(empty($name)) {
|
||||||
|
echo 'Specify a migration name.' . PHP_EOL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!preg_match('#^([a-z_]+)$#', $name)) {
|
||||||
|
echo 'Migration name may only contain alpha and _ characters.' . PHP_EOL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$fileName = date('Y_m_d_His_') . trim($name, '_') . '.php';
|
||||||
|
$filePath = MSZ_ROOT . '/database/' . $fileName;
|
||||||
|
$namespace = snake_to_camel($name);
|
||||||
|
|
||||||
|
file_put_contents($filePath, sprintf(self::TEMPLATE, $namespace));
|
||||||
|
|
||||||
|
echo "Template for '{$namespace}' has been created." . PHP_EOL;
|
||||||
|
}
|
||||||
|
}
|
50
src/Console/Commands/TwitterAuthCommand.php
Normal file
50
src/Console/Commands/TwitterAuthCommand.php
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
<?php
|
||||||
|
namespace Misuzu\Console\Commands;
|
||||||
|
|
||||||
|
use Misuzu\Config;
|
||||||
|
use Misuzu\Twitter;
|
||||||
|
use Misuzu\Console\CommandArgs;
|
||||||
|
use Misuzu\Console\CommandInterface;
|
||||||
|
|
||||||
|
class TwitterAuthCommand implements CommandInterface {
|
||||||
|
public function getName(): string {
|
||||||
|
return 'twitter-auth';
|
||||||
|
}
|
||||||
|
public function getSummary(): string {
|
||||||
|
return 'Creates Twitter authentication tokens.';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function dispatch(CommandArgs $args): void {
|
||||||
|
$apiKey = Config::get('twitter.api.key', Config::TYPE_STR);
|
||||||
|
$apiSecret = Config::get('twitter.api.secret', Config::TYPE_STR);
|
||||||
|
|
||||||
|
if(empty($apiKey) || empty($apiSecret)) {
|
||||||
|
echo 'No Twitter api keys set in config.' . PHP_EOL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Twitter::init($apiKey, $apiSecret);
|
||||||
|
echo 'Twitter Authentication' . PHP_EOL;
|
||||||
|
|
||||||
|
$authPage = Twitter::createAuth();
|
||||||
|
|
||||||
|
if(empty($authPage)) {
|
||||||
|
echo 'Request to begin authentication failed.' . PHP_EOL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
echo 'Go to the page below and paste the pin code displayed.' . PHP_EOL . $authPage . PHP_EOL;
|
||||||
|
|
||||||
|
$pin = readline('Pin: ');
|
||||||
|
$authComplete = Twitter::completeAuth($pin);
|
||||||
|
|
||||||
|
if(empty($authComplete)) {
|
||||||
|
echo 'Invalid pin code.' . PHP_EOL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
echo 'Authentication successful!' . PHP_EOL
|
||||||
|
. "Token: {$authComplete['token']}" . PHP_EOL
|
||||||
|
. "Token Secret: {$authComplete['token_secret']}" . PHP_EOL;
|
||||||
|
}
|
||||||
|
}
|
6
src/Console/ConsoleException.php
Normal file
6
src/Console/ConsoleException.php
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?php
|
||||||
|
namespace Misuzu\Console;
|
||||||
|
|
||||||
|
use Misuzu\MisuzuException;
|
||||||
|
|
||||||
|
class ConsoleException extends MisuzuException {}
|
|
@ -6,9 +6,8 @@ function user_auth_tfa_token_generate(): string {
|
||||||
}
|
}
|
||||||
|
|
||||||
function user_auth_tfa_token_create(int $userId): string {
|
function user_auth_tfa_token_create(int $userId): string {
|
||||||
if($userId < 1) {
|
if($userId < 1)
|
||||||
return '';
|
return '';
|
||||||
}
|
|
||||||
|
|
||||||
$token = user_auth_tfa_token_generate();
|
$token = user_auth_tfa_token_generate();
|
||||||
|
|
||||||
|
@ -21,9 +20,8 @@ function user_auth_tfa_token_create(int $userId): string {
|
||||||
$createToken->bind('user_id', $userId);
|
$createToken->bind('user_id', $userId);
|
||||||
$createToken->bind('token', $token);
|
$createToken->bind('token', $token);
|
||||||
|
|
||||||
if(!$createToken->execute()) {
|
if(!$createToken->execute())
|
||||||
return '';
|
return '';
|
||||||
}
|
|
||||||
|
|
||||||
return $token;
|
return $token;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,20 +12,17 @@ function user_avatar_valid_resolution(int $resolution): bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
function user_avatar_resolution_closest(int $resolution): int {
|
function user_avatar_resolution_closest(int $resolution): int {
|
||||||
if($resolution === 0) {
|
if($resolution === 0)
|
||||||
return MSZ_USER_AVATAR_RESOLUTION_ORIGINAL;
|
return MSZ_USER_AVATAR_RESOLUTION_ORIGINAL;
|
||||||
}
|
|
||||||
|
|
||||||
$closest = null;
|
$closest = null;
|
||||||
|
|
||||||
foreach(MSZ_USER_AVATAR_RESOLUTIONS as $res) {
|
foreach(MSZ_USER_AVATAR_RESOLUTIONS as $res) {
|
||||||
if($res === MSZ_USER_AVATAR_RESOLUTION_ORIGINAL) {
|
if($res === MSZ_USER_AVATAR_RESOLUTION_ORIGINAL)
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
if($closest === null || abs($resolution - $closest) >= abs($res - $resolution)) {
|
if($closest === null || abs($resolution - $closest) >= abs($res - $resolution))
|
||||||
$closest = $res;
|
$closest = $res;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $closest;
|
return $closest;
|
||||||
|
@ -77,9 +74,8 @@ define('MSZ_USER_AVATAR_ERROR_STORE_FAILED', 6);
|
||||||
define('MSZ_USER_AVATAR_ERROR_FILE_NOT_FOUND', 7);
|
define('MSZ_USER_AVATAR_ERROR_FILE_NOT_FOUND', 7);
|
||||||
|
|
||||||
function user_avatar_set_from_path(int $userId, string $path, array $options = []): int {
|
function user_avatar_set_from_path(int $userId, string $path, array $options = []): int {
|
||||||
if(!file_exists($path)) {
|
if(!file_exists($path))
|
||||||
return MSZ_USER_AVATAR_ERROR_FILE_NOT_FOUND;
|
return MSZ_USER_AVATAR_ERROR_FILE_NOT_FOUND;
|
||||||
}
|
|
||||||
|
|
||||||
$options = array_merge(user_avatar_default_options(), $options);
|
$options = array_merge(user_avatar_default_options(), $options);
|
||||||
|
|
||||||
|
@ -89,22 +85,18 @@ function user_avatar_set_from_path(int $userId, string $path, array $options = [
|
||||||
if($imageInfo === false
|
if($imageInfo === false
|
||||||
|| count($imageInfo) < 3
|
|| count($imageInfo) < 3
|
||||||
|| $imageInfo[0] < 1
|
|| $imageInfo[0] < 1
|
||||||
|| $imageInfo[1] < 1) {
|
|| $imageInfo[1] < 1)
|
||||||
return MSZ_USER_AVATAR_ERROR_INVALID_IMAGE;
|
return MSZ_USER_AVATAR_ERROR_INVALID_IMAGE;
|
||||||
}
|
|
||||||
|
|
||||||
if(!user_avatar_is_allowed_type($imageInfo[2])) {
|
if(!user_avatar_is_allowed_type($imageInfo[2]))
|
||||||
return MSZ_USER_AVATAR_ERROR_PROHIBITED_TYPE;
|
return MSZ_USER_AVATAR_ERROR_PROHIBITED_TYPE;
|
||||||
}
|
|
||||||
|
|
||||||
if($imageInfo[0] > $options['max_width']
|
if($imageInfo[0] > $options['max_width']
|
||||||
|| $imageInfo[1] > $options['max_height']) {
|
|| $imageInfo[1] > $options['max_height'])
|
||||||
return MSZ_USER_AVATAR_ERROR_DIMENSIONS_TOO_LARGE;
|
return MSZ_USER_AVATAR_ERROR_DIMENSIONS_TOO_LARGE;
|
||||||
}
|
|
||||||
|
|
||||||
if(filesize($path) > $options['max_size']) {
|
if(filesize($path) > $options['max_size'])
|
||||||
return MSZ_USER_AVATAR_ERROR_DATA_TOO_LARGE;
|
return MSZ_USER_AVATAR_ERROR_DATA_TOO_LARGE;
|
||||||
}
|
|
||||||
|
|
||||||
user_avatar_delete($userId);
|
user_avatar_delete($userId);
|
||||||
|
|
||||||
|
@ -113,9 +105,8 @@ function user_avatar_set_from_path(int $userId, string $path, array $options = [
|
||||||
mkdirs($storageDir, true);
|
mkdirs($storageDir, true);
|
||||||
$avatarPath = "{$storageDir}/{$fileName}";
|
$avatarPath = "{$storageDir}/{$fileName}";
|
||||||
|
|
||||||
if(!copy($path, $avatarPath)) {
|
if(!copy($path, $avatarPath))
|
||||||
return MSZ_USER_AVATAR_ERROR_STORE_FAILED;
|
return MSZ_USER_AVATAR_ERROR_STORE_FAILED;
|
||||||
}
|
|
||||||
|
|
||||||
return MSZ_USER_AVATAR_NO_ERRORS;
|
return MSZ_USER_AVATAR_NO_ERRORS;
|
||||||
}
|
}
|
||||||
|
@ -123,9 +114,8 @@ function user_avatar_set_from_path(int $userId, string $path, array $options = [
|
||||||
function user_avatar_set_from_data(int $userId, string $data, array $options = []): int {
|
function user_avatar_set_from_data(int $userId, string $data, array $options = []): int {
|
||||||
$tmp = tempnam(sys_get_temp_dir(), 'msz');
|
$tmp = tempnam(sys_get_temp_dir(), 'msz');
|
||||||
|
|
||||||
if($tmp === false || !file_exists($tmp)) {
|
if($tmp === false || !file_exists($tmp))
|
||||||
return MSZ_USER_AVATAR_ERROR_TMP_FAILED;
|
return MSZ_USER_AVATAR_ERROR_TMP_FAILED;
|
||||||
}
|
|
||||||
|
|
||||||
chmod($tmp, 644);
|
chmod($tmp, 644);
|
||||||
file_put_contents($tmp, $data);
|
file_put_contents($tmp, $data);
|
||||||
|
|
|
@ -45,23 +45,19 @@ function user_background_settings_strings(int $settings, string $format = '%s'):
|
||||||
|
|
||||||
$attachment = $settings & 0x0F;
|
$attachment = $settings & 0x0F;
|
||||||
|
|
||||||
if(array_key_exists($attachment, MSZ_USER_BACKGROUND_ATTACHMENTS_NAMES)) {
|
if(array_key_exists($attachment, MSZ_USER_BACKGROUND_ATTACHMENTS_NAMES))
|
||||||
$arr[] = sprintf($format, MSZ_USER_BACKGROUND_ATTACHMENTS_NAMES[$attachment]);
|
$arr[] = sprintf($format, MSZ_USER_BACKGROUND_ATTACHMENTS_NAMES[$attachment]);
|
||||||
}
|
|
||||||
|
|
||||||
foreach(MSZ_USER_BACKGROUND_ATTRIBUTES_NAMES as $flag => $name) {
|
foreach(MSZ_USER_BACKGROUND_ATTRIBUTES_NAMES as $flag => $name)
|
||||||
if(($settings & $flag) > 0) {
|
if(($settings & $flag) > 0)
|
||||||
$arr[] = sprintf($format, $name);
|
$arr[] = sprintf($format, $name);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $arr;
|
return $arr;
|
||||||
}
|
}
|
||||||
|
|
||||||
function user_background_set_settings(int $userId, int $settings): void {
|
function user_background_set_settings(int $userId, int $settings): void {
|
||||||
if($userId < 1) {
|
if($userId < 1)
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
$setAttrs = \Misuzu\DB::prepare('
|
$setAttrs = \Misuzu\DB::prepare('
|
||||||
UPDATE `msz_users`
|
UPDATE `msz_users`
|
||||||
|
@ -109,9 +105,8 @@ define('MSZ_USER_BACKGROUND_ERROR_STORE_FAILED', 6);
|
||||||
define('MSZ_USER_BACKGROUND_ERROR_FILE_NOT_FOUND', 7);
|
define('MSZ_USER_BACKGROUND_ERROR_FILE_NOT_FOUND', 7);
|
||||||
|
|
||||||
function user_background_set_from_path(int $userId, string $path, array $options = []): int {
|
function user_background_set_from_path(int $userId, string $path, array $options = []): int {
|
||||||
if(!file_exists($path)) {
|
if(!file_exists($path))
|
||||||
return MSZ_USER_BACKGROUND_ERROR_FILE_NOT_FOUND;
|
return MSZ_USER_BACKGROUND_ERROR_FILE_NOT_FOUND;
|
||||||
}
|
|
||||||
|
|
||||||
$options = array_merge(user_background_default_options(), $options);
|
$options = array_merge(user_background_default_options(), $options);
|
||||||
|
|
||||||
|
@ -121,22 +116,18 @@ function user_background_set_from_path(int $userId, string $path, array $options
|
||||||
if($imageInfo === false
|
if($imageInfo === false
|
||||||
|| count($imageInfo) < 3
|
|| count($imageInfo) < 3
|
||||||
|| $imageInfo[0] < 1
|
|| $imageInfo[0] < 1
|
||||||
|| $imageInfo[1] < 1) {
|
|| $imageInfo[1] < 1)
|
||||||
return MSZ_USER_BACKGROUND_ERROR_INVALID_IMAGE;
|
return MSZ_USER_BACKGROUND_ERROR_INVALID_IMAGE;
|
||||||
}
|
|
||||||
|
|
||||||
if(!user_background_is_allowed_type($imageInfo[2])) {
|
if(!user_background_is_allowed_type($imageInfo[2]))
|
||||||
return MSZ_USER_BACKGROUND_ERROR_PROHIBITED_TYPE;
|
return MSZ_USER_BACKGROUND_ERROR_PROHIBITED_TYPE;
|
||||||
}
|
|
||||||
|
|
||||||
if($imageInfo[0] > $options['max_width']
|
if($imageInfo[0] > $options['max_width']
|
||||||
|| $imageInfo[1] > $options['max_height']) {
|
|| $imageInfo[1] > $options['max_height'])
|
||||||
return MSZ_USER_BACKGROUND_ERROR_DIMENSIONS_TOO_LARGE;
|
return MSZ_USER_BACKGROUND_ERROR_DIMENSIONS_TOO_LARGE;
|
||||||
}
|
|
||||||
|
|
||||||
if(filesize($path) > $options['max_size']) {
|
if(filesize($path) > $options['max_size'])
|
||||||
return MSZ_USER_BACKGROUND_ERROR_DATA_TOO_LARGE;
|
return MSZ_USER_BACKGROUND_ERROR_DATA_TOO_LARGE;
|
||||||
}
|
|
||||||
|
|
||||||
user_background_delete($userId);
|
user_background_delete($userId);
|
||||||
|
|
||||||
|
@ -145,9 +136,8 @@ function user_background_set_from_path(int $userId, string $path, array $options
|
||||||
mkdirs($storageDir, true);
|
mkdirs($storageDir, true);
|
||||||
$backgroundPath = "{$storageDir}/{$fileName}";
|
$backgroundPath = "{$storageDir}/{$fileName}";
|
||||||
|
|
||||||
if(!copy($path, $backgroundPath)) {
|
if(!copy($path, $backgroundPath))
|
||||||
return MSZ_USER_BACKGROUND_ERROR_STORE_FAILED;
|
return MSZ_USER_BACKGROUND_ERROR_STORE_FAILED;
|
||||||
}
|
|
||||||
|
|
||||||
return MSZ_USER_BACKGROUND_NO_ERRORS;
|
return MSZ_USER_BACKGROUND_NO_ERRORS;
|
||||||
}
|
}
|
||||||
|
@ -155,9 +145,8 @@ function user_background_set_from_path(int $userId, string $path, array $options
|
||||||
function user_background_set_from_data(int $userId, string $data, array $options = []): int {
|
function user_background_set_from_data(int $userId, string $data, array $options = []): int {
|
||||||
$tmp = tempnam(sys_get_temp_dir(), 'msz');
|
$tmp = tempnam(sys_get_temp_dir(), 'msz');
|
||||||
|
|
||||||
if($tmp === false || !file_exists($tmp)) {
|
if($tmp === false || !file_exists($tmp))
|
||||||
return MSZ_USER_BACKGROUND_ERROR_TMP_FAILED;
|
return MSZ_USER_BACKGROUND_ERROR_TMP_FAILED;
|
||||||
}
|
|
||||||
|
|
||||||
chmod($tmp, 644);
|
chmod($tmp, 644);
|
||||||
file_put_contents($tmp, $data);
|
file_put_contents($tmp, $data);
|
||||||
|
|
|
@ -14,13 +14,11 @@ function user_relation_is_valid_type(int $type): bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
function user_relation_set(int $userId, int $subjectId, int $type = MSZ_USER_RELATION_FOLLOW): bool {
|
function user_relation_set(int $userId, int $subjectId, int $type = MSZ_USER_RELATION_FOLLOW): bool {
|
||||||
if($type === MSZ_USER_RELATION_NONE) {
|
if($type === MSZ_USER_RELATION_NONE)
|
||||||
return user_relation_remove($userId, $subjectId);
|
return user_relation_remove($userId, $subjectId);
|
||||||
}
|
|
||||||
|
|
||||||
if($userId < 1 || $subjectId < 1 || !user_relation_is_valid_type($type)) {
|
if($userId < 1 || $subjectId < 1 || !user_relation_is_valid_type($type))
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
$addRelation = \Misuzu\DB::prepare('
|
$addRelation = \Misuzu\DB::prepare('
|
||||||
REPLACE INTO `msz_user_relations`
|
REPLACE INTO `msz_user_relations`
|
||||||
|
@ -37,9 +35,8 @@ function user_relation_set(int $userId, int $subjectId, int $type = MSZ_USER_REL
|
||||||
}
|
}
|
||||||
|
|
||||||
function user_relation_remove(int $userId, int $subjectId): bool {
|
function user_relation_remove(int $userId, int $subjectId): bool {
|
||||||
if($userId < 1 || $subjectId < 1) {
|
if($userId < 1 || $subjectId < 1)
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
$removeRelation = \Misuzu\DB::prepare('
|
$removeRelation = \Misuzu\DB::prepare('
|
||||||
DELETE FROM `msz_user_relations`
|
DELETE FROM `msz_user_relations`
|
||||||
|
@ -81,9 +78,8 @@ function user_relation_info(int $userId, int $subjectId): array {
|
||||||
}
|
}
|
||||||
|
|
||||||
function user_relation_count(int $userId, int $type, bool $from): int {
|
function user_relation_count(int $userId, int $type, bool $from): int {
|
||||||
if($userId < 1 || $type <= MSZ_USER_RELATION_NONE || !user_relation_is_valid_type($type)) {
|
if($userId < 1 || $type <= MSZ_USER_RELATION_NONE || !user_relation_is_valid_type($type))
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
static $getCount = [];
|
static $getCount = [];
|
||||||
$fetchCount = $getCount[$from] ?? null;
|
$fetchCount = $getCount[$from] ?? null;
|
||||||
|
@ -123,9 +119,8 @@ function user_relation_users(
|
||||||
int $offset = 0,
|
int $offset = 0,
|
||||||
int $requestingUserId = 0
|
int $requestingUserId = 0
|
||||||
): array {
|
): array {
|
||||||
if($userId < 1 || $type <= MSZ_USER_RELATION_NONE || !user_relation_is_valid_type($type)) {
|
if($userId < 1 || $type <= MSZ_USER_RELATION_NONE || !user_relation_is_valid_type($type))
|
||||||
return [];
|
return [];
|
||||||
}
|
|
||||||
|
|
||||||
$fetchAll = $take < 1;
|
$fetchAll = $take < 1;
|
||||||
$key = sprintf('%s,%s', $from ? 'from' : 'to', $fetchAll ? 'all' : 'page');
|
$key = sprintf('%s,%s', $from ? 'from' : 'to', $fetchAll ? 'all' : 'page');
|
||||||
|
|
|
@ -47,9 +47,8 @@ function user_role_has(int $userId, int $roleId): bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
function user_role_set_display(int $userId, int $roleId): bool {
|
function user_role_set_display(int $userId, int $roleId): bool {
|
||||||
if(!user_role_has($userId, $roleId)) {
|
if(!user_role_has($userId, $roleId))
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
$setDisplay = \Misuzu\DB::prepare('
|
$setDisplay = \Misuzu\DB::prepare('
|
||||||
UPDATE `msz_users`
|
UPDATE `msz_users`
|
||||||
|
@ -63,9 +62,8 @@ function user_role_set_display(int $userId, int $roleId): bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
function user_role_get_display(int $userId): int {
|
function user_role_get_display(int $userId): int {
|
||||||
if($userId < 1) {
|
if($userId < 1)
|
||||||
return MSZ_ROLE_MAIN;
|
return MSZ_ROLE_MAIN;
|
||||||
}
|
|
||||||
|
|
||||||
$fetchRole = \Misuzu\DB::prepare('
|
$fetchRole = \Misuzu\DB::prepare('
|
||||||
SELECT `display_role`
|
SELECT `display_role`
|
||||||
|
|
|
@ -41,9 +41,8 @@ function user_password_set(int $userId, string $password): bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
function user_totp_info(int $userId): array {
|
function user_totp_info(int $userId): array {
|
||||||
if($userId < 1) {
|
if($userId < 1)
|
||||||
return [];
|
return [];
|
||||||
}
|
|
||||||
|
|
||||||
$getTwoFactorInfo = \Misuzu\DB::prepare('
|
$getTwoFactorInfo = \Misuzu\DB::prepare('
|
||||||
SELECT
|
SELECT
|
||||||
|
@ -58,9 +57,8 @@ function user_totp_info(int $userId): array {
|
||||||
}
|
}
|
||||||
|
|
||||||
function user_totp_update(int $userId, ?string $key): void {
|
function user_totp_update(int $userId, ?string $key): void {
|
||||||
if($userId < 1) {
|
if($userId < 1)
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
$key = empty($key) ? null : $key;
|
$key = empty($key) ? null : $key;
|
||||||
|
|
||||||
|
@ -75,9 +73,8 @@ function user_totp_update(int $userId, ?string $key): void {
|
||||||
}
|
}
|
||||||
|
|
||||||
function user_email_get(int $userId): string {
|
function user_email_get(int $userId): string {
|
||||||
if($userId < 1) {
|
if($userId < 1)
|
||||||
return '';
|
return '';
|
||||||
}
|
|
||||||
|
|
||||||
$fetchMail = \Misuzu\DB::prepare('
|
$fetchMail = \Misuzu\DB::prepare('
|
||||||
SELECT `email`
|
SELECT `email`
|
||||||
|
@ -150,9 +147,8 @@ function user_check_super(int $userId): bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
function user_check_authority(int $userId, int $subjectId, bool $canManageSelf = true): bool {
|
function user_check_authority(int $userId, int $subjectId, bool $canManageSelf = true): bool {
|
||||||
if($canManageSelf && $userId === $subjectId) {
|
if($canManageSelf && $userId === $subjectId)
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
$checkHierarchy = \Misuzu\DB::prepare('
|
$checkHierarchy = \Misuzu\DB::prepare('
|
||||||
SELECT (
|
SELECT (
|
||||||
|
@ -193,25 +189,22 @@ define('MSZ_E_USER_BIRTHDATE_FAIL', 3);
|
||||||
define('MSZ_E_USER_BIRTHDATE_YEAR', 4);
|
define('MSZ_E_USER_BIRTHDATE_YEAR', 4);
|
||||||
|
|
||||||
function user_set_birthdate(int $userId, int $day, int $month, int $year, int $yearRange = 100): int {
|
function user_set_birthdate(int $userId, int $day, int $month, int $year, int $yearRange = 100): int {
|
||||||
if($userId < 1) {
|
if($userId < 1)
|
||||||
return MSZ_E_USER_BIRTHDATE_USER;
|
return MSZ_E_USER_BIRTHDATE_USER;
|
||||||
}
|
|
||||||
|
|
||||||
$unset = $day === 0 && $month === 0;
|
$unset = $day === 0 && $month === 0;
|
||||||
|
|
||||||
if($year === 0) {
|
if($year === 0) {
|
||||||
$checkYear = date('Y');
|
$checkYear = date('Y');
|
||||||
} else {
|
} else {
|
||||||
if($year < date('Y') - $yearRange || $year > date('Y')) {
|
if($year < date('Y') - $yearRange || $year > date('Y'))
|
||||||
return MSZ_E_USER_BIRTHDATE_YEAR;
|
return MSZ_E_USER_BIRTHDATE_YEAR;
|
||||||
}
|
|
||||||
|
|
||||||
$checkYear = $year;
|
$checkYear = $year;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!$unset && !checkdate($month, $day, $checkYear)) {
|
if(!$unset && !checkdate($month, $day, $checkYear))
|
||||||
return MSZ_E_USER_BIRTHDATE_DATE;
|
return MSZ_E_USER_BIRTHDATE_DATE;
|
||||||
}
|
|
||||||
|
|
||||||
$birthdate = $unset ? null : implode('-', [$year, $month, $day]);
|
$birthdate = $unset ? null : implode('-', [$year, $month, $day]);
|
||||||
$setBirthdate = \Misuzu\DB::prepare('
|
$setBirthdate = \Misuzu\DB::prepare('
|
||||||
|
@ -228,11 +221,7 @@ function user_set_birthdate(int $userId, int $day, int $month, int $year, int $y
|
||||||
}
|
}
|
||||||
|
|
||||||
function user_get_birthdays(int $day = 0, int $month = 0) {
|
function user_get_birthdays(int $day = 0, int $month = 0) {
|
||||||
if($day < 1 || $month < 1) {
|
$date = ($day < 1 || $month < 1) ? date('%-m-d') : "%-{$month}-{$day}";
|
||||||
$date = date('%-m-d');
|
|
||||||
} else {
|
|
||||||
$date = "%-{$month}-{$day}";
|
|
||||||
}
|
|
||||||
|
|
||||||
$getBirthdays = \Misuzu\DB::prepare('
|
$getBirthdays = \Misuzu\DB::prepare('
|
||||||
SELECT `user_id`, `username`, `user_birthdate`,
|
SELECT `user_id`, `username`, `user_birthdate`,
|
||||||
|
@ -254,19 +243,16 @@ define('MSZ_E_USER_ABOUT_TOO_LONG', 3);
|
||||||
define('MSZ_E_USER_ABOUT_UPDATE_FAILED', 4);
|
define('MSZ_E_USER_ABOUT_UPDATE_FAILED', 4);
|
||||||
|
|
||||||
function user_set_about_page(int $userId, string $content, int $parser = \Misuzu\Parsers\Parser::PLAIN): int {
|
function user_set_about_page(int $userId, string $content, int $parser = \Misuzu\Parsers\Parser::PLAIN): int {
|
||||||
if($userId < 1) {
|
if($userId < 1)
|
||||||
return MSZ_E_USER_ABOUT_INVALID_USER;
|
return MSZ_E_USER_ABOUT_INVALID_USER;
|
||||||
}
|
|
||||||
|
|
||||||
if(!\Misuzu\Parsers\Parser::isValid($parser)) {
|
if(!\Misuzu\Parsers\Parser::isValid($parser))
|
||||||
return MSZ_E_USER_ABOUT_INVALID_PARSER;
|
return MSZ_E_USER_ABOUT_INVALID_PARSER;
|
||||||
}
|
|
||||||
|
|
||||||
$length = strlen($content);
|
$length = strlen($content);
|
||||||
|
|
||||||
if($length > MSZ_USER_ABOUT_MAX_LENGTH) {
|
if($length > MSZ_USER_ABOUT_MAX_LENGTH)
|
||||||
return MSZ_E_USER_ABOUT_TOO_LONG;
|
return MSZ_E_USER_ABOUT_TOO_LONG;
|
||||||
}
|
|
||||||
|
|
||||||
$setAbout = \Misuzu\DB::prepare('
|
$setAbout = \Misuzu\DB::prepare('
|
||||||
UPDATE `msz_users`
|
UPDATE `msz_users`
|
||||||
|
@ -292,19 +278,16 @@ define('MSZ_E_USER_SIGNATURE_TOO_LONG', 3);
|
||||||
define('MSZ_E_USER_SIGNATURE_UPDATE_FAILED', 4);
|
define('MSZ_E_USER_SIGNATURE_UPDATE_FAILED', 4);
|
||||||
|
|
||||||
function user_set_signature(int $userId, string $content, int $parser = \Misuzu\Parsers\Parser::PLAIN): int {
|
function user_set_signature(int $userId, string $content, int $parser = \Misuzu\Parsers\Parser::PLAIN): int {
|
||||||
if($userId < 1) {
|
if($userId < 1)
|
||||||
return MSZ_E_USER_SIGNATURE_INVALID_USER;
|
return MSZ_E_USER_SIGNATURE_INVALID_USER;
|
||||||
}
|
|
||||||
|
|
||||||
if(!\Misuzu\Parsers\Parser::isValid($parser)) {
|
if(!\Misuzu\Parsers\Parser::isValid($parser))
|
||||||
return MSZ_E_USER_SIGNATURE_INVALID_PARSER;
|
return MSZ_E_USER_SIGNATURE_INVALID_PARSER;
|
||||||
}
|
|
||||||
|
|
||||||
$length = strlen($content);
|
$length = strlen($content);
|
||||||
|
|
||||||
if($length > MSZ_USER_SIGNATURE_MAX_LENGTH) {
|
if($length > MSZ_USER_SIGNATURE_MAX_LENGTH)
|
||||||
return MSZ_E_USER_SIGNATURE_TOO_LONG;
|
return MSZ_E_USER_SIGNATURE_TOO_LONG;
|
||||||
}
|
|
||||||
|
|
||||||
$setSignature = \Misuzu\DB::prepare('
|
$setSignature = \Misuzu\DB::prepare('
|
||||||
UPDATE `msz_users`
|
UPDATE `msz_users`
|
||||||
|
|
|
@ -58,21 +58,17 @@ function user_warning_add(
|
||||||
string $privateNote,
|
string $privateNote,
|
||||||
?int $duration = null
|
?int $duration = null
|
||||||
): int {
|
): int {
|
||||||
if(!user_warning_type_is_valid($type)) {
|
if(!user_warning_type_is_valid($type))
|
||||||
return MSZ_E_WARNING_ADD_TYPE;
|
return MSZ_E_WARNING_ADD_TYPE;
|
||||||
}
|
|
||||||
|
|
||||||
if($userId < 1) {
|
if($userId < 1)
|
||||||
return MSZ_E_WARNING_ADD_USER;
|
return MSZ_E_WARNING_ADD_USER;
|
||||||
}
|
|
||||||
|
|
||||||
if(user_warning_has_duration($type)) {
|
if(user_warning_has_duration($type)) {
|
||||||
if($duration <= time()) {
|
if($duration <= time())
|
||||||
return MSZ_E_WARNING_ADD_DURATION;
|
return MSZ_E_WARNING_ADD_DURATION;
|
||||||
}
|
} else
|
||||||
} else {
|
|
||||||
$duration = 0;
|
$duration = 0;
|
||||||
}
|
|
||||||
|
|
||||||
$addWarning = \Misuzu\DB::prepare('
|
$addWarning = \Misuzu\DB::prepare('
|
||||||
INSERT INTO `msz_user_warnings`
|
INSERT INTO `msz_user_warnings`
|
||||||
|
@ -89,17 +85,15 @@ function user_warning_add(
|
||||||
$addWarning->bind('note_private', $privateNote);
|
$addWarning->bind('note_private', $privateNote);
|
||||||
$addWarning->bind('duration', $duration < 1 ? null : date('Y-m-d H:i:s', $duration));
|
$addWarning->bind('duration', $duration < 1 ? null : date('Y-m-d H:i:s', $duration));
|
||||||
|
|
||||||
if(!$addWarning->execute()) {
|
if(!$addWarning->execute())
|
||||||
return MSZ_E_WARNING_ADD_DB;
|
return MSZ_E_WARNING_ADD_DB;
|
||||||
}
|
|
||||||
|
|
||||||
return \Misuzu\DB::lastId();
|
return \Misuzu\DB::lastId();
|
||||||
}
|
}
|
||||||
|
|
||||||
function user_warning_count(int $userId): int {
|
function user_warning_count(int $userId): int {
|
||||||
if($userId < 1) {
|
if($userId < 1)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
$countWarnings = \Misuzu\DB::prepare('
|
$countWarnings = \Misuzu\DB::prepare('
|
||||||
SELECT COUNT(`warning_id`)
|
SELECT COUNT(`warning_id`)
|
||||||
|
@ -111,9 +105,8 @@ function user_warning_count(int $userId): int {
|
||||||
}
|
}
|
||||||
|
|
||||||
function user_warning_remove(int $warningId): bool {
|
function user_warning_remove(int $warningId): bool {
|
||||||
if($warningId < 1) {
|
if($warningId < 1)
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
$removeWarning = \Misuzu\DB::prepare('
|
$removeWarning = \Misuzu\DB::prepare('
|
||||||
DELETE FROM `msz_user_warnings`
|
DELETE FROM `msz_user_warnings`
|
||||||
|
@ -148,9 +141,8 @@ function user_warning_fetch(
|
||||||
));
|
));
|
||||||
$fetchWarnings->bind('user_id', $userId);
|
$fetchWarnings->bind('user_id', $userId);
|
||||||
|
|
||||||
if($days !== null) {
|
if($days !== null)
|
||||||
$fetchWarnings->bind('days', $days);
|
$fetchWarnings->bind('days', $days);
|
||||||
}
|
|
||||||
|
|
||||||
return $fetchWarnings->fetchAll();
|
return $fetchWarnings->fetchAll();
|
||||||
}
|
}
|
||||||
|
@ -162,9 +154,8 @@ function user_warning_global_count(?int $userId = null): int {
|
||||||
%s
|
%s
|
||||||
', $userId > 0 ? 'WHERE `user_id` = :user_id' : ''));
|
', $userId > 0 ? 'WHERE `user_id` = :user_id' : ''));
|
||||||
|
|
||||||
if($userId > 0) {
|
if($userId > 0)
|
||||||
$countWarnings->bind('user_id', $userId);
|
$countWarnings->bind('user_id', $userId);
|
||||||
}
|
|
||||||
|
|
||||||
return (int)$countWarnings->fetchColumn(0, 0);
|
return (int)$countWarnings->fetchColumn(0, 0);
|
||||||
}
|
}
|
||||||
|
@ -191,9 +182,8 @@ function user_warning_global_fetch(int $offset = 0, int $take = 50, ?int $userId
|
||||||
$fetchWarnings->bind('offset', $offset);
|
$fetchWarnings->bind('offset', $offset);
|
||||||
$fetchWarnings->bind('take', $take);
|
$fetchWarnings->bind('take', $take);
|
||||||
|
|
||||||
if($userId > 0) {
|
if($userId > 0)
|
||||||
$fetchWarnings->bind('user_id', $userId);
|
$fetchWarnings->bind('user_id', $userId);
|
||||||
}
|
|
||||||
|
|
||||||
return $fetchWarnings->fetchAll();
|
return $fetchWarnings->fetchAll();
|
||||||
}
|
}
|
||||||
|
@ -215,16 +205,14 @@ function user_warning_check_ip(string $address): bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
function user_warning_check_expiration(int $userId, int $type): int {
|
function user_warning_check_expiration(int $userId, int $type): int {
|
||||||
if($userId < 1 || !user_warning_has_duration($type)) {
|
if($userId < 1 || !user_warning_has_duration($type))
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
static $memo = [];
|
static $memo = [];
|
||||||
$memoId = "{$userId}-{$type}";
|
$memoId = "{$userId}-{$type}";
|
||||||
|
|
||||||
if(array_key_exists($memoId, $memo)) {
|
if(array_key_exists($memoId, $memo))
|
||||||
return $memo[$memoId];
|
return $memo[$memoId];
|
||||||
}
|
|
||||||
|
|
||||||
$getExpiration = \Misuzu\DB::prepare('
|
$getExpiration = \Misuzu\DB::prepare('
|
||||||
SELECT `warning_duration`
|
SELECT `warning_duration`
|
||||||
|
@ -244,15 +232,13 @@ function user_warning_check_expiration(int $userId, int $type): int {
|
||||||
}
|
}
|
||||||
|
|
||||||
function user_warning_check_restriction(int $userId): bool {
|
function user_warning_check_restriction(int $userId): bool {
|
||||||
if($userId < 1) {
|
if($userId < 1)
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
static $memo = [];
|
static $memo = [];
|
||||||
|
|
||||||
if(array_key_exists($userId, $memo)) {
|
if(array_key_exists($userId, $memo))
|
||||||
return $memo[$userId];
|
return $memo[$userId];
|
||||||
}
|
|
||||||
|
|
||||||
$checkAddress = \Misuzu\DB::prepare(sprintf(
|
$checkAddress = \Misuzu\DB::prepare(sprintf(
|
||||||
'
|
'
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue