418 lines
20 KiB
PHP
418 lines
20 KiB
PHP
<?php
|
|
namespace Misuzu;
|
|
|
|
use stdClass;
|
|
use InvalidArgumentException;
|
|
use RuntimeException;
|
|
use Index\ByteFormat;
|
|
use Misuzu\Forum\ForumSignaturesData;
|
|
use Misuzu\Parsers\TextFormat;
|
|
use Misuzu\Profile\{ProfileAboutData,ProfileBackgroundAttach};
|
|
use Misuzu\Users\{User,UserBirthdatesData};
|
|
use Misuzu\Users\Assets\UserAvatarAsset;
|
|
use Misuzu\Users\Assets\UserBackgroundAsset;
|
|
|
|
if(!isset($msz) || !($msz instanceof \Misuzu\MisuzuContext))
|
|
die('Script must be called through the Misuzu route dispatcher.');
|
|
|
|
$userId = !empty($_GET['u']) && is_string($_GET['u']) ? trim($_GET['u']) : 0;
|
|
$profileMode = !empty($_GET['m']) && is_string($_GET['m']) ? (string)$_GET['m'] : '';
|
|
$isEditing = !empty($_GET['edit']) && is_string($_GET['edit']) ? (bool)$_GET['edit'] : !empty($_POST);
|
|
|
|
$viewerInfo = $msz->authInfo->userInfo;
|
|
$viewingAsGuest = $viewerInfo === null;
|
|
$viewerId = $viewingAsGuest ? '0' : $viewerInfo->id;
|
|
|
|
try {
|
|
$userInfo = $msz->usersCtx->getUserInfo($userId, 'profile');
|
|
} catch(RuntimeException $ex) {
|
|
$userId = $msz->usersCtx->namesHistory->resolvePastUserName($userId);
|
|
if($userId !== null) {
|
|
header(sprintf('Location: %s', $msz->urls->format('user-profile', ['user' => $userId])));
|
|
return;
|
|
}
|
|
|
|
http_response_code(404);
|
|
Template::render('profile.index', [
|
|
'profile_is_guest' => $viewingAsGuest,
|
|
'profile_is_deleted' => true,
|
|
'profile_is_banned' => false,
|
|
]);
|
|
return;
|
|
}
|
|
|
|
if($userInfo->deleted) {
|
|
http_response_code(404);
|
|
Template::render('profile.index', [
|
|
'profile_is_guest' => $viewingAsGuest,
|
|
'profile_is_deleted' => true,
|
|
'profile_is_banned' => false,
|
|
]);
|
|
return;
|
|
}
|
|
|
|
switch($profileMode) {
|
|
default:
|
|
Template::throwError(404);
|
|
|
|
case 'forum-topics':
|
|
Tools::redirect($msz->urls->format('search-query', ['query' => sprintf('type:forum:topic author:%s', $userInfo->name), 'section' => 'topics']));
|
|
return;
|
|
|
|
case 'forum-posts':
|
|
Tools::redirect($msz->urls->format('search-query', ['query' => sprintf('type:forum:post author:%s', $userInfo->name), 'section' => 'posts']));
|
|
return;
|
|
|
|
case '':
|
|
break;
|
|
}
|
|
|
|
$notices = [];
|
|
|
|
$userRank = $msz->usersCtx->getUserRank($userInfo);
|
|
$viewerRank = $msz->usersCtx->getUserRank($viewerInfo);
|
|
|
|
$viewerPermsGlobal = $msz->authInfo->getPerms('global');
|
|
$viewerPermsUser = $msz->authInfo->getPerms('user');
|
|
|
|
$activeBanInfo = $msz->usersCtx->tryGetActiveBan($userInfo);
|
|
$isBanned = $activeBanInfo !== null;
|
|
$viewingOwnProfile = (string)$viewerId === $userInfo->id;
|
|
$canManageWarnings = $viewerPermsUser->check(Perm::U_WARNINGS_MANAGE);
|
|
$canEdit = !$viewingAsGuest && ((!$isBanned && $viewingOwnProfile) || $viewerInfo->super || (
|
|
$viewerPermsUser->check(Perm::U_USERS_MANAGE) && ($viewingOwnProfile || $viewerRank > $userRank)
|
|
));
|
|
$avatarAsset = new UserAvatarAsset($userInfo);
|
|
$backgroundInfo = $msz->profileCtx->backgrounds->getProfileBackground($userInfo);
|
|
$backgroundAsset = new UserBackgroundAsset($userInfo);
|
|
|
|
$aboutInfo = $msz->profileCtx->about->getProfileAbout($userInfo);
|
|
$sigInfo = $msz->forumCtx->signatures->getSignature($userInfo);
|
|
|
|
if($isEditing) {
|
|
if(!$canEdit)
|
|
Template::throwError(403);
|
|
|
|
$perms = $viewerPermsUser->checkMany([
|
|
'edit_profile' => Perm::U_PROFILE_EDIT,
|
|
'edit_avatar' => Perm::U_AVATAR_CHANGE,
|
|
'edit_background' => Perm::U_PROFILE_BACKGROUND_CHANGE,
|
|
'edit_about' => Perm::U_PROFILE_ABOUT_EDIT,
|
|
'edit_birthdate' => Perm::U_PROFILE_BIRTHDATE_EDIT,
|
|
'edit_signature' => Perm::U_FORUM_SIGNATURE_EDIT,
|
|
]);
|
|
|
|
Template::set([
|
|
'perms' => $perms,
|
|
'birthdate_info' => $msz->usersCtx->birthdates->getUserBirthdate($userInfo),
|
|
]);
|
|
|
|
if(!empty($_POST)) {
|
|
if(!CSRF::validateRequest()) {
|
|
$notices[] = "Couldn't verify you, please refresh the page and retry.";
|
|
} else {
|
|
$profileFieldsSubmit = filter_input(INPUT_POST, 'profile', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY);
|
|
|
|
if(!empty($profileFieldsSubmit)) {
|
|
if(!$perms->edit_profile) {
|
|
$notices[] = "You're not allowed to edit your profile.";
|
|
} else {
|
|
$profileFieldInfos = iterator_to_array($msz->profileCtx->fields->getFields());
|
|
$profileFieldsSetInfos = [];
|
|
$profileFieldsSetValues = [];
|
|
$profileFieldsRemove = [];
|
|
|
|
foreach($profileFieldInfos as $fieldInfo) {
|
|
$fieldName = $fieldInfo->name;
|
|
$fieldValue = empty($profileFieldsSubmit[$fieldName]) ? '' : (string)filter_var($profileFieldsSubmit[$fieldName]);
|
|
|
|
if(empty($profileFieldsSubmit[$fieldName])) {
|
|
$profileFieldsRemove[] = $fieldInfo;
|
|
continue;
|
|
}
|
|
|
|
if($fieldInfo->checkValue($fieldValue)) {
|
|
$profileFieldsSetInfos[] = $fieldInfo;
|
|
$profileFieldsSetValues[] = $fieldValue;
|
|
} else
|
|
$notices[] = sprintf("%s isn't properly formatted.", $fieldInfo->title);
|
|
|
|
unset($fieldName, $fieldValue, $fieldInfo);
|
|
}
|
|
|
|
if(!empty($profileFieldsRemove))
|
|
$msz->profileCtx->fields->removeFieldValues($userInfo, $profileFieldsRemove);
|
|
if(!empty($profileFieldsSetInfos))
|
|
$msz->profileCtx->fields->setFieldValues($userInfo, $profileFieldsSetInfos, $profileFieldsSetValues);
|
|
}
|
|
}
|
|
|
|
if(filter_has_var(INPUT_POST, 'about_body')) {
|
|
if(!$perms->edit_about) {
|
|
$notices[] = "You're not allowed to edit your about page.";
|
|
} else {
|
|
$aboutBody = (string)filter_input(INPUT_POST, 'about_body');
|
|
if(trim($aboutBody) === '') {
|
|
$msz->profileCtx->about->deleteProfileAbout($userInfo);
|
|
$aboutInfo = null;
|
|
} else {
|
|
$aboutFormat = TextFormat::tryFrom(filter_input(INPUT_POST, 'about_format'));
|
|
$aboutValid = ProfileAboutData::validateProfileAbout($aboutFormat, $aboutBody);
|
|
if($aboutValid === '')
|
|
$aboutInfo = $msz->profileCtx->about->updateProfileAbout($userInfo, $aboutBody, $aboutFormat);
|
|
else
|
|
$notices[] = ProfileAboutData::validateProfileAboutText($aboutValid);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(filter_has_var(INPUT_POST, 'sig_body')) {
|
|
if(!$perms->edit_signature) {
|
|
$notices[] = "You're not allowed to edit your forum signature.";
|
|
} else {
|
|
$sigBody = (string)filter_input(INPUT_POST, 'sig_body');
|
|
if(trim($sigBody) === '') {
|
|
$msz->forumCtx->signatures->deleteSignature($userInfo);
|
|
$sigInfo = null;
|
|
} else {
|
|
$sigFormat = TextFormat::tryFrom(filter_input(INPUT_POST, 'sig_format'));
|
|
$sigValid = ForumSignaturesData::validateSignature($sigFormat, $sigBody);
|
|
if($sigValid === '')
|
|
$sigInfo = $msz->forumCtx->signatures->updateSignature($userInfo, $sigBody, $sigFormat);
|
|
else
|
|
$notices[] = ForumSignaturesData::validateSignatureText($sigValid);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(!empty($_POST['birthdate']) && is_array($_POST['birthdate'])) {
|
|
if(!$perms->edit_birthdate) {
|
|
$notices[] = "You aren't allow to change your birthdate.";
|
|
} else {
|
|
$birthYear = (int)($_POST['birthdate']['year'] ?? 0);
|
|
$birthMonth = (int)($_POST['birthdate']['month'] ?? 0);
|
|
$birthDay = (int)($_POST['birthdate']['day'] ?? 0);
|
|
$birthValid = UserBirthdatesData::validateBirthdate($birthYear, $birthMonth, $birthDay);
|
|
|
|
if($birthValid === '') {
|
|
if($birthMonth === 0 && $birthDay === 0)
|
|
$msz->usersCtx->birthdates->deleteUserBirthdate($userInfo);
|
|
else
|
|
$msz->usersCtx->birthdates->updateUserBirthdate($userInfo, $birthYear === 0 ? null : $birthYear, $birthMonth, $birthDay);
|
|
} else
|
|
$notices[] = UserBirthdatesData::validateBirthdateText($birthValid);
|
|
}
|
|
}
|
|
|
|
if(!empty($_FILES['avatar'])) {
|
|
if(!empty($_POST['avatar']['delete'])) {
|
|
$avatarAsset->delete();
|
|
} else {
|
|
if(!$perms->edit_avatar) {
|
|
$notices[] = "You aren't allow to change your avatar.";
|
|
} elseif(!empty($_FILES['avatar'])
|
|
&& is_array($_FILES['avatar'])
|
|
&& !empty($_FILES['avatar']['name']['file'])) {
|
|
if($_FILES['avatar']['error']['file'] !== UPLOAD_ERR_OK) {
|
|
switch($_FILES['avatar']['error']['file']) {
|
|
case UPLOAD_ERR_NO_FILE:
|
|
$notices[] = 'Select a file before hitting upload!';
|
|
break;
|
|
case UPLOAD_ERR_PARTIAL:
|
|
$notices[] = 'The upload was interrupted, please try again!';
|
|
break;
|
|
case UPLOAD_ERR_INI_SIZE:
|
|
case UPLOAD_ERR_FORM_SIZE:
|
|
$notices[] = sprintf('Your avatar is not allowed to be larger in file size than %s!', ByteFormat::format($avatarAsset->getMaxBytes()));
|
|
break;
|
|
default:
|
|
$notices[] = 'Unable to save your avatar, contact an administator!';
|
|
break;
|
|
}
|
|
} else {
|
|
try {
|
|
$avatarAsset->setFromPath($_FILES['avatar']['tmp_name']['file']);
|
|
} catch(InvalidArgumentException $ex) {
|
|
$exMessage = $ex->getMessage();
|
|
$notices[] = match($exMessage) {
|
|
'$path is not a valid image.' => 'The file you uploaded was not an image!',
|
|
'$path is not an allowed image file.' => 'This type of image is not supported, keep to PNG, JPG or GIF!',
|
|
'Dimensions of $path are too large.' => sprintf("Your avatar can't be larger than %dx%d!", $avatarAsset->getMaxWidth(), $avatarAsset->getMaxHeight()),
|
|
'File size of $path is too large.' => sprintf('Your avatar is not allowed to be larger in file size than %s!', ByteFormat::format($avatarAsset->getMaxBytes())),
|
|
default => $exMessage,
|
|
};
|
|
} catch(RuntimeException $ex) {
|
|
$notices[] = 'Unable to save your avatar, contact an administator!';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(filter_has_var(INPUT_POST, 'bg_attach')) {
|
|
$bgFormat = ProfileBackgroundAttach::tryFrom((string)filter_input(INPUT_POST, 'bg_attach'));
|
|
|
|
if($bgFormat === null) {
|
|
$backgroundAsset->delete();
|
|
$msz->profileCtx->backgrounds->deleteProfileBackground($userInfo);
|
|
$backgroundAsset = null;
|
|
} else {
|
|
if(!$perms->edit_background) {
|
|
$notices[] = "You aren't allow to change your background.";
|
|
} elseif(!empty($_FILES['bg_file']) && is_array($_FILES['bg_file'])) {
|
|
if(!empty($_FILES['bg_file']['name'])) {
|
|
if($_FILES['bg_file']['error'] !== UPLOAD_ERR_OK) {
|
|
switch($_FILES['bg_file']['error']) {
|
|
case UPLOAD_ERR_NO_FILE:
|
|
$notices[] = 'Select a file before hitting upload!';
|
|
break;
|
|
case UPLOAD_ERR_PARTIAL:
|
|
$notices[] = 'The upload was interrupted, please try again!';
|
|
break;
|
|
case UPLOAD_ERR_INI_SIZE:
|
|
case UPLOAD_ERR_FORM_SIZE:
|
|
$notices[] = sprintf('Your background is not allowed to be larger in file size than %s!', ByteFormat::format(isset($backgroundProps) && is_array($backgroundProps) ? $backgroundProps['max_size'] : 0));
|
|
break;
|
|
default:
|
|
$notices[] = 'Unable to save your background, contact an administator!';
|
|
break;
|
|
}
|
|
} else {
|
|
try {
|
|
$backgroundAsset->setFromPath($_FILES['bg_file']['tmp_name']);
|
|
} catch(InvalidArgumentException $ex) {
|
|
$exMessage = $ex->getMessage();
|
|
$notices[] = match($exMessage) {
|
|
'$path is not a valid image.' => 'The file you uploaded was not an image!',
|
|
'$path is not an allowed image file.' => 'This type of image is not supported, keep to PNG, JPG or GIF!',
|
|
'Dimensions of $path are too large.' => sprintf("Your background can't be larger than %dx%d!", $backgroundAsset->getMaxWidth(), $backgroundAsset->getMaxHeight()),
|
|
'File size of $path is too large.' => sprintf('Your background is not allowed to be larger in file size than %s!', ByteFormat::format($backgroundAsset->getMaxBytes())),
|
|
default => $exMessage,
|
|
};
|
|
} catch(RuntimeException $ex) {
|
|
$notices[] = 'Unable to save your background, contact an administator!';
|
|
}
|
|
}
|
|
}
|
|
|
|
$backgroundInfo = $msz->profileCtx->backgrounds->updateProfileBackground(
|
|
$userInfo,
|
|
$bgFormat,
|
|
filter_has_var(INPUT_POST, 'bg_blend'),
|
|
filter_has_var(INPUT_POST, 'bg_slide')
|
|
);
|
|
}
|
|
}
|
|
|
|
$backgroundAsset = new UserBackgroundAsset($userInfo);
|
|
}
|
|
}
|
|
|
|
// Unset $isEditing and hope the user doesn't refresh their profile!
|
|
if(empty($notices))
|
|
$isEditing = false;
|
|
}
|
|
}
|
|
|
|
// TODO: create user counters so these can be statically kept
|
|
$profileStats = new stdClass;
|
|
$profileStats->forum_topic_count = $msz->forumCtx->countTotalUserTopics($userInfo);
|
|
$profileStats->forum_post_count = $msz->forumCtx->countTotalUserPosts($userInfo);
|
|
$profileStats->comments_count = $msz->comments->countPosts(userInfo: $userInfo, deleted: false);
|
|
|
|
if(!$viewingAsGuest) {
|
|
Template::set('profile_warnings', iterator_to_array($msz->usersCtx->warnings->getWarningsWithDefaultBacklog($userInfo)));
|
|
|
|
if((!$isBanned || $canEdit)) {
|
|
$unranked = $msz->config->getValues([
|
|
'forum_leader.unranked.forum:a',
|
|
'forum_leader.unranked.topic:a',
|
|
]);
|
|
|
|
$activeCategoryStats = $msz->forumCtx->categories->getMostActiveCategoryInfo(
|
|
$userInfo,
|
|
$unranked['forum_leader.unranked.forum'],
|
|
$unranked['forum_leader.unranked.topic'],
|
|
deleted: false
|
|
);
|
|
$activeCategoryInfo = $activeCategoryStats->success ? $msz->forumCtx->categories->getCategory(categoryId: $activeCategoryStats->categoryId) : null;
|
|
|
|
$activeTopicStats = $msz->forumCtx->topics->getMostActiveTopicInfo(
|
|
$userInfo,
|
|
$unranked['forum_leader.unranked.forum'],
|
|
$unranked['forum_leader.unranked.topic'],
|
|
deleted: false
|
|
);
|
|
$activeTopicInfo = $activeTopicStats->success ? $msz->forumCtx->topics->getTopic(topicId: $activeTopicStats->topicId) : null;
|
|
|
|
$profileFieldValues = iterator_to_array($msz->profileCtx->fields->getFieldValues($userInfo));
|
|
$profileFieldInfos = $profileFieldInfos ?? iterator_to_array($msz->profileCtx->fields->getFields(fieldValueInfos: $isEditing ? null : $profileFieldValues));
|
|
$profileFieldFormats = iterator_to_array($msz->profileCtx->fields->getFieldFormats(fieldValueInfos: $profileFieldValues));
|
|
|
|
$profileFieldRawValues = [];
|
|
$profileFieldLinkValues = [];
|
|
$profileFieldDisplayValues = [];
|
|
|
|
// using field infos as the basis for now, uses the correct ordering
|
|
foreach($profileFieldInfos as $fieldInfo) {
|
|
unset($fieldValue);
|
|
|
|
foreach($profileFieldValues as $fieldValueTest)
|
|
if($fieldValueTest->fieldId === $fieldInfo->id) {
|
|
$fieldValue = $fieldValueTest;
|
|
break;
|
|
}
|
|
|
|
$fieldName = $fieldInfo->name;
|
|
|
|
if(isset($fieldValue)) {
|
|
foreach($profileFieldFormats as $fieldFormatTest)
|
|
if($fieldFormatTest->id === $fieldValue->formatId) {
|
|
$fieldFormat = $fieldFormatTest;
|
|
break;
|
|
}
|
|
|
|
if(!isset($fieldFormat))
|
|
continue;
|
|
|
|
$profileFieldRawValues[$fieldName] = $fieldValue->value;
|
|
$profileFieldDisplayValues[$fieldName] = $fieldFormat->formatDisplay($fieldValue->value);
|
|
if($fieldFormat->linkFormat !== null)
|
|
$profileFieldLinkValues[$fieldName] = $fieldFormat->formatLink($fieldValue->value);
|
|
}
|
|
}
|
|
|
|
Template::set([
|
|
'profile_active_category_stats' => $activeCategoryStats,
|
|
'profile_active_category_info' => $activeCategoryInfo,
|
|
'profile_active_topic_stats' => $activeTopicStats,
|
|
'profile_active_topic_info' => $activeTopicInfo,
|
|
'profile_fields_infos' => $profileFieldInfos,
|
|
'profile_fields_raw_values' => $profileFieldRawValues,
|
|
'profile_fields_display_values' => $profileFieldDisplayValues,
|
|
'profile_fields_link_values' => $profileFieldLinkValues,
|
|
]);
|
|
}
|
|
}
|
|
|
|
Template::render('profile.index', [
|
|
'profile_viewer' => $viewerInfo,
|
|
'profile_user' => $userInfo,
|
|
'profile_colour' => $msz->usersCtx->getUserColour($userInfo),
|
|
'profile_stats' => $profileStats,
|
|
'profile_mode' => $profileMode,
|
|
'profile_notices' => $notices,
|
|
'profile_can_edit' => $canEdit,
|
|
'profile_is_editing' => $isEditing,
|
|
'profile_is_banned' => $isBanned,
|
|
'profile_is_guest' => $viewingAsGuest,
|
|
'profile_is_deleted' => false,
|
|
'profile_ban_info' => $activeBanInfo,
|
|
'profile_avatar_asset' => $avatarAsset,
|
|
'profile_background_info' => $backgroundInfo,
|
|
'profile_background_asset' => $backgroundAsset,
|
|
'profile_can_send_messages' => $viewerPermsGlobal->check(Perm::G_MESSAGES_SEND),
|
|
'profile_age' => $msz->usersCtx->birthdates->getUserAge($userInfo),
|
|
'profile_about_info' => $aboutInfo,
|
|
'profile_forum_signature_info' => $sigInfo,
|
|
]);
|