Refactored privilege system a bit

- Jobs specify main privilege and sub privileges separately
  Rationale: increase maintenance, restrict what can be done runtime
- Renamed ChangeUser* to EditUser* (consistency with EditPost*)
- Simplified enum names and configuration reading
- IJob interface members must be explicitly implemented
  Rationale: reduce chances of forgetting something, or typos in
  inherited method names
- Invalid privileges names in configuration yield exceptions
This commit is contained in:
Marcin Kurczewski 2014-05-17 15:00:30 +02:00
parent 2a7b7e7ac2
commit e59b7e8b7b
69 changed files with 984 additions and 381 deletions

View file

@ -120,15 +120,15 @@ listUsers=registered
viewUser=registered
viewUserEmail.all=admin
viewUserEmail.own=registered
changeUserPassword.own=registered
changeUserPassword.all=admin
changeUserEmail.own=registered
changeUserEmail.all=admin
changeUserEmailNoConfirm=admin
changeUserAccessRank=admin
changeUserName=moderator
changeUserSettings.all=nobody
changeUserSettings.own=registered
editUserPassword.own=registered
editUserPassword.all=admin
editUserEmail.own=registered
editUserEmail.all=admin
editUserEmailNoConfirm=admin
editUserAccessRank=admin
editUserName=moderator
editUserSettings.all=nobody
editUserSettings.own=registered
acceptUserRegistration=moderator
banUser.own=nobody
banUser.all=admin

View file

@ -13,15 +13,11 @@ class Access
$key .= '.';
list ($privilegeName, $subPrivilegeName) = explode('.', $key);
$privilegeName = TextCaseConverter::convert($privilegeName,
TextCaseConverter::CAMEL_CASE,
TextCaseConverter::SPINAL_CASE);
$subPrivilegeName = TextCaseConverter::convert($subPrivilegeName,
TextCaseConverter::CAMEL_CASE,
TextCaseConverter::SPINAL_CASE);
$key = rtrim($privilegeName . '.' . $subPrivilegeName, '.');
if (!in_array($privilegeName, Privilege::getAllConstants()))
throw new Exception('Invalid privilege name in config: ' . $privilegeName);
$minAccessRank = TextHelper::resolveConstant($minAccessRankName, 'AccessRank');
self::$privileges[$key] = $minAccessRank;
@ -46,14 +42,9 @@ class Access
$minAccessRank = AccessRank::Nobody;
$key = TextCaseConverter::convert($privilege->toString(),
TextCaseConverter::CAMEL_CASE,
TextCaseConverter::SPINAL_CASE);
$key = $privilege->toString();
$privilege->secondary = null;
$key2 = TextCaseConverter::convert($privilege->toString(),
TextCaseConverter::CAMEL_CASE,
TextCaseConverter::SPINAL_CASE);
$key2 = $privilege->toString();
if (isset(self::$privileges[$key]))
$minAccessRank = self::$privileges[$key];
@ -85,7 +76,7 @@ class Access
public static function assert(Privilege $privilege, $user = null)
{
if (!self::check($privilege, $user))
self::fail('Insufficient privileges (' . $privilege->toString() . ')');
self::fail('Insufficient privileges (' . $privilege->toDisplayString() . ')');
}
public static function assertEmailConfirmation($user = null)

View file

@ -51,14 +51,16 @@ final class Api
if ($job->isConfirmedEmailRequired())
Access::assertEmailConfirmation();
$privileges = $job->getRequiredPrivileges();
if ($privileges !== false)
{
if (!is_array($privileges))
$privileges = [$privileges];
$mainPrivilege = $job->getRequiredMainPrivilege();
$subPrivileges = $job->getRequiredSubPrivileges();
if (!is_array($subPrivileges))
$subPrivileges = [$subPrivileges];
foreach ($privileges as $privilege)
Access::assert($privilege);
if ($mainPrivilege !== null)
{
Access::assert(new Privilege($mainPrivilege));
foreach ($subPrivileges as $subPrivilege)
Access::assert(new Privilege($mainPrivilege, $subPrivilege));
}
}

View file

@ -38,21 +38,6 @@ abstract class AbstractJob implements IJob
return $this->subJobs;
}
public function getRequiredPrivileges()
{
return false;
}
public function isAuthenticationRequired()
{
return false;
}
public function isConfirmedEmailRequired()
{
return false;
}
public function getContext()
{
return $this->context;

View file

@ -35,9 +35,14 @@ class AddCommentJob extends AbstractJob
JobArgs::ARG_NEW_TEXT);
}
public function getRequiredPrivileges()
public function getRequiredMainPrivilege()
{
return new Privilege(Privilege::AddComment);
return Privilege::AddComment;
}
public function getRequiredSubPrivileges()
{
return null;
}
public function isAuthenticationRequired()

View file

@ -25,11 +25,14 @@ class DeleteCommentJob extends AbstractJob
return $this->commentRetriever->getRequiredArguments();
}
public function getRequiredPrivileges()
public function getRequiredMainPrivilege()
{
return new Privilege(
Privilege::DeleteComment,
Access::getIdentity($this->commentRetriever->retrieve()->getCommenter()));
return Privilege::DeleteComment;
}
public function getRequiredSubPrivileges()
{
return Access::getIdentity($this->commentRetriever->retrieve()->getCommenter());
}
public function isAuthenticationRequired()

View file

@ -30,11 +30,14 @@ class EditCommentJob extends AbstractJob
JobArgs::ARG_NEW_TEXT);
}
public function getRequiredPrivileges()
public function getRequiredMainPrivilege()
{
return new Privilege(
Privilege::EditComment,
Access::getIdentity($this->commentRetriever->retrieve()->getCommenter()));
return Privilege::EditComment;
}
public function getRequiredSubPrivileges()
{
return Access::getIdentity($this->commentRetriever->retrieve()->getCommenter());
}
public function isAuthenticationRequired()

View file

@ -38,8 +38,23 @@ class ListCommentsJob extends AbstractJob implements IPagedJob
return $this->pager->getRequiredArguments();
}
public function getRequiredPrivileges()
public function getRequiredMainPrivilege()
{
return new Privilege(Privilege::ListComments);
return Privilege::ListComments;
}
public function getRequiredSubPrivileges()
{
return null;
}
public function isAuthenticationRequired()
{
return false;
}
public function isConfirmedEmailRequired()
{
return false;
}
}

View file

@ -41,9 +41,14 @@ class PreviewCommentJob extends AbstractJob
$this->postRetriever->getRequiredArguments()));
}
public function getRequiredPrivileges()
public function getRequiredMainPrivilege()
{
return new Privilege(Privilege::AddComment);
return Privilege::AddComment;
}
public function getRequiredSubPrivileges()
{
return null;
}
public function isAuthenticationRequired()

View file

@ -11,8 +11,24 @@ class GetPropertyJob extends AbstractJob
return JobArgs::ARG_QUERY;
}
public function getRequiredPrivileges()
public function getRequiredMainPrivilege()
{
return null;
}
public function getRequiredSubPrivileges()
{
return null;
}
public function isAuthenticationRequired()
{
return false;
}
public function isConfirmedEmailRequired()
{
return false;
}
}

View file

@ -5,7 +5,8 @@ interface IJob
public function execute();
public function getRequiredArguments();
public function getRequiredPrivileges();
public function getRequiredMainPrivilege();
public function getRequiredSubPrivileges();
public function isAuthenticationRequired();
public function isConfirmedEmailRequired();

View file

@ -58,8 +58,23 @@ class GetLogJob extends AbstractJob implements IPagedJob
JobArgs::Optional(JobArgs::ARG_QUERY));
}
public function getRequiredPrivileges()
public function getRequiredMainPrivilege()
{
return new Privilege(Privilege::ViewLog);
return Privilege::ViewLog;
}
public function getRequiredSubPrivileges()
{
return null;
}
public function isAuthenticationRequired()
{
return false;
}
public function isConfirmedEmailRequired()
{
return false;
}
}

View file

@ -22,8 +22,23 @@ class ListLogsJob extends AbstractJob
return null;
}
public function getRequiredPrivileges()
public function getRequiredMainPrivilege()
{
return new Privilege(Privilege::ListLogs);
return Privilege::ListLogs;
}
public function getRequiredSubPrivileges()
{
return null;
}
public function isAuthenticationRequired()
{
return false;
}
public function isConfirmedEmailRequired()
{
return false;
}
}

View file

@ -66,9 +66,19 @@ class AddPostJob extends AbstractJob
return JobArgs::Optional(JobArgs::ARG_ANONYMOUS);
}
public function getRequiredPrivileges()
public function getRequiredMainPrivilege()
{
return new Privilege(Privilege::AddPost);
return Privilege::AddPost;
}
public function getRequiredSubPrivileges()
{
return null;
}
public function isAuthenticationRequired()
{
return false;
}
public function isConfirmedEmailRequired()

View file

@ -24,11 +24,14 @@ class DeletePostJob extends AbstractJob
return $this->postRetriever->getRequiredArguments();
}
public function getRequiredPrivileges()
public function getRequiredMainPrivilege()
{
return new Privilege(
Privilege::DeletePost,
Access::getIdentity($this->postRetriever->retrieve()->getUploader()));
return Privilege::DeletePost;
}
public function getRequiredSubPrivileges()
{
return Access::getIdentity($this->postRetriever->retrieve()->getUploader());
}
public function isAuthenticationRequired()

View file

@ -42,12 +42,25 @@ class EditPostContentJob extends AbstractJob
JobArgs::ARG_NEW_POST_CONTENT_URL));
}
public function getRequiredPrivileges()
public function getRequiredMainPrivilege()
{
return new Privilege(
$this->getContext() == self::CONTEXT_BATCH_ADD
? Privilege::AddPostContent
: Privilege::EditPostContent,
Access::getIdentity($this->postRetriever->retrieve()->getUploader()));
return $this->getContext() == self::CONTEXT_BATCH_ADD
? Privilege::AddPostContent
: Privilege::EditPostContent;
}
public function getRequiredSubPrivileges()
{
return Access::getIdentity($this->postRetriever->retrieve()->getUploader());
}
public function isAuthenticationRequired()
{
return false;
}
public function isConfirmedEmailRequired()
{
return false;
}
}

View file

@ -46,10 +46,23 @@ class EditPostJob extends AbstractJob
return $this->postRetriever->getRequiredArguments();
}
public function getRequiredPrivileges()
public function getRequiredMainPrivilege()
{
return new Privilege(
Privilege::EditPost,
Access::getIdentity($this->postRetriever->retrieve()->getUploader()));
return Privilege::EditPost;
}
public function getRequiredSubPrivileges()
{
return Access::getIdentity($this->postRetriever->retrieve()->getUploader());
}
public function isAuthenticationRequired()
{
return false;
}
public function isConfirmedEmailRequired()
{
return false;
}
}

View file

@ -51,12 +51,25 @@ class EditPostRelationsJob extends AbstractJob
JobArgs::ARG_NEW_RELATED_POST_IDS);
}
public function getRequiredPrivileges()
public function getRequiredMainPrivilege()
{
return new Privilege(
$this->getContext() == self::CONTEXT_BATCH_ADD
? Privilege::AddPostRelations
: Privilege::EditPostRelations,
Access::getIdentity($this->postRetriever->retrieve()->getUploader()));
return $this->getContext() == self::CONTEXT_BATCH_ADD
? Privilege::AddPostRelations
: Privilege::EditPostRelations;
}
public function getRequiredSubPrivileges()
{
return Access::getIdentity($this->postRetriever->retrieve()->getUploader());
}
public function isAuthenticationRequired()
{
return false;
}
public function isConfirmedEmailRequired()
{
return false;
}
}

View file

@ -37,12 +37,25 @@ class EditPostSafetyJob extends AbstractJob
JobArgs::ARG_NEW_SAFETY);
}
public function getRequiredPrivileges()
public function getRequiredMainPrivilege()
{
return new Privilege(
$this->getContext() == self::CONTEXT_BATCH_ADD
? Privilege::AddPostSafety
: Privilege::EditPostSafety,
Access::getIdentity($this->postRetriever->retrieve()->getUploader()));
return $this->getContext() == self::CONTEXT_BATCH_ADD
? Privilege::AddPostSafety
: Privilege::EditPostSafety;
}
public function getRequiredSubPrivileges()
{
return Access::getIdentity($this->postRetriever->retrieve()->getUploader());
}
public function isAuthenticationRequired()
{
return false;
}
public function isConfirmedEmailRequired()
{
return false;
}
}

View file

@ -37,12 +37,25 @@ class EditPostSourceJob extends AbstractJob
JobArgs::ARG_NEW_SOURCE);
}
public function getRequiredPrivileges()
public function getRequiredMainPrivilege()
{
return new Privilege(
$this->getContext() == self::CONTEXT_BATCH_ADD
? Privilege::AddPostSource
: Privilege::EditPostSource,
Access::getIdentity($this->postRetriever->retrieve()->getUploader()));
return $this->getContext() == self::CONTEXT_BATCH_ADD
? Privilege::AddPostSource
: Privilege::EditPostSource;
}
public function getRequiredSubPrivileges()
{
return Access::getIdentity($this->postRetriever->retrieve()->getUploader());
}
public function isAuthenticationRequired()
{
return false;
}
public function isConfirmedEmailRequired()
{
return false;
}
}

View file

@ -54,12 +54,25 @@ class EditPostTagsJob extends AbstractJob
JobArgs::ARG_NEW_TAG_NAMES);
}
public function getRequiredPrivileges()
public function getRequiredMainPrivilege()
{
return new Privilege(
$this->getContext() == self::CONTEXT_BATCH_ADD
? Privilege::AddPostTags
: Privilege::EditPostTags,
Access::getIdentity($this->postRetriever->retrieve()->getUploader()));
return $this->getContext() == self::CONTEXT_BATCH_ADD
? Privilege::AddPostTags
: Privilege::EditPostTags;
}
public function getRequiredSubPrivileges()
{
return Access::getIdentity($this->postRetriever->retrieve()->getUploader());
}
public function isAuthenticationRequired()
{
return false;
}
public function isConfirmedEmailRequired()
{
return false;
}
}

View file

@ -32,12 +32,25 @@ class EditPostThumbJob extends AbstractJob
JobArgs::ARG_NEW_THUMB_CONTENT);
}
public function getRequiredPrivileges()
public function getRequiredMainPrivilege()
{
return new Privilege(
$this->getContext() == self::CONTEXT_BATCH_ADD
? Privilege::AddPostThumb
: Privilege::EditPostThumb,
Access::getIdentity($this->postRetriever->retrieve()->getUploader()));
return $this->getContext() == self::CONTEXT_BATCH_ADD
? Privilege::AddPostThumb
: Privilege::EditPostThumb;
}
public function getRequiredSubPrivileges()
{
return Access::getIdentity($this->postRetriever->retrieve()->getUploader());
}
public function isAuthenticationRequired()
{
return false;
}
public function isConfirmedEmailRequired()
{
return false;
}
}

View file

@ -38,15 +38,23 @@ class FeaturePostJob extends AbstractJob
JobArgs::Optional(JobArgs::ARG_ANONYMOUS));
}
public function getRequiredPrivileges()
public function getRequiredMainPrivilege()
{
return new Privilege(
Privilege::FeaturePost,
Access::getIdentity($this->postRetriever->retrieve()->getUploader()));
return Privilege::FeaturePost;
}
public function getRequiredSubPrivileges()
{
return Access::getIdentity($this->postRetriever->retrieve()->getUploader());
}
public function isAuthenticationRequired()
{
return true;
}
public function isConfirmedEmailRequired()
{
return false;
}
}

View file

@ -31,10 +31,23 @@ class FlagPostJob extends AbstractJob
return $this->postRetriever->getRequiredArguments();
}
public function getRequiredPrivileges()
public function getRequiredMainPrivilege()
{
return new Privilege(
Privilege::FlagPost,
Access::getIdentity($this->postRetriever->retrieve()->getUploader()));
return Privilege::FlagPost;
}
public function getRequiredSubPrivileges()
{
return Access::getIdentity($this->postRetriever->retrieve()->getUploader());
}
public function isAuthenticationRequired()
{
return false;
}
public function isConfirmedEmailRequired()
{
return false;
}
}

View file

@ -32,16 +32,31 @@ class GetPostContentJob extends AbstractJob
return $this->postRetriever->getRequiredArguments();
}
public function getRequiredPrivileges()
public function getRequiredMainPrivilege()
{
return Privilege::ViewPost;
}
public function getRequiredSubPrivileges()
{
$post = $this->postRetriever->retrieve();
$privileges = [];
if ($post->isHidden())
$privileges []= new Privilege(Privilege::ViewPost, 'hidden');
$privileges []= 'hidden';
$privileges []= new Privilege(Privilege::ViewPost, $post->getSafety()->toString());
$privileges []= $post->getSafety()->toString();
return $privileges;
}
public function isAuthenticationRequired()
{
return false;
}
public function isConfirmedEmailRequired()
{
return false;
}
}

View file

@ -24,16 +24,31 @@ class GetPostJob extends AbstractJob
null);
}
public function getRequiredPrivileges()
public function getRequiredMainPrivilege()
{
return Privilege::ViewPost;
}
public function getRequiredSubPrivileges()
{
$post = $this->postRetriever->retrieve();
$privileges = [];
if ($post->isHidden())
$privileges []= new Privilege(Privilege::ViewPost, 'hidden');
$privileges []= 'hidden';
$privileges []= new Privilege(Privilege::ViewPost, $post->getSafety()->toString());
$privileges []= $post->getSafety()->toString();
return $privileges;
}
public function isAuthenticationRequired()
{
return false;
}
public function isConfirmedEmailRequired()
{
return false;
}
}

View file

@ -43,7 +43,22 @@ class GetPostThumbJob extends AbstractJob
return $this->postRetriever->getRequiredArguments();
}
public function getRequiredPrivileges()
public function getRequiredMainPrivilege()
{
return null;
}
public function getRequiredSubPrivileges()
{
return null;
}
public function isAuthenticationRequired()
{
return false;
}
public function isConfirmedEmailRequired()
{
return false;
}

View file

@ -37,8 +37,23 @@ class ListPostsJob extends AbstractJob implements IPagedJob
JobArgs::Optional(JobArgs::ARG_QUERY));
}
public function getRequiredPrivileges()
public function getRequiredMainPrivilege()
{
return new Privilege(Privilege::ListPosts);
return Privilege::ListPosts;
}
public function getRequiredSubPrivileges()
{
return null;
}
public function isAuthenticationRequired()
{
return false;
}
public function isConfirmedEmailRequired()
{
return false;
}
}

View file

@ -25,15 +25,23 @@ class ScorePostJob extends AbstractJob
JobArgs::ARG_NEW_POST_SCORE);
}
public function getRequiredPrivileges()
public function getRequiredMainPrivilege()
{
return new Privilege(
Privilege::ScorePost,
Access::getIdentity($this->postRetriever->retrieve()->getUploader()));
return Privilege::ScorePost;
}
public function getRequiredSubPrivileges()
{
return Access::getIdentity($this->postRetriever->retrieve()->getUploader());
}
public function isAuthenticationRequired()
{
return true;
}
public function isConfirmedEmailRequired()
{
return false;
}
}

View file

@ -33,15 +33,23 @@ class TogglePostFavoriteJob extends AbstractJob
JobArgs::ARG_NEW_STATE);
}
public function getRequiredPrivileges()
public function getRequiredMainPrivilege()
{
return new Privilege(
Privilege::FavoritePost,
Access::getIdentity($this->postRetriever->retrieve()->getUploader()));
return Privilege::FavoritePost;
}
public function getRequiredSubPrivileges()
{
return Access::getIdentity($this->postRetriever->retrieve()->getUploader());
}
public function isAuthenticationRequired()
{
return true;
}
public function isConfirmedEmailRequired()
{
return false;
}
}

View file

@ -66,10 +66,23 @@ class TogglePostTagJob extends AbstractJob
Jobargs::ARG_NEW_STATE));
}
public function getRequiredPrivileges()
public function getRequiredMainPrivilege()
{
return new Privilege(
Privilege::EditPostTags,
Access::getIdentity($this->postRetriever->retrieve()->getUploader()));
return Privilege::EditPostTags;
}
public function getRequiredSubPrivileges()
{
return Access::getIdentity($this->postRetriever->retrieve()->getUploader());
}
public function isAuthenticationRequired()
{
return false;
}
public function isConfirmedEmailRequired()
{
return false;
}
}

View file

@ -33,10 +33,23 @@ class TogglePostVisibilityJob extends AbstractJob
JobArgs::ARG_NEW_STATE);
}
public function getRequiredPrivileges()
public function getRequiredMainPrivilege()
{
return new Privilege(
Privilege::HidePost,
Access::getIdentity($this->postRetriever->retrieve()->getUploader()));
return Privilege::HidePost;
}
public function getRequiredSubPrivileges()
{
return Access::getIdentity($this->postRetriever->retrieve()->getUploader());
}
public function isAuthenticationRequired()
{
return false;
}
public function isConfirmedEmailRequired()
{
return false;
}
}

View file

@ -37,8 +37,23 @@ class ListRelatedTagsJob extends AbstractJob implements IPagedJob
JobArgs::Optional(JobArgs::ARG_TAG_NAMES));
}
public function getRequiredPrivileges()
public function getRequiredMainPrivilege()
{
return new Privilege(Privilege::ListTags);
return Privilege::ListTags;
}
public function getRequiredSubPrivileges()
{
return null;
}
public function isAuthenticationRequired()
{
return false;
}
public function isConfirmedEmailRequired()
{
return false;
}
}

View file

@ -35,8 +35,23 @@ class ListTagsJob extends AbstractJob implements IPagedJob
JobArgs::Optional(JobArgs::ARG_QUERY));
}
public function getRequiredPrivileges()
public function getRequiredMainPrivilege()
{
return new Privilege(Privilege::ListTags);
return Privilege::ListTags;
}
public function getRequiredSubPrivileges()
{
return null;
}
public function isAuthenticationRequired()
{
return false;
}
public function isConfirmedEmailRequired()
{
return false;
}
}

View file

@ -22,8 +22,23 @@ class MergeTagsJob extends AbstractJob
JobArgs::ARG_TARGET_TAG_NAME);
}
public function getRequiredPrivileges()
public function getRequiredMainPrivilege()
{
return new Privilege(Privilege::MergeTags);
return Privilege::MergeTags;
}
public function getRequiredSubPrivileges()
{
return null;
}
public function isAuthenticationRequired()
{
return false;
}
public function isConfirmedEmailRequired()
{
return false;
}
}

View file

@ -22,8 +22,23 @@ class RenameTagsJob extends AbstractJob
JobArgs::ARG_TARGET_TAG_NAME);
}
public function getRequiredPrivileges()
public function getRequiredMainPrivilege()
{
return new Privilege(Privilege::RenameTags);
return Privilege::RenameTags;
}
public function getRequiredSubPrivileges()
{
return null;
}
public function isAuthenticationRequired()
{
return false;
}
public function isConfirmedEmailRequired()
{
return false;
}
}

View file

@ -27,8 +27,23 @@ class AcceptUserRegistrationJob extends AbstractJob
return $this->userRetriever->getRequiredArguments();
}
public function getRequiredPrivileges()
public function getRequiredMainPrivilege()
{
return new Privilege(Privilege::AcceptUserRegistration);
return Privilege::AcceptUserRegistration;
}
public function getRequiredSubPrivileges()
{
return null;
}
public function isAuthenticationRequired()
{
return false;
}
public function isConfirmedEmailRequired()
{
return false;
}
}

View file

@ -52,6 +52,26 @@ class ActivateUserEmailJob extends AbstractJob
$this->userRetriever->getRequiredArguments());
}
public function getRequiredMainPrivilege()
{
return null;
}
public function getRequiredSubPrivileges()
{
return null;
}
public function isAuthenticationRequired()
{
return false;
}
public function isConfirmedEmailRequired()
{
return false;
}
public static function sendEmail($user)
{
$regConfig = Core::getConfig()->registration;

View file

@ -65,8 +65,23 @@ class AddUserJob extends AbstractJob
return null;
}
public function getRequiredPrivileges()
public function getRequiredMainPrivilege()
{
return new Privilege(Privilege::RegisterAccount);
return Privilege::RegisterAccount;
}
public function getRequiredSubPrivileges()
{
return null;
}
public function isAuthenticationRequired()
{
return false;
}
public function isConfirmedEmailRequired()
{
return false;
}
}

View file

@ -25,10 +25,23 @@ class DeleteUserJob extends AbstractJob
return $this->userRetriever->getRequiredArguments();
}
public function getRequiredPrivileges()
public function getRequiredMainPrivilege()
{
return new Privilege(
Privilege::DeleteUser,
Access::getIdentity($this->userRetriever->retrieve()));
return Privilege::DeleteUser;
}
public function getRequiredSubPrivileges()
{
return Access::getIdentity($this->userRetriever->retrieve());
}
public function isAuthenticationRequired()
{
return false;
}
public function isConfirmedEmailRequired()
{
return false;
}
}

View file

@ -37,10 +37,23 @@ class EditUserAccessRankJob extends AbstractJob
JobArgs::ARG_NEW_ACCESS_RANK);
}
public function getRequiredPrivileges()
public function getRequiredMainPrivilege()
{
return new Privilege(
Privilege::ChangeUserAccessRank,
Access::getIdentity($this->userRetriever->retrieve()));
return Privilege::EditUserAccessRank;
}
public function getRequiredSubPrivileges()
{
return Access::getIdentity($this->userRetriever->retrieve());
}
public function isAuthenticationRequired()
{
return false;
}
public function isConfirmedEmailRequired()
{
return false;
}
}

View file

@ -40,7 +40,7 @@ class EditUserEmailJob extends AbstractJob
public static function observeSave($user)
{
if (Access::check(new Privilege(Privilege::ChangeUserEmailNoConfirm), $user))
if (Access::check(new Privilege(Privilege::EditUserEmailNoConfirm), $user))
{
$user->confirmEmail();
}
@ -58,12 +58,25 @@ class EditUserEmailJob extends AbstractJob
JobArgs::ARG_NEW_EMAIL);
}
public function getRequiredPrivileges()
public function getRequiredMainPrivilege()
{
return new Privilege(
$this->getContext() == self::CONTEXT_BATCH_ADD
? Privilege::RegisterAccount
: Privilege::ChangeUserEmail,
Access::getIdentity($this->userRetriever->retrieve()));
return $this->getContext() == self::CONTEXT_BATCH_ADD
? Privilege::RegisterAccount
: Privilege::EditUserEmail;
}
public function getRequiredSubPrivileges()
{
return Access::getIdentity($this->userRetriever->retrieve());
}
public function isAuthenticationRequired()
{
return false;
}
public function isConfirmedEmailRequired()
{
return false;
}
}

View file

@ -66,7 +66,22 @@ class EditUserJob extends AbstractJob
return $this->userRetriever->getRequiredArguments();
}
public function getRequiredPrivileges()
public function getRequiredMainPrivilege()
{
return null;
}
public function getRequiredSubPrivileges()
{
return null;
}
public function isAuthenticationRequired()
{
return false;
}
public function isConfirmedEmailRequired()
{
return false;
}

View file

@ -37,12 +37,25 @@ class EditUserNameJob extends AbstractJob
JobArgs::ARG_NEW_USER_NAME);
}
public function getRequiredPrivileges()
public function getRequiredMainPrivilege()
{
return new Privilege(
$this->getContext() == self::CONTEXT_BATCH_ADD
? Privilege::RegisterAccount
: Privilege::ChangeUserName,
Access::getIdentity($this->userRetriever->retrieve()));
return $this->getContext() == self::CONTEXT_BATCH_ADD
? Privilege::RegisterAccount
: Privilege::EditUserName;
}
public function getRequiredSubPrivileges()
{
return Access::getIdentity($this->userRetriever->retrieve());
}
public function isAuthenticationRequired()
{
return false;
}
public function isConfirmedEmailRequired()
{
return false;
}
}

View file

@ -36,12 +36,25 @@ class EditUserPasswordJob extends AbstractJob
JobArgs::ARG_NEW_PASSWORD);
}
public function getRequiredPrivileges()
public function getRequiredMainPrivilege()
{
return new Privilege(
$this->getContext() == self::CONTEXT_BATCH_ADD
? Privilege::RegisterAccount
: Privilege::ChangeUserPassword,
Access::getIdentity($this->userRetriever->retrieve()));
return $this->getContext() == self::CONTEXT_BATCH_ADD
? Privilege::RegisterAccount
: Privilege::EditUserPassword;
}
public function getRequiredSubPrivileges()
{
return Access::getIdentity($this->userRetriever->retrieve());
}
public function isAuthenticationRequired()
{
return false;
}
public function isConfirmedEmailRequired()
{
return false;
}
}

View file

@ -34,15 +34,23 @@ class EditUserSettingsJob extends AbstractJob
JobArgs::ARG_NEW_SETTINGS);
}
public function getRequiredPrivileges()
public function getRequiredMainPrivilege()
{
return new Privilege(
Privilege::ChangeUserSettings,
Access::getIdentity($this->userRetriever->retrieve()));
return Privilege::EditUserSettings;
}
public function getRequiredSubPrivileges()
{
return Access::getIdentity($this->userRetriever->retrieve());
}
public function isAuthenticationRequired()
{
return false;
}
public function isConfirmedEmailRequired()
{
return false;
}
}

View file

@ -31,10 +31,23 @@ class FlagUserJob extends AbstractJob
return $this->userRetriever->getRequiredArguments();
}
public function getRequiredPrivileges()
public function getRequiredMainPrivilege()
{
return new Privilege(
Privilege::FlagUser,
Access::getIdentity($this->userRetriever->retrieve()));
return Privilege::FlagUser;
}
public function getRequiredSubPrivileges()
{
return Access::getIdentity($this->userRetriever->retrieve());
}
public function isAuthenticationRequired()
{
return false;
}
public function isConfirmedEmailRequired()
{
return false;
}
}

View file

@ -18,10 +18,23 @@ class GetUserJob extends AbstractJob
return $this->userRetriever->getRequiredArguments();
}
public function getRequiredPrivileges()
public function getRequiredMainPrivilege()
{
return new Privilege(
Privilege::ViewUser,
Access::getIdentity($this->userRetriever->retrieve()));
return Privilege::ViewUser;
}
public function getRequiredSubPrivileges()
{
return Access::getIdentity($this->userRetriever->retrieve());
}
public function isAuthenticationRequired()
{
return false;
}
public function isConfirmedEmailRequired()
{
return false;
}
}

View file

@ -19,15 +19,23 @@ class GetUserSettingsJob extends AbstractJob
return $this->userRetriever->getRequiredArguments();
}
public function getRequiredPrivileges()
public function getRequiredMainPrivilege()
{
return new Privilege(
Privilege::ChangeUserSettings,
Access::getIdentity($this->userRetriever->retrieve()));
return Privilege::EditUserSettings;
}
public function getRequiredSubPrivileges()
{
return Access::getIdentity($this->userRetriever->retrieve());
}
public function isAuthenticationRequired()
{
return false;
}
public function isConfirmedEmailRequired()
{
return false;
}
}

View file

@ -35,8 +35,23 @@ class ListUsersJob extends AbstractJob implements IPagedJob
JobArgs::Optional(JobArgs::ARG_QUERY));
}
public function getRequiredPrivileges()
public function getRequiredMainPrivilege()
{
return new Privilege(Privilege::ListUsers);
return Privilege::ListUsers;
}
public function getRequiredSubPrivileges()
{
return null;
}
public function isAuthenticationRequired()
{
return false;
}
public function isConfirmedEmailRequired()
{
return false;
}
}

View file

@ -56,6 +56,26 @@ class PasswordResetJob extends AbstractJob
JobArgs::ARG_TOKEN);
}
public function getRequiredMainPrivilege()
{
return null;
}
public function getRequiredSubPrivileges()
{
return null;
}
public function isAuthenticationRequired()
{
return false;
}
public function isConfirmedEmailRequired()
{
return false;
}
public static function sendEmail($user)
{
$regConfig = Core::getConfig()->registration;

View file

@ -36,10 +36,23 @@ class ToggleUserBanJob extends AbstractJob
JobArgs::ARG_NEW_STATE);
}
public function getRequiredPrivileges()
public function getRequiredMainPrivilege()
{
return new Privilege(
Privilege::BanUser,
Access::getIdentity($this->userRetriever->retrieve()));
return Privilege::BanUser;
}
public function getRequiredSubPrivileges()
{
return Access::getIdentity($this->userRetriever->retrieve());
}
public function isAuthenticationRequired()
{
return false;
}
public function isConfirmedEmailRequired()
{
return false;
}
}

View file

@ -332,7 +332,7 @@ class UserController extends AbstractController
elseif ($tab == 'settings')
{
Access::assert(new Privilege(
Privilege::ChangeUserSettings,
Privilege::EditUserSettings,
Access::getIdentity($user)));
}
elseif ($tab == 'edit' and !(new EditUserJob)->canEditAnything(Auth::getCurrentUser()))

View file

@ -120,7 +120,7 @@ final class UserEntity extends AbstractEntity implements IValidatable, ISerializ
$this->accessRank->validate();
if ($this->accessRank->toInteger() == AccessRank::Nobody)
throw new Exception(sprintf('Cannot set special access rank "%s"', $this->accessRank->toString()));
throw new Exception(sprintf('Cannot set special access rank "%s"', $this->accessRank->toDisplayString()));
}
private function validateEmails()

View file

@ -24,7 +24,13 @@ class PostSafety extends Enum implements IValidatable
public function toString()
{
return self::_toString($this->safety);
switch ($this->safety)
{
case self::Safe: return 'safe';
case self::Sketchy: return 'sketchy';
case self::Unsafe: return 'unsafe';
}
return null;
}
public static function makeFlags($safetyCodes)

View file

@ -1,59 +1,59 @@
<?php
class Privilege extends Enum
{
const ListPosts = 1;
const ViewPost = 3;
const RetrievePost = 4;
const FavoritePost = 5;
const HidePost = 9;
const DeletePost = 10;
const FeaturePost = 25;
const ScorePost = 31;
const FlagPost = 34;
const ListPosts = 'listPosts';
const ViewPost = 'viewPost';
const RetrievePost = 'retrievePost';
const FavoritePost = 'favoritePost';
const HidePost = 'hidePost';
const DeletePost = 'deletePost';
const FeaturePost = 'featurePost';
const ScorePost = 'scorePost';
const FlagPost = 'flagPost';
const EditPost = 45;
const EditPostSafety = 6;
const EditPostTags = 7;
const EditPostThumb = 8;
const EditPostSource = 26;
const EditPostRelations = 30;
const EditPostContent = 36;
const EditPost = 'editPost';
const EditPostSafety = 'editPostSafety';
const EditPostTags = 'editPostTags';
const EditPostThumb = 'editPostThumb';
const EditPostSource = 'editPostSource';
const EditPostRelations = 'editPostRelations';
const EditPostContent = 'editPostContent';
const AddPost = 2;
const AddPostSafety = 39;
const AddPostTags = 40;
const AddPostThumb = 41;
const AddPostSource = 42;
const AddPostRelations = 43;
const AddPostContent = 44;
const AddPost = 'addPost';
const AddPostSafety = 'addPostSafety';
const AddPostTags = 'addPostTags';
const AddPostThumb = 'addPostThumb';
const AddPostSource = 'addPostSource';
const AddPostRelations = 'addPostRelations';
const AddPostContent = 'addPostContent';
const RegisterAccount = 38;
const ListUsers = 11;
const ViewUser = 12;
const ViewUserEmail = 22;
const BanUser = 13;
const AcceptUserRegistration = 14;
const ChangeUserPassword = 15;
const ChangeUserAccessRank = 16;
const ChangeUserEmail = 17;
const ChangeUserEmailNoConfirm = 46;
const ChangeUserName = 18;
const ChangeUserSettings = 28;
const DeleteUser = 19;
const FlagUser = 35;
const RegisterAccount = 'registerAccount';
const ListUsers = 'listUsers';
const ViewUser = 'viewUser';
const ViewUserEmail = 'viewUserEmail';
const BanUser = 'banUser';
const AcceptUserRegistration = 'acceptUserRegistration';
const EditUserPassword = 'editUserPassword';
const EditUserAccessRank = 'editUserAccessRank';
const EditUserEmail = 'editUserEmail';
const EditUserEmailNoConfirm = 'editUserEmailNoConfirm';
const EditUserName = 'editUserName';
const EditUserSettings = 'editUserSettings';
const DeleteUser = 'deleteUser';
const FlagUser = 'flagUser';
const ListComments = 20;
const AddComment = 23;
const DeleteComment = 24;
const EditComment = 37;
const ListComments = 'listComments';
const AddComment = 'addComment';
const DeleteComment = 'deleteComment';
const EditComment = 'editComment';
const ListTags = 21;
const MergeTags = 27;
const RenameTags = 47;
const MassTag = 29;
const ListTags = 'listTags';
const MergeTags = 'mergeTags';
const RenameTags = 'renameTags';
const MassTag = 'massTag';
const ListLogs = 32;
const ViewLog = 33;
const ListLogs = 'listLogs';
const ViewLog = 'viewLog';
public $primary;
public $secondary;
@ -66,7 +66,7 @@ class Privilege extends Enum
public function toString()
{
$string = self::_toString($this->primary);
$string = $this->primary;
if ($this->secondary)
$string .= '.' . $this->secondary;
return $string;

View file

@ -117,7 +117,7 @@
?>
<?php if (Access::check(new Privilege(
Privilege::ChangeUserSettings,
Privilege::EditUserSettings,
Access::getIdentity(Auth::getCurrentUser())))): ?>
<li class="safety">
<ul>

View file

@ -21,7 +21,7 @@
<?php endif ?>
<?php if (Access::check(new Privilege(
Privilege::ChangeUserName,
Privilege::EditUserName,
Access::getIdentity($this->context->transport->user)))): ?>
<div class="form-row nickname">
@ -38,7 +38,7 @@
<?php endif ?>
<?php if (Access::check(new Privilege(
Privilege::ChangeUserEmail,
Privilege::EditUserEmail,
Access::getIdentity($this->context->transport->user)))): ?>
<div class="form-row email">
@ -55,7 +55,7 @@
<?php endif ?>
<?php if (Access::check(new Privilege(
Privilege::ChangeUserPassword,
Privilege::EditUserPassword,
Access::getIdentity($this->context->transport->user)))): ?>
<div class="form-row password1">
@ -83,7 +83,7 @@
<?php endif ?>
<?php if (Access::check(new Privilege(
Privilege::ChangeUserAccessRank,
Privilege::EditUserAccessRank,
Access::getIdentity($this->context->transport->user)))): ?>
<div class="form-row access-rank">

View file

@ -70,10 +70,10 @@ $this->assets->addStylesheet('user-view.css');
<?php
$userModificationPrivileges = [
Privilege::ChangeUserName,
Privilege::ChangeUserEmail,
Privilege::ChangeUserPassword,
Privilege::ChangeUserAccessRank,
Privilege::EditUserName,
Privilege::EditUserEmail,
Privilege::EditUserPassword,
Privilege::EditUserAccessRank,
];
$userModificationPrivileges = array_fill_keys($userModificationPrivileges, false);
foreach (array_keys($userModificationPrivileges) as $privilege)
@ -224,7 +224,7 @@ $this->assets->addStylesheet('user-view.css');
</li>
<?php if (Access::check(new Privilege(
Privilege::ChangeUserSettings,
Privilege::EditUserSettings,
Access::getIdentity($this->context->transport->user)))): ?>
<?php if ($this->context->transport->tab == 'settings'): ?>

View file

@ -15,7 +15,6 @@ class PostMocker extends AbstractMocker implements IMocker
public function mockSingle()
{
$post = PostModel::spawn();
#$post->setUploader($owner);
$post->setType(new PostType(PostType::Image));
$post->setTags([$this->tagMocker->mockSingle()]);
copy($this->testSupport->getPath('image.jpg'), $post->getFullPath());

View file

@ -11,83 +11,83 @@ class ApiPrivilegeTest extends AbstractFullApiTest
public function testRegularPrivileges()
{
$this->testRegularPrivilege(new AcceptUserRegistrationJob(), new Privilege(Privilege::AcceptUserRegistration));
$this->testRegularPrivilege(new ActivateUserEmailJob(), false);
$this->testRegularPrivilege(new AddCommentJob(), new Privilege(Privilege::AddComment));
$this->testRegularPrivilege(new PreviewCommentJob(), new Privilege(Privilege::AddComment));
$this->testRegularPrivilege(new AddPostJob(), new Privilege(Privilege::AddPost));
$this->testRegularPrivilege(new AddUserJob(), new Privilege(Privilege::RegisterAccount));
$this->testRegularPrivilege(new EditUserJob(), false);
$this->testRegularPrivilege(new GetLogJob(), new Privilege(Privilege::ViewLog));
$this->testRegularPrivilege(new GetPropertyJob(), false);
$this->testRegularPrivilege(new ListCommentsJob(), new Privilege(Privilege::ListComments));
$this->testRegularPrivilege(new ListLogsJob(), new Privilege(Privilege::ListLogs));
$this->testRegularPrivilege(new ListPostsJob(), new Privilege(Privilege::ListPosts));
$this->testRegularPrivilege(new ListRelatedTagsJob(), new Privilege(Privilege::ListTags));
$this->testRegularPrivilege(new ListTagsJob(), new Privilege(Privilege::ListTags));
$this->testRegularPrivilege(new ListUsersJob(), new Privilege(Privilege::ListUsers));
$this->testRegularPrivilege(new PasswordResetJob(), false);
$this->testRegularPrivilege(new MergeTagsJob(), new Privilege(Privilege::MergeTags));
$this->testRegularPrivilege(new RenameTagsJob(), new Privilege(Privilege::RenameTags));
$this->testRegularPrivilege(new AcceptUserRegistrationJob(), Privilege::AcceptUserRegistration);
$this->testRegularPrivilege(new ActivateUserEmailJob(), null);
$this->testRegularPrivilege(new AddCommentJob(), Privilege::AddComment);
$this->testRegularPrivilege(new PreviewCommentJob(), Privilege::AddComment);
$this->testRegularPrivilege(new AddPostJob(), Privilege::AddPost);
$this->testRegularPrivilege(new AddUserJob(), Privilege::RegisterAccount);
$this->testRegularPrivilege(new EditUserJob(), null);
$this->testRegularPrivilege(new GetLogJob(), Privilege::ViewLog);
$this->testRegularPrivilege(new GetPropertyJob(), null);
$this->testRegularPrivilege(new ListCommentsJob(), Privilege::ListComments);
$this->testRegularPrivilege(new ListLogsJob(), Privilege::ListLogs);
$this->testRegularPrivilege(new ListPostsJob(), Privilege::ListPosts);
$this->testRegularPrivilege(new ListRelatedTagsJob(), Privilege::ListTags);
$this->testRegularPrivilege(new ListTagsJob(), Privilege::ListTags);
$this->testRegularPrivilege(new ListUsersJob(), Privilege::ListUsers);
$this->testRegularPrivilege(new PasswordResetJob(), null);
$this->testRegularPrivilege(new MergeTagsJob(), Privilege::MergeTags);
$this->testRegularPrivilege(new RenameTagsJob(), Privilege::RenameTags);
}
protected function testRegularPrivilege($job, $expectedPrivilege)
{
$this->testedJobs []= $job;
$this->assert->areEquivalent($expectedPrivilege, $job->getRequiredPrivileges());
$this->assert->areEqual($expectedPrivilege, $job->getRequiredMainPrivilege());
$this->assert->isNull($job->getRequiredSubPrivileges());
}
public function testDynamicPostPrivileges()
{
$this->login($this->userMocker->mockSingle());
$this->testDynamicPostPrivilege(new DeletePostJob(), new Privilege(Privilege::DeletePost));
$this->testDynamicPostPrivilege(new EditPostJob(), new Privilege(Privilege::EditPost));
$this->testDynamicPostPrivilege(new EditPostContentJob(), new Privilege(Privilege::EditPostContent));
$this->testDynamicPostPrivilege(new EditPostRelationsJob(), new Privilege(Privilege::EditPostRelations));
$this->testDynamicPostPrivilege(new EditPostSafetyJob(), new Privilege(Privilege::EditPostSafety));
$this->testDynamicPostPrivilege(new EditPostSourceJob(), new Privilege(Privilege::EditPostSource));
$this->testDynamicPostPrivilege(new EditPostTagsJob(), new Privilege(Privilege::EditPostTags));
$this->testDynamicPostPrivilege(new EditPostThumbJob(), new Privilege(Privilege::EditPostThumb));
$this->testDynamicPostPrivilege(new DeletePostJob(), Privilege::DeletePost);
$this->testDynamicPostPrivilege(new EditPostJob(), Privilege::EditPost);
$this->testDynamicPostPrivilege(new EditPostContentJob(), Privilege::EditPostContent);
$this->testDynamicPostPrivilege(new EditPostRelationsJob(), Privilege::EditPostRelations);
$this->testDynamicPostPrivilege(new EditPostSafetyJob(), Privilege::EditPostSafety);
$this->testDynamicPostPrivilege(new EditPostSourceJob(), Privilege::EditPostSource);
$this->testDynamicPostPrivilege(new EditPostTagsJob(), Privilege::EditPostTags);
$this->testDynamicPostPrivilege(new EditPostThumbJob(), Privilege::EditPostThumb);
$ctx = function($job)
{
$job->setContext(AbstractJob::CONTEXT_BATCH_ADD);
return $job;
};
$this->testDynamicPostPrivilege($ctx(new EditPostContentJob), new Privilege(Privilege::AddPostContent));
$this->testDynamicPostPrivilege($ctx(new EditPostRelationsJob), new Privilege(Privilege::AddPostRelations));
$this->testDynamicPostPrivilege($ctx(new EditPostSafetyJob), new Privilege(Privilege::AddPostSafety));
$this->testDynamicPostPrivilege($ctx(new EditPostSourceJob), new Privilege(Privilege::AddPostSource));
$this->testDynamicPostPrivilege($ctx(new EditPostTagsJob), new Privilege(Privilege::AddPostTags));
$this->testDynamicPostPrivilege($ctx(new EditPostThumbJob), new Privilege(Privilege::AddPostThumb));
$this->testDynamicPostPrivilege($ctx(new EditPostContentJob), Privilege::AddPostContent);
$this->testDynamicPostPrivilege($ctx(new EditPostRelationsJob), Privilege::AddPostRelations);
$this->testDynamicPostPrivilege($ctx(new EditPostSafetyJob), Privilege::AddPostSafety);
$this->testDynamicPostPrivilege($ctx(new EditPostSourceJob), Privilege::AddPostSource);
$this->testDynamicPostPrivilege($ctx(new EditPostTagsJob), Privilege::AddPostTags);
$this->testDynamicPostPrivilege($ctx(new EditPostThumbJob), Privilege::AddPostThumb);
$this->testDynamicPostPrivilege(new FeaturePostJob(), new Privilege(Privilege::FeaturePost));
$this->testDynamicPostPrivilege(new FlagPostJob(), new Privilege(Privilege::FlagPost));
$this->testDynamicPostPrivilege(new ScorePostJob(), new Privilege(Privilege::ScorePost));
$this->testDynamicPostPrivilege(new TogglePostTagJob(), new Privilege(Privilege::EditPostTags));
$this->testDynamicPostPrivilege(new TogglePostVisibilityJob(), new Privilege(Privilege::HidePost));
$this->testDynamicPostPrivilege(new TogglePostFavoriteJob(), new Privilege(Privilege::FavoritePost));
$this->testDynamicPostPrivilege(new FeaturePostJob(), Privilege::FeaturePost);
$this->testDynamicPostPrivilege(new FlagPostJob(), Privilege::FlagPost);
$this->testDynamicPostPrivilege(new ScorePostJob(), Privilege::ScorePost);
$this->testDynamicPostPrivilege(new TogglePostTagJob(), Privilege::EditPostTags);
$this->testDynamicPostPrivilege(new TogglePostVisibilityJob(), Privilege::HidePost);
$this->testDynamicPostPrivilege(new TogglePostFavoriteJob(), Privilege::FavoritePost);
}
protected function testDynamicPostPrivilege($job, $expectedPrivilege)
{
$this->testedJobs []= $job;
$this->assert->areEqual($expectedPrivilege, $job->getRequiredMainPrivilege());
list ($ownPost, $otherPost) = $this->postMocker->mockMultiple(2);
$ownPost->setUploader(Auth::getCurrentUser());
$otherPost->setUploader($this->userMocker->mockSingle());
PostModel::save([$ownPost, $otherPost]);
$expectedPrivilege->secondary = 'all';
$job->setArgument(JobArgs::ARG_POST_ID, $otherPost->getId());
$job->prepare();
$this->assert->areEquivalent($expectedPrivilege, $job->getRequiredPrivileges());
$this->assert->areEqual('all', $job->getRequiredSubPrivileges());
$expectedPrivilege->secondary = 'own';
$job->setArgument(JobArgs::ARG_POST_ID, $ownPost->getId());
$job->prepare();
$this->assert->areEquivalent($expectedPrivilege, $job->getRequiredPrivileges());
$this->assert->areEqual('own', $job->getRequiredSubPrivileges());
}
public function testDynamicPostRetrievalPrivileges()
@ -110,9 +110,10 @@ class ApiPrivilegeTest extends AbstractFullApiTest
$job->setArgument(JobArgs::ARG_POST_ID, $post->getId());
$job->setArgument(JobArgs::ARG_POST_NAME, $post->getName());
$job->prepare();
$this->assert->areEquivalent([
new Privilege(Privilege::ViewPost, 'hidden'),
new Privilege(Privilege::ViewPost, 'safe')], $job->getRequiredPrivileges());
$this->assert->areEqual(Privilege::ViewPost, $job->getRequiredMainPrivilege());
$sub = $job->getRequiredSubPrivileges();
natcasesort($sub);
$this->assert->areEquivalent(['hidden', 'safe'], $sub);
}
}
@ -120,7 +121,7 @@ class ApiPrivilegeTest extends AbstractFullApiTest
{
$job = new GetPostThumbJob();
$this->testedJobs []= $job;
$this->assert->areEquivalent(false, $job->getRequiredPrivileges());
$this->assert->isNull($job->getRequiredMainPrivilege());
}
public function testDynamicUserPrivileges()
@ -128,86 +129,85 @@ class ApiPrivilegeTest extends AbstractFullApiTest
$ownUser = $this->userMocker->mockSingle();
$this->login($ownUser);
$this->testDynamicUserPrivilege(new DeleteUserJob(), new Privilege(Privilege::DeleteUser));
$this->testDynamicUserPrivilege(new EditUserAccessRankJob(), new Privilege(Privilege::ChangeUserAccessRank));
$this->testDynamicUserPrivilege(new EditUserEmailJob(), new Privilege(Privilege::ChangeUserEmail));
$this->testDynamicUserPrivilege(new EditUserNameJob(), new Privilege(Privilege::ChangeUserName));
$this->testDynamicUserPrivilege(new EditUserPasswordJob(), new Privilege(Privilege::ChangeUserPassword));
$this->testDynamicUserPrivilege(new EditUserSettingsJob(), new Privilege(Privilege::ChangeUserSettings));
$this->testDynamicUserPrivilege(new DeleteUserJob(), Privilege::DeleteUser);
$this->testDynamicUserPrivilege(new EditUserAccessRankJob(), Privilege::EditUserAccessRank);
$this->testDynamicUserPrivilege(new EditUserEmailJob(), Privilege::EditUserEmail);
$this->testDynamicUserPrivilege(new EditUserNameJob(), Privilege::EditUserName);
$this->testDynamicUserPrivilege(new EditUserPasswordJob(), Privilege::EditUserPassword);
$this->testDynamicUserPrivilege(new EditUserSettingsJob(), Privilege::EditUserSettings);
$ctx = function($job)
{
$job->setContext(AbstractJob::CONTEXT_BATCH_ADD);
return $job;
};
$this->testDynamicUserPrivilege($ctx(new EditUserAccessRankJob()), new Privilege(Privilege::ChangeUserAccessRank));
$this->testDynamicUserPrivilege($ctx(new EditUserEmailJob()), new Privilege(Privilege::RegisterAccount));
$this->testDynamicUserPrivilege($ctx(new EditUserNameJob()), new Privilege(Privilege::RegisterAccount));
$this->testDynamicUserPrivilege($ctx(new EditUserPasswordJob()), new Privilege(Privilege::RegisterAccount));
$this->testDynamicUserPrivilege($ctx(new EditUserSettingsJob()), new Privilege(Privilege::ChangeUserSettings));
$this->testDynamicUserPrivilege($ctx(new EditUserAccessRankJob()), Privilege::EditUserAccessRank);
$this->testDynamicUserPrivilege($ctx(new EditUserEmailJob()), Privilege::RegisterAccount);
$this->testDynamicUserPrivilege($ctx(new EditUserNameJob()), Privilege::RegisterAccount);
$this->testDynamicUserPrivilege($ctx(new EditUserPasswordJob()), Privilege::RegisterAccount);
$this->testDynamicUserPrivilege($ctx(new EditUserSettingsJob()), Privilege::EditUserSettings);
$this->testDynamicUserPrivilege(new FlagUserJob(), new Privilege(Privilege::FlagUser));
$this->testDynamicUserPrivilege(new GetUserJob(), new Privilege(Privilege::ViewUser));
$this->testDynamicUserPrivilege(new GetUserSettingsJob(), new Privilege(Privilege::ChangeUserSettings));
$this->testDynamicUserPrivilege(new ToggleUserBanJob(), new Privilege(Privilege::BanUser));
$this->testDynamicUserPrivilege(new FlagUserJob(), Privilege::FlagUser);
$this->testDynamicUserPrivilege(new GetUserJob(), Privilege::ViewUser);
$this->testDynamicUserPrivilege(new GetUserSettingsJob(), Privilege::EditUserSettings);
$this->testDynamicUserPrivilege(new ToggleUserBanJob(), Privilege::BanUser);
}
protected function testDynamicUserPrivilege($job, $expectedPrivilege)
{
$this->testedJobs []= $job;
$this->assert->areEqual($expectedPrivilege, $job->getRequiredMainPrivilege());
$ownUser = Auth::getCurrentUser();
$otherUser = $this->userMocker->mockSingle();
$otherUser->setName('dummy' . uniqid());
UserModel::save($otherUser);
$this->testedJobs []= $job;
$expectedPrivilege->secondary = 'own';
$job->setArgument(JobArgs::ARG_USER_NAME, $ownUser->getName());
$job->prepare();
$this->assert->areEquivalent($expectedPrivilege, $job->getRequiredPrivileges());
$this->assert->areEqual('own', $job->getRequiredSubPrivileges());
$expectedPrivilege->secondary = 'all';
$job->setArgument(JobArgs::ARG_USER_NAME, $otherUser->getName());
$job->prepare();
$this->assert->areEquivalent($expectedPrivilege, $job->getRequiredPrivileges());
$this->assert->areEqual('all', $job->getRequiredSubPrivileges());
}
public function testDynamicCommentPrivileges()
{
$this->login($this->userMocker->mockSingle());
$this->testDynamicCommentPrivilege(new DeleteCommentJob(), new Privilege(Privilege::DeleteComment));
$this->testDynamicCommentPrivilege(new EditCommentJob(), new Privilege(Privilege::EditComment));
$this->testDynamicCommentPrivilege(new DeleteCommentJob(), Privilege::DeleteComment);
$this->testDynamicCommentPrivilege(new EditCommentJob(), Privilege::EditComment);
}
protected function testDynamicCommentPrivilege($job, $expectedPrivilege)
{
$this->testedJobs []= $job;
$this->assert->areEqual($expectedPrivilege, $job->getRequiredMainPrivilege());
list ($ownComment, $otherComment) = $this->commentMocker->mockMultiple(2);
$ownComment->setCommenter(Auth::getCurrentUser());
$otherComment->setCommenter($this->userMocker->mockSingle());
CommentModel::save([$ownComment, $otherComment]);
$this->testedJobs []= $job;
$expectedPrivilege->secondary = 'own';
$job->setArgument(JobArgs::ARG_COMMENT_ID, $ownComment->getId());
$job->prepare();
$this->assert->areEquivalent($expectedPrivilege, $job->getRequiredPrivileges());
$this->assert->areEqual('own', $job->getRequiredSubPrivileges());
$expectedPrivilege->secondary = 'all';
$job->setArgument(JobArgs::ARG_COMMENT_ID, $otherComment->getId());
$job->prepare();
$this->assert->areEquivalent($expectedPrivilege, $job->getRequiredPrivileges());
$this->assert->areEqual('all', $job->getRequiredSubPrivileges());
}
public function testPrivilegeEnforcing()
{
$this->assert->throws(function()
$post = $this->postMocker->mockSingle();
Core::getConfig()->registration->needEmailForCommenting = false;
$this->assert->throws(function() use ($post)
{
$post = $this->postMocker->mockSingle();
Core::getConfig()->registration->needEmailForCommenting = false;
return Api::run(
Api::run(
new AddCommentJob(),
[
JobArgs::ARG_POST_ID => $post->getId(),
@ -215,4 +215,39 @@ class ApiPrivilegeTest extends AbstractFullApiTest
]);
}, 'Insufficient privileges');
}
public function testComplexPrivilegeEnforcing()
{
$post = $this->postMocker->mockSingle();
Core::getConfig()->registration->needEmailForCommenting = false;
$this->grantAccess('editPost.own');
$this->grantAccess('editPostTags.own');
$this->revokeAccess('editPost.all');
$this->revokeAccess('editPostTags.all');
$user = $this->userMocker->mockSingle();
$this->login($user);
$this->assert->throws(function() use ($post)
{
Api::run(
new EditPostTagsJob(),
[
JobArgs::ARG_POST_ID => $post->getId(),
JobArgs::ARG_NEW_TAG_NAMES => ['test1', 'test2'],
]);
}, 'Insufficient privileges');
$post->setUploader($user);
PostModel::save($post);
$this->assert->doesNotThrow(function() use ($post)
{
Api::run(
new EditPostTagsJob(),
[
JobArgs::ARG_POST_ID => $post->getId(),
JobArgs::ARG_NEW_TAG_NAMES => ['test1', 'test2'],
]);
});
}
}

View file

@ -147,7 +147,7 @@ class AddUserJobTest extends AbstractTest
Mailer::mockSending();
$this->assert->areEqual(0, Mailer::getMailCounter());
Core::getConfig()->privileges->changeUserEmailNoConfirm = 'admin';
Core::getConfig()->privileges->editUserEmailNoConfirm = 'admin';
$this->grantAccess('registerAccount');
$user1 = $this->assert->doesNotThrow(function()
@ -189,7 +189,7 @@ class AddUserJobTest extends AbstractTest
Mailer::mockSending();
$this->assert->areEqual(0, Mailer::getMailCounter());
Core::getConfig()->privileges->changeUserEmailNoConfirm = 'nobody';
Core::getConfig()->privileges->editUserEmailNoConfirm = 'nobody';
$this->grantAccess('registerAccount');
$user1 = $this->assert->doesNotThrow(function()
@ -229,7 +229,7 @@ class AddUserJobTest extends AbstractTest
Mailer::mockSending();
$this->assert->areEqual(0, Mailer::getMailCounter());
Core::getConfig()->privileges->changeUserEmailNoConfirm = 'anonymous';
Core::getConfig()->privileges->editUserEmailNoConfirm = 'anonymous';
$this->grantAccess('registerAccount');
$user1 = $this->assert->doesNotThrow(function()

View file

@ -3,7 +3,7 @@ class EditUserAccessRankJobTest extends AbstractTest
{
public function testEditing()
{
$this->grantAccess('changeUserAccessRank');
$this->grantAccess('editUserAccessRank');
$user = $this->userMocker->mockSingle();
$this->assert->areEqual(AccessRank::Registered, $user->getAccessRank()->toInteger());
@ -23,7 +23,7 @@ class EditUserAccessRankJobTest extends AbstractTest
public function testSettingToNobodyDenial()
{
$this->grantAccess('changeUserAccessRank');
$this->grantAccess('editUserAccessRank');
$user = $this->userMocker->mockSingle();
$this->assert->areEqual(AccessRank::Registered, $user->getAccessRank()->toInteger());
@ -41,7 +41,7 @@ class EditUserAccessRankJobTest extends AbstractTest
public function testHigherThanMyselfDenial()
{
Core::getConfig()->privileges->changeUserAccessRank = 'power-user';
Core::getConfig()->privileges->editUserAccessRank = 'power-user';
Access::init();
$user = $this->userMocker->mockSingle();

View file

@ -7,8 +7,8 @@ class EditUserEmailJobTest extends AbstractTest
Mailer::mockSending();
$this->assert->areEqual(0, Mailer::getMailCounter());
Core::getConfig()->privileges->changeUserEmailNoConfirm = 'anonymous';
$this->grantAccess('changeUserEmail');
Core::getConfig()->privileges->editUserEmailNoConfirm = 'anonymous';
$this->grantAccess('editUserEmail');
$user = $this->userMocker->mockSingle();
@ -34,8 +34,8 @@ class EditUserEmailJobTest extends AbstractTest
Mailer::mockSending();
$this->assert->areEqual(0, Mailer::getMailCounter());
Core::getConfig()->privileges->changeUserEmailNoConfirm = 'admin';
$this->grantAccess('changeUserEmail');
Core::getConfig()->privileges->editUserEmailNoConfirm = 'admin';
$this->grantAccess('editUserEmail');
$user = $this->userMocker->mockSingle();
@ -60,8 +60,8 @@ class EditUserEmailJobTest extends AbstractTest
Core::getConfig()->registration->needEmailForRegistering = false;
Mailer::mockSending();
Core::getConfig()->privileges->changeUserEmailNoConfirm = 'nobody';
$this->grantAccess('changeUserEmail');
Core::getConfig()->privileges->editUserEmailNoConfirm = 'nobody';
$this->grantAccess('editUserEmail');
$user = $this->userMocker->mockSingle();
@ -82,8 +82,8 @@ class EditUserEmailJobTest extends AbstractTest
Mailer::mockSending();
$this->assert->areEqual(0, Mailer::getMailCounter());
Core::getConfig()->privileges->changeUserEmailNoConfirm = 'anonymous';
$this->grantAccess('changeUserEmail');
Core::getConfig()->privileges->editUserEmailNoConfirm = 'anonymous';
$this->grantAccess('editUserEmail');
list ($user, $otherUser)
= $this->userMocker->mockMultiple(2);

View file

@ -3,8 +3,8 @@ class EditUserJobTest extends AbstractTest
{
public function testSaving()
{
$this->grantAccess('changeUserName.own');
$this->grantAccess('changeUserPassword.own');
$this->grantAccess('editUserName.own');
$this->grantAccess('editUserPassword.own');
$user = $this->userMocker->mockSingle();
$newName = 'dummy' . uniqid();
@ -29,7 +29,7 @@ class EditUserJobTest extends AbstractTest
public function testPartialPrivilegeFail()
{
$this->grantAccess('changeUserName.own');
$this->grantAccess('editUserName.own');
$user = $this->userMocker->mockSingle();
$newName = 'dummy' . uniqid();
@ -58,7 +58,7 @@ class EditUserJobTest extends AbstractTest
public function testCanEditSomething()
{
$this->grantAccess('changeUserName.own');
$this->grantAccess('editUserName.own');
$user = $this->userMocker->mockSingle();
$user = $this->assert->isTrue((new EditUserJob())->canEditAnything($user));
}

View file

@ -3,7 +3,7 @@ class EditUserNameJobTest extends AbstractTest
{
public function testEditing()
{
$this->grantAccess('changeUserName');
$this->grantAccess('editUserName');
$user = $this->userMocker->mockSingle();
$newName = uniqid();
@ -25,7 +25,7 @@ class EditUserNameJobTest extends AbstractTest
public function testTooShortName()
{
$this->grantAccess('changeUserName');
$this->grantAccess('editUserName');
$user = $this->userMocker->mockSingle();
$newName = str_repeat('a', Core::getConfig()->registration->userNameMinLength - 1);
@ -43,7 +43,7 @@ class EditUserNameJobTest extends AbstractTest
public function testTooLongName()
{
$this->grantAccess('changeUserName');
$this->grantAccess('editUserName');
$user = $this->userMocker->mockSingle();
$newName = str_repeat('a', Core::getConfig()->registration->userNameMaxLength + 1);
@ -61,7 +61,7 @@ class EditUserNameJobTest extends AbstractTest
public function testInvalidName()
{
$this->grantAccess('changeUserName');
$this->grantAccess('editUserName');
$user = $this->userMocker->mockSingle();
$newName = 'ble/ble';
@ -79,7 +79,7 @@ class EditUserNameJobTest extends AbstractTest
public function testChangingToExistingDenial()
{
$this->grantAccess('changeUserName');
$this->grantAccess('editUserName');
list ($user, $otherUser)
= $this->userMocker->mockMultiple(2);

View file

@ -13,7 +13,7 @@ class EditUserPasswordJobTest extends AbstractTest
public function testTooShortPassword()
{
$this->grantAccess('changeUserPassword');
$this->grantAccess('editUserPassword');
$user = $this->userMocker->mockSingle();
$newPassword = str_repeat('a', Core::getConfig()->registration->passMinLength - 1);
@ -34,7 +34,7 @@ class EditUserPasswordJobTest extends AbstractTest
private function testValidPassword($newPassword)
{
$this->grantAccess('changeUserPassword');
$this->grantAccess('editUserPassword');
$user = $this->userMocker->mockSingle();
$newPasswordHash = UserModel::hashPassword($newPassword, $user->getPasswordSalt());

View file

@ -3,7 +3,7 @@ class EditUserSettingsJobTest extends AbstractTest
{
public function testEditing()
{
$this->grantAccess('changeUserSettings');
$this->grantAccess('editUserSettings');
$user = $this->userMocker->mockSingle();
$expectedSafety = (new PostSafety(PostSafety::Sketchy))->toFlag();
@ -33,7 +33,7 @@ class EditUserSettingsJobTest extends AbstractTest
public function testSettingAdditional()
{
$this->grantAccess('changeUserSettings');
$this->grantAccess('editUserSettings');
$user = $this->userMocker->mockSingle();
$user = $this->assert->doesNotThrow(function() use ($user)
@ -61,7 +61,7 @@ class EditUserSettingsJobTest extends AbstractTest
public function testSettingBadValues()
{
$this->grantAccess('changeUserSettings');
$this->grantAccess('editUserSettings');
$user = $this->userMocker->mockSingle();
$user = $this->assert->doesNotThrow(function() use ($user)
@ -90,7 +90,7 @@ class EditUserSettingsJobTest extends AbstractTest
public function testSettingTooLongData()
{
$this->grantAccess('changeUserSettings');
$this->grantAccess('editUserSettings');
$user = $this->userMocker->mockSingle();
$this->assert->throws(function() use ($user)

View file

@ -3,7 +3,7 @@ class GetUserSettingsJobTest extends AbstractTest
{
public function testRetrieving()
{
$this->grantAccess('changeUserSettings');
$this->grantAccess('editUserSettings');
$user = $this->userMocker->mockSingle();
$settings = $this->assert->doesNotThrow(function() use ($user)
@ -25,7 +25,7 @@ class GetUserSettingsJobTest extends AbstractTest
public function testSwitchingSafety()
{
$this->grantAccess('changeUserSettings');
$this->grantAccess('editUserSettings');
$user = $this->userMocker->mockSingle();
$user->getSettings()->enableSafety(new PostSafety(PostSafety::Sketchy), true);
@ -53,7 +53,7 @@ class GetUserSettingsJobTest extends AbstractTest
public function testSwitchingSafety2()
{
$this->grantAccess('changeUserSettings');
$this->grantAccess('editUserSettings');
$user = $this->userMocker->mockSingle();
$user->getSettings()->enableSafety(new PostSafety(PostSafety::Sketchy), true);