2022-09-13 13:14:49 +00:00
< ? php
namespace Misuzu ;
use InvalidArgumentException ;
2023-07-22 15:02:41 +00:00
use RuntimeException ;
2023-07-05 23:09:28 +00:00
use Index\ByteFormat ;
2023-08-02 22:12:47 +00:00
use Index\DateTime ;
2022-09-13 13:14:49 +00:00
use Misuzu\Parsers\Parser ;
use Misuzu\Users\User ;
2023-08-02 22:12:47 +00:00
use Misuzu\Users\Assets\UserAvatarAsset ;
2022-09-13 13:14:49 +00:00
use Misuzu\Users\Assets\UserBackgroundAsset ;
2023-04-29 21:57:21 +00:00
$userId = ! empty ( $_GET [ 'u' ]) && is_string ( $_GET [ 'u' ]) ? trim ( $_GET [ 'u' ]) : 0 ;
2022-09-13 13:14:49 +00:00
$profileMode = ! empty ( $_GET [ 'm' ]) && is_string ( $_GET [ 'm' ]) ? ( string ) $_GET [ 'm' ] : '' ;
$isEditing = ! empty ( $_GET [ 'edit' ]) && is_string ( $_GET [ 'edit' ]) ? ( bool ) $_GET [ 'edit' ] : ! empty ( $_POST ) && is_array ( $_POST );
2023-08-02 22:12:47 +00:00
$users = $msz -> getUsers ();
$viewerInfo = $msz -> getActiveUser ();
$viewingAsGuest = $viewerInfo === null ;
$viewerId = $viewingAsGuest ? '0' : $viewerInfo -> getId ();
2023-07-25 15:03:25 +00:00
2022-09-13 13:14:49 +00:00
try {
2023-08-02 22:12:47 +00:00
$userInfo = $users -> getUser ( $userId , 'profile' );
2023-07-22 15:02:41 +00:00
} catch ( RuntimeException $ex ) {
2022-09-13 13:14:49 +00:00
http_response_code ( 404 );
2023-07-25 15:03:25 +00:00
Template :: render ( 'profile.index' , [
'profile_is_guest' => $viewingAsGuest ,
'profile_is_deleted' => true ,
2023-08-02 22:12:47 +00:00
'profile_is_banned' => false ,
2023-07-25 15:03:25 +00:00
]);
2022-09-13 13:14:49 +00:00
return ;
}
2023-08-02 22:12:47 +00:00
if ( $userInfo -> isDeleted ()) {
2022-09-13 13:14:49 +00:00
http_response_code ( 404 );
2023-07-25 15:03:25 +00:00
Template :: render ( 'profile.index' , [
'profile_is_guest' => $viewingAsGuest ,
'profile_is_deleted' => true ,
2023-08-02 22:12:47 +00:00
'profile_is_banned' => false ,
2023-07-25 15:03:25 +00:00
]);
2022-09-13 13:14:49 +00:00
return ;
}
$notices = [];
2023-08-02 22:12:47 +00:00
$userRank = $users -> getUserRank ( $userInfo );
$viewerRank = $users -> getUserRank ( $viewerInfo );
$activeBanInfo = $msz -> tryGetActiveBan ( $userInfo );
2023-07-26 18:19:46 +00:00
$isBanned = $activeBanInfo !== null ;
2023-07-29 22:18:20 +00:00
$profileFields = $msz -> getProfileFields ();
2023-08-02 22:12:47 +00:00
$viewingOwnProfile = ( string ) $viewerId === $userInfo -> getId ();
$userPerms = perms_get_user ( $viewerId )[ MSZ_PERMS_USER ];
2022-09-13 13:14:49 +00:00
$canManageWarnings = perms_check ( $userPerms , MSZ_PERM_USER_MANAGE_WARNINGS );
2023-08-02 22:12:47 +00:00
$canEdit = ! $viewingAsGuest && (( ! $isBanned && $viewingOwnProfile ) || $viewerInfo -> isSuperUser () || (
2023-07-26 18:19:46 +00:00
perms_check ( $userPerms , MSZ_PERM_USER_MANAGE_USERS )
2023-08-02 22:12:47 +00:00
&& ( $viewingOwnProfile || $viewerRank > $userRank )
2023-07-26 18:19:46 +00:00
));
2023-08-02 22:12:47 +00:00
$avatarInfo = new UserAvatarAsset ( $userInfo );
$backgroundInfo = new UserBackgroundAsset ( $userInfo );
2022-09-13 13:14:49 +00:00
if ( $isEditing ) {
if ( ! $canEdit ) {
echo render_error ( 403 );
return ;
}
$perms = perms_check_bulk ( $userPerms , [
'edit_profile' => MSZ_PERM_USER_EDIT_PROFILE ,
'edit_avatar' => MSZ_PERM_USER_CHANGE_AVATAR ,
'edit_background' => MSZ_PERM_USER_CHANGE_BACKGROUND ,
'edit_about' => MSZ_PERM_USER_EDIT_ABOUT ,
'edit_birthdate' => MSZ_PERM_USER_EDIT_BIRTHDATE ,
'edit_signature' => MSZ_PERM_USER_EDIT_SIGNATURE ,
]);
Template :: set ([
'perms' => $perms ,
'background_attachments' => UserBackgroundAsset :: getAttachmentStringOptions (),
]);
if ( ! empty ( $_POST ) && is_array ( $_POST )) {
if ( ! CSRF :: validateRequest ()) {
$notices [] = 'Couldn\'t verify you, please refresh the page and retry.' ;
} else {
2023-07-20 19:36:43 +00:00
$profileFieldsSubmit = filter_input ( INPUT_POST , 'profile' , FILTER_DEFAULT , FILTER_REQUIRE_ARRAY );
if ( ! empty ( $profileFieldsSubmit )) {
2022-09-13 13:14:49 +00:00
if ( ! $perms [ 'edit_profile' ]) {
$notices [] = 'You\'re not allowed to edit your profile' ;
} else {
2023-07-20 19:36:43 +00:00
$profileFieldInfos = $profileFields -> getFields ();
$profileFieldsSetInfos = [];
$profileFieldsSetValues = [];
$profileFieldsRemove = [];
foreach ( $profileFieldInfos as $fieldInfo ) {
$fieldName = $fieldInfo -> getName ();
$fieldValue = empty ( $profileFieldsSubmit [ $fieldName ]) ? '' : ( string ) filter_var ( $profileFieldsSubmit [ $fieldName ]);
if ( empty ( $profileFieldsSubmit [ $fieldName ])) {
$profileFieldsRemove [] = $fieldInfo ;
continue ;
2022-09-13 13:14:49 +00:00
}
2023-07-20 19:36:43 +00:00
if ( $fieldInfo -> checkValue ( $fieldValue )) {
$profileFieldsSetInfos [] = $fieldInfo ;
$profileFieldsSetValues [] = $fieldValue ;
} else
$notices [] = sprintf ( '%s isn\'t properly formatted.' , $fieldInfo -> getTitle ());
2023-07-22 20:54:52 +00:00
unset ( $fieldName , $fieldValue , $fieldInfo );
2022-09-13 13:14:49 +00:00
}
2023-07-20 19:36:43 +00:00
if ( ! empty ( $profileFieldsRemove ))
2023-08-02 22:12:47 +00:00
$profileFields -> removeFieldValues ( $userInfo , $profileFieldsRemove );
2023-07-20 19:36:43 +00:00
if ( ! empty ( $profileFieldsSetInfos ))
2023-08-02 22:12:47 +00:00
$profileFields -> setFieldValues ( $userInfo , $profileFieldsSetInfos , $profileFieldsSetValues );
2022-09-13 13:14:49 +00:00
}
}
if ( ! empty ( $_POST [ 'about' ]) && is_array ( $_POST [ 'about' ])) {
if ( ! $perms [ 'edit_about' ]) {
$notices [] = 'You\'re not allowed to edit your about page.' ;
} else {
$aboutText = ( string )( $_POST [ 'about' ][ 'text' ] ? ? '' );
$aboutParse = ( int )( $_POST [ 'about' ][ 'parser' ] ? ? Parser :: PLAIN );
$aboutValid = User :: validateProfileAbout ( $aboutParse , $aboutText );
if ( $aboutValid === '' )
2023-08-02 22:12:47 +00:00
$users -> updateUser ( $userInfo , aboutContent : $aboutText , aboutParser : $aboutParse );
2022-09-13 13:14:49 +00:00
else switch ( $aboutValid ) {
case 'parser' :
$notices [] = 'The selected about section parser is invalid.' ;
break ;
case 'long' :
$notices [] = sprintf ( 'Please keep the length of your about section below %d characters.' , User :: PROFILE_ABOUT_MAX_LENGTH );
break ;
default :
$notices [] = 'Failed to update about section, contact an administator.' ;
break ;
}
}
}
if ( ! empty ( $_POST [ 'signature' ]) && is_array ( $_POST [ 'signature' ])) {
if ( ! $perms [ 'edit_signature' ]) {
$notices [] = 'You\'re not allowed to edit your forum signature.' ;
} else {
$sigText = ( string )( $_POST [ 'signature' ][ 'text' ] ? ? '' );
$sigParse = ( int )( $_POST [ 'signature' ][ 'parser' ] ? ? Parser :: PLAIN );
$sigValid = User :: validateForumSignature ( $sigParse , $sigText );
if ( $sigValid === '' )
2023-08-02 22:12:47 +00:00
$users -> updateUser ( $userInfo , signatureContent : $sigText , signatureParser : $sigParse );
2022-09-13 13:14:49 +00:00
else switch ( $sigValid ) {
case 'parser' :
$notices [] = 'The selected forum signature parser is invalid.' ;
break ;
case 'long' :
$notices [] = sprintf ( 'Please keep the length of your signature below %d characters.' , User :: FORUM_SIGNATURE_MAX_LENGTH );
break ;
default :
$notices [] = 'Failed to update signature, contact an administator.' ;
break ;
}
}
}
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 = User :: validateBirthdate ( $birthYear , $birthMonth , $birthDay );
if ( $birthValid === '' )
2023-08-02 22:12:47 +00:00
$users -> updateUser ( $userInfo , birthYear : $birthYear , birthMonth : $birthMonth , birthDay : $birthDay );
2022-09-13 13:14:49 +00:00
else switch ( $birthValid ) {
case 'year' :
$notices [] = 'The given birth year is invalid.' ;
break ;
case 'date' :
$notices [] = 'The given birthdate is invalid.' ;
break ;
default :
$notices [] = 'Something unexpected happened while setting your birthdate.' ;
break ;
}
}
}
if ( ! empty ( $_FILES [ 'avatar' ])) {
if ( ! empty ( $_POST [ 'avatar' ][ 'delete' ])) {
$avatarInfo -> 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 :
2023-07-05 23:09:28 +00:00
$notices [] = sprintf ( 'Your avatar is not allowed to be larger in file size than %s!' , ByteFormat :: format ( $avatarInfo -> getMaxBytes ()));
2022-09-13 13:14:49 +00:00
break ;
default :
$notices [] = 'Unable to save your avatar, contact an administator!' ;
break ;
}
} else {
try {
$avatarInfo -> setFromPath ( $_FILES [ 'avatar' ][ 'tmp_name' ][ 'file' ]);
2023-07-22 15:02:41 +00:00
} 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!' , $avatarInfo -> getMaxWidth (), $avatarInfo -> getMaxHeight ()),
'File size of $path is too large.' => sprintf ( 'Your avatar is not allowed to be larger in file size than %s!' , ByteFormat :: format ( $avatarInfo -> getMaxBytes ())),
default => $exMessage ,
};
} catch ( RuntimeException $ex ) {
2022-09-13 13:14:49 +00:00
$notices [] = 'Unable to save your avatar, contact an administator!' ;
}
}
}
}
}
if ( ! empty ( $_FILES [ 'background' ])) {
if (( int )( $_POST [ 'background' ][ 'attach' ] ? ? - 1 ) === 0 ) {
$backgroundInfo -> delete ();
} else {
if ( ! $perms [ 'edit_background' ]) {
$notices [] = 'You aren\'t allow to change your background.' ;
} elseif ( ! empty ( $_FILES [ 'background' ]) && is_array ( $_FILES [ 'background' ])) {
if ( ! empty ( $_FILES [ 'background' ][ 'name' ][ 'file' ])) {
if ( $_FILES [ 'background' ][ 'error' ][ 'file' ] !== UPLOAD_ERR_OK ) {
switch ( $_FILES [ 'background' ][ '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 :
2023-07-05 23:09:28 +00:00
$notices [] = sprintf ( 'Your background is not allowed to be larger in file size than %s!' , ByteFormat :: format ( $backgroundProps [ 'max_size' ]));
2022-09-13 13:14:49 +00:00
break ;
default :
$notices [] = 'Unable to save your background, contact an administator!' ;
break ;
}
} else {
try {
$backgroundInfo -> setFromPath ( $_FILES [ 'background' ][ 'tmp_name' ][ 'file' ]);
2023-07-22 15:02:41 +00:00
} 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!' , $backgroundInfo -> getMaxWidth (), $backgroundInfo -> getMaxHeight ()),
'File size of $path is too large.' => sprintf ( 'Your background is not allowed to be larger in file size than %2$s!' , ByteFormat :: format ( $backgroundInfo -> getMaxBytes ())),
default => $exMessage ,
};
} catch ( RuntimeException $ex ) {
2022-09-13 13:14:49 +00:00
$notices [] = 'Unable to save your background, contact an administator!' ;
}
}
}
$backgroundInfo -> setAttachment (( int )( $_POST [ 'background' ][ 'attach' ] ? ? 0 ))
-> setBlend ( ! empty ( $_POST [ 'background' ][ 'attr' ][ 'blend' ]))
-> setSlide ( ! empty ( $_POST [ 'background' ][ 'attr' ][ 'slide' ]));
}
}
2023-08-02 22:12:47 +00:00
$users -> updateUser ( $userInfo , backgroundSettings : $backgroundInfo -> getSettings ());
}
2022-09-13 13:14:49 +00:00
}
// Unset $isEditing and hope the user doesn't refresh their profile!
if ( empty ( $notices ))
$isEditing = false ;
}
}
$profileStats = DB :: prepare ( '
SELECT (
SELECT COUNT ( `topic_id` )
FROM `msz_forum_topics`
WHERE `user_id` = u . `user_id`
AND `topic_deleted` IS NULL
) AS `forum_topic_count` ,
(
SELECT COUNT ( `post_id` )
FROM `msz_forum_posts`
WHERE `user_id` = u . `user_id`
AND `post_deleted` IS NULL
) AS `forum_post_count` ,
(
SELECT COUNT ( `change_id` )
FROM `msz_changelog_changes`
WHERE `user_id` = u . `user_id`
) AS `changelog_count` ,
(
SELECT COUNT ( `comment_id` )
FROM `msz_comments_posts`
WHERE `user_id` = u . `user_id`
AND `comment_deleted` IS NULL
) AS `comments_count`
FROM `msz_users` AS u
WHERE `user_id` = : user_id
2023-08-02 22:12:47 +00:00
')->bind(' user_id ' , $userInfo -> getId ()) -> fetch ();
2022-09-13 13:14:49 +00:00
switch ( $profileMode ) {
default :
echo render_error ( 404 );
return ;
case 'forum-topics' :
$template = 'profile.topics' ;
2023-08-02 22:12:47 +00:00
$topicsCount = forum_topic_count_user ( $userInfo -> getId (), $viewerId );
2022-09-13 13:14:49 +00:00
$topicsPagination = new Pagination ( $topicsCount , 20 );
if ( ! $topicsPagination -> hasValidOffset ()) {
echo render_error ( 404 );
return ;
}
$topics = forum_topic_listing_user (
2023-08-02 22:12:47 +00:00
$userInfo -> getId (), $viewerId ,
2022-09-13 13:14:49 +00:00
$topicsPagination -> getOffset (), $topicsPagination -> getRange ()
);
Template :: set ([
2023-08-02 22:12:47 +00:00
'title' => $userInfo -> getName () . ' / topics' ,
'canonical_url' => url ( 'user-profile-forum-topics' , [ 'user' => $userInfo -> getId (), 'page' => Pagination :: param ()]),
2022-09-13 13:14:49 +00:00
'profile_topics' => $topics ,
'profile_topics_pagination' => $topicsPagination ,
]);
break ;
case 'forum-posts' :
$template = 'profile.posts' ;
2023-08-02 22:12:47 +00:00
$postsCount = forum_post_count_user ( $userInfo -> getId ());
2022-09-13 13:14:49 +00:00
$postsPagination = new Pagination ( $postsCount , 20 );
if ( ! $postsPagination -> hasValidOffset ()) {
echo render_error ( 404 );
return ;
}
$posts = forum_post_listing (
2023-08-02 22:12:47 +00:00
$userInfo -> getId (),
2022-09-13 13:14:49 +00:00
$postsPagination -> getOffset (),
$postsPagination -> getRange (),
false ,
true
);
Template :: set ([
2023-08-02 22:12:47 +00:00
'title' => $userInfo -> getName () . ' / posts' ,
'canonical_url' => url ( 'user-profile-forum-posts' , [ 'user' => $userInfo -> getId (), 'page' => Pagination :: param ()]),
2022-09-13 13:14:49 +00:00
'profile_posts' => $posts ,
'profile_posts_pagination' => $postsPagination ,
]);
break ;
case '' :
$template = 'profile.index' ;
2023-07-26 22:43:50 +00:00
if ( ! $viewingAsGuest ) {
2023-08-02 22:12:47 +00:00
Template :: set ( 'profile_warnings' , $msz -> getWarnings () -> getWarningsWithDefaultBacklog ( $userInfo ));
2023-07-20 19:36:43 +00:00
2023-07-26 22:43:50 +00:00
if (( ! $isBanned || $canEdit )) {
2023-08-02 22:12:47 +00:00
$activeCategoryStats = forum_get_user_most_active_category_info ( $userInfo -> getId ());
2023-07-26 22:43:50 +00:00
$activeCategoryInfo = empty ( $activeCategoryStats -> forum_id ) ? null : forum_get ( $activeCategoryStats -> forum_id );
2023-07-20 19:36:43 +00:00
2023-08-02 22:12:47 +00:00
$activeTopicStats = forum_get_user_most_active_topic_info ( $userInfo -> getId ());
2023-07-26 22:43:50 +00:00
$activeTopicInfo = empty ( $activeTopicStats -> topic_id ) ? null : forum_topic_get ( $activeTopicStats -> topic_id );
2023-07-20 19:36:43 +00:00
2023-08-02 22:12:47 +00:00
$profileFieldValues = $profileFields -> getFieldValues ( $userInfo );
2023-07-26 22:43:50 +00:00
$profileFieldInfos = $profileFieldInfos ? ? $profileFields -> getFields ( fieldValueInfos : $isEditing ? null : $profileFieldValues );
$profileFieldFormats = $profileFields -> getFieldFormats ( fieldValueInfos : $profileFieldValues );
2023-07-20 19:36:43 +00:00
2023-07-26 22:43:50 +00:00
$profileFieldRawValues = [];
$profileFieldLinkValues = [];
$profileFieldDisplayValues = [];
2023-07-22 21:25:45 +00:00
2023-07-26 22:43:50 +00:00
// using field infos as the basis for now, uses the correct ordering
foreach ( $profileFieldInfos as $fieldInfo ) {
unset ( $fieldValue );
2023-07-20 19:36:43 +00:00
2023-07-26 22:43:50 +00:00
foreach ( $profileFieldValues as $fieldValueTest )
if ( $fieldValueTest -> getFieldId () === $fieldInfo -> getId ()) {
$fieldValue = $fieldValueTest ;
2023-07-20 19:36:43 +00:00
break ;
}
2023-07-26 22:43:50 +00:00
$fieldName = $fieldInfo -> getName ();
if ( isset ( $fieldValue )) {
foreach ( $profileFieldFormats as $fieldFormatTest )
if ( $fieldFormatTest -> getId () === $fieldValue -> getFormatId ()) {
$fieldFormat = $fieldFormatTest ;
break ;
}
$profileFieldRawValues [ $fieldName ] = $fieldValue -> getValue ();
$profileFieldDisplayValues [ $fieldName ] = $fieldFormat -> formatDisplay ( $fieldValue -> getValue ());
if ( $fieldFormat -> hasLinkFormat ())
$profileFieldLinkValues [ $fieldName ] = $fieldFormat -> formatLink ( $fieldValue -> getValue ());
}
2023-07-20 19:36:43 +00:00
}
2023-07-26 22:43:50 +00:00
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 ,
]);
}
2023-07-20 19:36:43 +00:00
}
2022-09-13 13:14:49 +00:00
break ;
}
if ( ! empty ( $template )) {
Template :: render ( $template , [
2023-08-02 22:12:47 +00:00
'profile_viewer' => $viewerInfo ,
'profile_user' => $userInfo ,
'profile_colour' => $users -> getUserColour ( $userInfo ),
2022-09-13 13:14:49 +00:00
'profile_stats' => $profileStats ,
'profile_mode' => $profileMode ,
'profile_notices' => $notices ,
'profile_can_edit' => $canEdit ,
'profile_is_editing' => $isEditing ,
'profile_is_banned' => $isBanned ,
2023-07-20 19:36:43 +00:00
'profile_is_guest' => $viewingAsGuest ,
2023-07-25 15:03:25 +00:00
'profile_is_deleted' => false ,
2023-07-26 18:19:46 +00:00
'profile_ban_info' => $activeBanInfo ,
2023-08-02 22:12:47 +00:00
'profile_avatar_info' => $avatarInfo ,
'profile_background_info' => $backgroundInfo ,
2022-09-13 13:14:49 +00:00
]);
}