2022-09-13 13:14:49 +00:00
< ? php
namespace Misuzu ;
2023-08-31 00:24:59 +00:00
use stdClass ;
2022-09-13 13:14:49 +00:00
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-09-08 20:40:48 +00:00
$urls = $msz -> getURLs ();
2023-09-06 13:50:19 +00:00
$usersCtx = $msz -> getUsersContext ();
$users = $usersCtx -> getUsers ();
2023-09-08 13:22:46 +00:00
$forumCtx = $msz -> getForumContext ();
$forumCategories = $forumCtx -> getCategories ();
$forumTopics = $forumCtx -> getTopics ();
$forumPosts = $forumCtx -> getPosts ();
2023-08-02 22:12:47 +00:00
2023-09-06 20:06:07 +00:00
$authInfo = $msz -> getAuthInfo ();
$viewerInfo = $authInfo -> getUserInfo ();
2023-08-02 22:12:47 +00:00
$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-09-06 13:50:19 +00:00
$userInfo = $usersCtx -> getUserInfo ( $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 ;
}
2023-08-28 01:17:34 +00:00
switch ( $profileMode ) {
default :
2023-08-31 15:59:53 +00:00
Template :: throwError ( 404 );
2023-08-28 01:17:34 +00:00
case 'forum-topics' :
2023-09-08 20:40:48 +00:00
Tools :: redirect ( $urls -> format ( 'search-query' , [ 'query' => sprintf ( 'type:forum:topic author:%s' , $userInfo -> getName ()), 'section' => 'topics' ]));
2023-08-28 01:17:34 +00:00
return ;
case 'forum-posts' :
2023-09-08 20:40:48 +00:00
Tools :: redirect ( $urls -> format ( 'search-query' , [ 'query' => sprintf ( 'type:forum:post author:%s' , $userInfo -> getName ()), 'section' => 'posts' ]));
2023-08-28 01:17:34 +00:00
return ;
case '' :
break ;
}
2022-09-13 13:14:49 +00:00
$notices = [];
2023-09-06 13:50:19 +00:00
$userRank = $usersCtx -> getUserRank ( $userInfo );
$viewerRank = $usersCtx -> getUserRank ( $viewerInfo );
2023-08-02 22:12:47 +00:00
2024-01-30 23:47:02 +00:00
$viewerPermsGlobal = $authInfo -> getPerms ( 'global' );
$viewerPermsUser = $authInfo -> getPerms ( 'user' );
2023-08-30 22:37:21 +00:00
2023-09-06 20:06:07 +00:00
$activeBanInfo = $usersCtx -> 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 ();
2024-01-30 23:47:02 +00:00
$canManageWarnings = $viewerPermsUser -> check ( Perm :: U_WARNINGS_MANAGE );
2023-08-02 22:12:47 +00:00
$canEdit = ! $viewingAsGuest && (( ! $isBanned && $viewingOwnProfile ) || $viewerInfo -> isSuperUser () || (
2024-01-30 23:47:02 +00:00
$viewerPermsUser -> check ( Perm :: U_USERS_MANAGE ) && ( $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 ) {
2023-08-31 15:59:53 +00:00
if ( ! $canEdit )
Template :: throwError ( 403 );
2022-09-13 13:14:49 +00:00
2024-01-30 23:47:02 +00:00
$perms = $viewerPermsUser -> checkMany ([
2023-08-30 22:37:21 +00:00
'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 ,
2022-09-13 13:14:49 +00:00
]);
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 )) {
2023-08-30 22:37:21 +00:00
if ( ! $perms -> edit_profile ) {
2022-09-13 13:14:49 +00:00
$notices [] = 'You\'re not allowed to edit your profile' ;
} else {
2024-02-11 02:22:22 +00:00
$profileFieldInfos = iterator_to_array ( $profileFields -> getFields ());
2023-07-20 19:36:43 +00:00
$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' ])) {
2023-08-30 22:37:21 +00:00
if ( ! $perms -> edit_about ) {
2022-09-13 13:14:49 +00:00
$notices [] = 'You\'re not allowed to edit your about page.' ;
} else {
$aboutText = ( string )( $_POST [ 'about' ][ 'text' ] ? ? '' );
$aboutParse = ( int )( $_POST [ 'about' ][ 'parser' ] ? ? Parser :: PLAIN );
2023-08-30 23:41:44 +00:00
$aboutValid = $users -> validateProfileAbout ( $aboutParse , $aboutText );
2022-09-13 13:14:49 +00:00
if ( $aboutValid === '' )
2023-08-02 22:12:47 +00:00
$users -> updateUser ( $userInfo , aboutContent : $aboutText , aboutParser : $aboutParse );
2023-08-30 23:41:44 +00:00
else
$notices [] = $users -> validateProfileAboutText ( $aboutValid );
2022-09-13 13:14:49 +00:00
}
}
if ( ! empty ( $_POST [ 'signature' ]) && is_array ( $_POST [ 'signature' ])) {
2023-08-30 22:37:21 +00:00
if ( ! $perms -> edit_signature ) {
2022-09-13 13:14:49 +00:00
$notices [] = 'You\'re not allowed to edit your forum signature.' ;
} else {
$sigText = ( string )( $_POST [ 'signature' ][ 'text' ] ? ? '' );
$sigParse = ( int )( $_POST [ 'signature' ][ 'parser' ] ? ? Parser :: PLAIN );
2023-08-30 23:41:44 +00:00
$sigValid = $users -> validateForumSignature ( $sigParse , $sigText );
2022-09-13 13:14:49 +00:00
if ( $sigValid === '' )
2023-08-02 22:12:47 +00:00
$users -> updateUser ( $userInfo , signatureContent : $sigText , signatureParser : $sigParse );
2023-08-30 23:41:44 +00:00
else
$notices [] = $users -> validateForumSignatureText ( $sigValid );
2022-09-13 13:14:49 +00:00
}
}
if ( ! empty ( $_POST [ 'birthdate' ]) && is_array ( $_POST [ 'birthdate' ])) {
2023-08-30 22:37:21 +00:00
if ( ! $perms -> edit_birthdate ) {
2022-09-13 13:14:49 +00:00
$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 );
2023-08-30 23:41:44 +00:00
$birthValid = $users -> validateBirthdate ( $birthYear , $birthMonth , $birthDay );
2022-09-13 13:14:49 +00:00
if ( $birthValid === '' )
2023-08-02 22:12:47 +00:00
$users -> updateUser ( $userInfo , birthYear : $birthYear , birthMonth : $birthMonth , birthDay : $birthDay );
2023-08-30 23:41:44 +00:00
else
$notices [] = $users -> validateBirthdateText ( $birthValid );
2022-09-13 13:14:49 +00:00
}
}
if ( ! empty ( $_FILES [ 'avatar' ])) {
if ( ! empty ( $_POST [ 'avatar' ][ 'delete' ])) {
$avatarInfo -> delete ();
} else {
2023-08-30 22:37:21 +00:00
if ( ! $perms -> edit_avatar ) {
2022-09-13 13:14:49 +00:00
$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 {
2023-08-30 22:37:21 +00:00
if ( ! $perms -> edit_background ) {
2022-09-13 13:14:49 +00:00
$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 ;
}
}
2023-08-31 00:24:59 +00:00
// TODO: create user counters so these can be statically kept
$profileStats = new stdClass ;
2023-09-08 13:22:46 +00:00
$profileStats -> forum_topic_count = $forumCtx -> countTotalUserTopics ( $userInfo );
$profileStats -> forum_post_count = $forumCtx -> countTotalUserPosts ( $userInfo );
2023-08-31 00:24:59 +00:00
$profileStats -> comments_count = $msz -> getComments () -> countPosts ( userInfo : $userInfo , deleted : false );
2022-09-13 13:14:49 +00:00
2023-08-28 01:17:34 +00:00
if ( ! $viewingAsGuest ) {
2024-02-07 00:04:45 +00:00
Template :: set ( 'profile_warnings' , iterator_to_array ( $usersCtx -> getWarnings () -> getWarningsWithDefaultBacklog ( $userInfo )));
2022-09-13 13:14:49 +00:00
2023-08-28 01:17:34 +00:00
if (( ! $isBanned || $canEdit )) {
$unranked = $cfg -> getValues ([
'forum_leader.unranked.forum:a' ,
'forum_leader.unranked.topic:a' ,
2022-09-13 13:14:49 +00:00
]);
2023-09-08 13:22:46 +00:00
$activeCategoryStats = $forumCategories -> getMostActiveCategoryInfo (
2023-08-28 01:17:34 +00:00
$userInfo ,
$unranked [ 'forum_leader.unranked.forum' ],
$unranked [ 'forum_leader.unranked.topic' ],
deleted : false
2022-09-13 13:14:49 +00:00
);
2023-09-08 13:22:46 +00:00
$activeCategoryInfo = $activeCategoryStats -> success ? $forumCategories -> getCategory ( categoryId : $activeCategoryStats -> categoryId ) : null ;
2022-09-13 13:14:49 +00:00
2023-09-08 13:22:46 +00:00
$activeTopicStats = $forumTopics -> getMostActiveTopicInfo (
2023-08-28 01:17:34 +00:00
$userInfo ,
$unranked [ 'forum_leader.unranked.forum' ],
$unranked [ 'forum_leader.unranked.topic' ],
deleted : false
);
2023-09-08 13:22:46 +00:00
$activeTopicInfo = $activeTopicStats -> success ? $forumTopics -> getTopic ( topicId : $activeTopicStats -> topicId ) : null ;
2023-07-20 19:36:43 +00:00
2024-02-11 02:22:22 +00:00
$profileFieldValues = iterator_to_array ( $profileFields -> getFieldValues ( $userInfo ));
$profileFieldInfos = $profileFieldInfos ? ? iterator_to_array ( $profileFields -> getFields ( fieldValueInfos : $isEditing ? null : $profileFieldValues ));
$profileFieldFormats = iterator_to_array ( $profileFields -> getFieldFormats ( fieldValueInfos : $profileFieldValues ));
2023-07-20 19:36:43 +00:00
2023-08-28 01:17:34 +00:00
$profileFieldRawValues = [];
$profileFieldLinkValues = [];
$profileFieldDisplayValues = [];
2023-07-22 21:25:45 +00:00
2023-08-28 01:17:34 +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-08-28 01:17:34 +00:00
foreach ( $profileFieldValues as $fieldValueTest )
if ( $fieldValueTest -> getFieldId () === $fieldInfo -> getId ()) {
$fieldValue = $fieldValueTest ;
break ;
}
2023-07-26 22:43:50 +00:00
2023-08-28 01:17:34 +00:00
$fieldName = $fieldInfo -> getName ();
2023-07-26 22:43:50 +00:00
2023-08-28 01:17:34 +00:00
if ( isset ( $fieldValue )) {
foreach ( $profileFieldFormats as $fieldFormatTest )
if ( $fieldFormatTest -> getId () === $fieldValue -> getFormatId ()) {
$fieldFormat = $fieldFormatTest ;
break ;
2023-07-26 22:43:50 +00:00
}
2023-07-20 19:36:43 +00:00
2023-08-28 01:17:34 +00:00
$profileFieldRawValues [ $fieldName ] = $fieldValue -> getValue ();
$profileFieldDisplayValues [ $fieldName ] = $fieldFormat -> formatDisplay ( $fieldValue -> getValue ());
if ( $fieldFormat -> hasLinkFormat ())
$profileFieldLinkValues [ $fieldName ] = $fieldFormat -> formatLink ( $fieldValue -> getValue ());
2023-07-26 22:43:50 +00:00
}
2023-07-20 19:36:43 +00:00
}
2022-09-13 13:14:49 +00:00
2023-08-28 01:17:34 +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 ,
]);
}
2022-09-13 13:14:49 +00:00
}
2023-08-28 01:17:34 +00:00
Template :: render ( 'profile.index' , [
'profile_viewer' => $viewerInfo ,
'profile_user' => $userInfo ,
2023-09-06 13:50:19 +00:00
'profile_colour' => $usersCtx -> getUserColour ( $userInfo ),
2023-08-28 01:17:34 +00:00
'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_info' => $avatarInfo ,
'profile_background_info' => $backgroundInfo ,
2024-01-30 23:47:02 +00:00
'profile_can_send_messages' => $viewerPermsGlobal -> check ( Perm :: G_MESSAGES_SEND ),
2023-08-28 01:17:34 +00:00
]);