diff --git a/app/blueprints/packages/packages.py b/app/blueprints/packages/packages.py index 4399267d..5d8711af 100644 --- a/app/blueprints/packages/packages.py +++ b/app/blueprints/packages/packages.py @@ -176,7 +176,7 @@ def view(package): threads = Thread.query.filter_by(package_id=package.id, review_id=None) if not current_user.is_authenticated: threads = threads.filter_by(private=False) - elif not current_user.rank.atLeast(UserRank.EDITOR) and not current_user == package.author: + elif not current_user.rank.atLeast(UserRank.APPROVER) and not current_user == package.author: threads = threads.filter(or_(Thread.private == False, Thread.author == current_user)) has_review = current_user.is_authenticated and PackageReview.query.filter_by(package=package, author=current_user).count() > 0 @@ -519,7 +519,8 @@ def remove_self_maintainers(package): @login_required @is_package_page def audit(package): - if not package.checkPerm(current_user, Permission.EDIT_PACKAGE): + if not (package.checkPerm(current_user, Permission.EDIT_PACKAGE) or + package.checkPerm(current_user, Permission.APPROVE_NEW)): abort(403) page = get_int_or_abort(request.args.get("page"), 1) diff --git a/app/blueprints/threads/__init__.py b/app/blueprints/threads/__init__.py index 7a6493fe..710d4355 100644 --- a/app/blueprints/threads/__init__.py +++ b/app/blueprints/threads/__init__.py @@ -240,8 +240,8 @@ def view(id): addNotification(thread.watchers, current_user, NotificationType.THREAD_REPLY, msg, thread.getViewURL(), thread.package) if thread.author == get_system_user(): - editors = User.query.filter(User.rank >= UserRank.EDITOR).all() - addNotification(editors, current_user, NotificationType.EDITOR_MISC, msg, + approvers = User.query.filter(User.rank >= UserRank.APPROVER).all() + addNotification(approvers, current_user, NotificationType.EDITOR_MISC, msg, thread.getViewURL(), thread.package) db.session.commit() @@ -336,8 +336,8 @@ def new(): if package is not None: addNotification(package.maintainers, current_user, NotificationType.NEW_THREAD, notif_msg, thread.getViewURL(), package) - editors = User.query.filter(User.rank >= UserRank.EDITOR).all() - addNotification(editors, current_user, NotificationType.EDITOR_MISC, notif_msg, thread.getViewURL(), package) + approvers = User.query.filter(User.rank >= UserRank.APPROVER).all() + addNotification(approvers, current_user, NotificationType.EDITOR_MISC, notif_msg, thread.getViewURL(), package) db.session.commit() diff --git a/app/blueprints/todo/__init__.py b/app/blueprints/todo/__init__.py index 5bb30b92..be9aa80c 100644 --- a/app/blueprints/todo/__init__.py +++ b/app/blueprints/todo/__init__.py @@ -99,7 +99,7 @@ def topics(): page = get_int_or_abort(request.args.get("page"), 1) num = get_int_or_abort(request.args.get("n"), 100) - if num > 100 and not current_user.rank.atLeast(UserRank.EDITOR): + if num > 100 and not current_user.rank.atLeast(UserRank.APPROVER): num = 100 query = query.paginate(page, num, True) @@ -160,7 +160,7 @@ def view_user(username=None): if not user: abort(404) - if current_user != user and not current_user.rank.atLeast(UserRank.EDITOR): + if current_user != user and not current_user.rank.atLeast(UserRank.APPROVER): abort(403) unapproved_packages = user.packages \ diff --git a/app/flatpages/help/ranks_permissions.md b/app/flatpages/help/ranks_permissions.md index 31568ef4..143214ae 100644 --- a/app/flatpages/help/ranks_permissions.md +++ b/app/flatpages/help/ranks_permissions.md @@ -5,7 +5,8 @@ title: Ranks and Permissions * **New Members** - mostly untrusted, cannot change package meta data or publish releases without approval. * **Members** - Trusted to change the meta data of their own packages', but cannot approve their own packages. * **Trusted Members** - Same as above, but can approve their own releases. -* **Editors** - Trusted to edit any package or release, and also responsible for approving new packages. +* **Approvers** - Responsible for approving new packages, screenshots, and releases. +* **Editors** - Same as above, and can edit any package or release. * **Moderators** - Same as above, but can manage users. * **Admins** - Full access. @@ -18,6 +19,7 @@ title: Ranks and Permissions New Member Member Trusted + Approver Editor Moderator Admin @@ -36,6 +38,8 @@ title: Ranks and Permissions N Y N + Y + N @@ -47,6 +51,8 @@ title: Ranks and Permissions ✓ + ✓ + ✓ ✓ ✓ @@ -62,6 +68,8 @@ title: Ranks and Permissions + ✓ + ✓ ✓ ✓ ✓ @@ -77,6 +85,8 @@ title: Ranks and Permissions ✓ + ✓ + ✓ ✓ ✓ ✓ @@ -92,6 +102,8 @@ title: Ranks and Permissions ✓ + ✓ + ✓ ✓ ✓ @@ -107,8 +119,10 @@ title: Ranks and Permissions ✓ - ✓ + ✓ + ✓ + ✓ ✓ ✓ ✓ @@ -122,6 +136,8 @@ title: Ranks and Permissions ✓ + ✓ + ✓ ✓ ✓ @@ -137,6 +153,8 @@ title: Ranks and Permissions ✓ + ✓ + ✓ ✓ ✓ ✓ @@ -152,6 +170,8 @@ title: Ranks and Permissions ✓ + ✓ + ✓ ✓ ✓ @@ -167,6 +187,8 @@ title: Ranks and Permissions ✓ + ✓ + ✓ ✓ ✓ ✓ @@ -182,6 +204,8 @@ title: Ranks and Permissions + + @@ -197,6 +221,8 @@ title: Ranks and Permissions ✓ + ✓ + ✓ ✓ ✓ ✓ @@ -212,6 +238,8 @@ title: Ranks and Permissions ✓ + ✓ + ✓ @@ -227,6 +255,8 @@ title: Ranks and Permissions ✓ + ✓ + ✓ @@ -242,6 +272,8 @@ title: Ranks and Permissions ✓ + ✓ + ✓ @@ -257,10 +289,12 @@ title: Ranks and Permissions + + - ✓3 - ✓23 + ✓2 + ✓12 ✓ @@ -268,5 +302,5 @@ title: Ranks and Permissions -2. Target user cannot be an admin. -3. Cannot set user to a higher rank than themselves. +1. Target user cannot be an admin. +2 Cannot set user to a higher rank than themselves. diff --git a/app/models/packages.py b/app/models/packages.py index 24a51139..a9b9e77d 100644 --- a/app/models/packages.py +++ b/app/models/packages.py @@ -520,6 +520,7 @@ class Package(db.Model): isOwner = user == self.author isMaintainer = isOwner or user.rank.atLeast(UserRank.EDITOR) or user in self.maintainers + isApprover = user.rank.atLeast(UserRank.APPROVER) if perm == Permission.CREATE_THREAD: return user.rank.atLeast(UserRank.MEMBER) @@ -528,25 +529,30 @@ class Package(db.Model): elif perm == Permission.MAKE_RELEASE or perm == Permission.ADD_SCREENSHOTS: return isMaintainer - elif perm == Permission.EDIT_PACKAGE or \ - perm == Permission.APPROVE_CHANGES or perm == Permission.APPROVE_RELEASE: + elif perm == Permission.EDIT_PACKAGE: return isMaintainer and user.rank.atLeast(UserRank.MEMBER if self.approved else UserRank.NEW_MEMBER) + elif perm == Permission.APPROVE_RELEASE: + return (isMaintainer or isApprover) and user.rank.atLeast(UserRank.MEMBER if self.approved else UserRank.NEW_MEMBER) + # Anyone can change the package name when not approved, but only editors when approved elif perm == Permission.CHANGE_NAME: return not self.approved or user.rank.atLeast(UserRank.EDITOR) # Editors can change authors and approve new packages elif perm == Permission.APPROVE_NEW or perm == Permission.CHANGE_AUTHOR: - return user.rank.atLeast(UserRank.EDITOR) + return isApprover elif perm == Permission.APPROVE_SCREENSHOT: - return isMaintainer and user.rank.atLeast(UserRank.TRUSTED_MEMBER if self.approved else UserRank.NEW_MEMBER) + return (isMaintainer or isApprover) and \ + user.rank.atLeast(UserRank.TRUSTED_MEMBER if self.approved else UserRank.NEW_MEMBER) - elif perm == Permission.EDIT_MAINTAINERS or perm == Permission.UNAPPROVE_PACKAGE or \ - perm == Permission.DELETE_PACKAGE: + elif perm == Permission.EDIT_MAINTAINERS or perm == Permission.DELETE_PACKAGE: return isOwner or user.rank.atLeast(UserRank.EDITOR) + elif perm == Permission.UNAPPROVE_PACKAGE: + return isOwner or user.rank.atLeast(UserRank.APPROVER) + elif perm == Permission.CHANGE_RELEASE_URL: return user.rank.atLeast(UserRank.MODERATOR) @@ -575,9 +581,10 @@ class Package(db.Model): return False if state == PackageState.READY_FOR_REVIEW or state == PackageState.APPROVED: - requiredPerm = Permission.APPROVE_NEW if state == PackageState.APPROVED else Permission.EDIT_PACKAGE + if state == PackageState.APPROVED and not self.checkPerm(user, Permission.APPROVE_NEW): + return False - if not self.checkPerm(user, requiredPerm): + if not (self.checkPerm(user, Permission.APPROVE_NEW) or self.checkPerm(user, Permission.EDIT_PACKAGE)): return False if state == PackageState.APPROVED and ("Other" in self.license.name or "Other" in self.media_license.name): @@ -881,7 +888,7 @@ class PackageRelease(db.Model): return count > 0 elif perm == Permission.APPROVE_RELEASE: - return user.rank.atLeast(UserRank.EDITOR) or \ + return user.rank.atLeast(UserRank.APPROVER) or \ (isMaintainer and user.rank.atLeast( UserRank.MEMBER if self.approved else UserRank.NEW_MEMBER)) else: diff --git a/app/models/threads.py b/app/models/threads.py index 2be48f17..f002942e 100644 --- a/app/models/threads.py +++ b/app/models/threads.py @@ -76,7 +76,7 @@ class Thread(db.Model): if self.package: isMaintainer = isMaintainer or user in self.package.maintainers - canSee = not self.private or isMaintainer or user.rank.atLeast(UserRank.EDITOR) + canSee = not self.private or isMaintainer or user.rank.atLeast(UserRank.APPROVER) if perm == Permission.SEE_THREAD: return canSee diff --git a/app/models/users.py b/app/models/users.py index b12b7911..81792d4a 100644 --- a/app/models/users.py +++ b/app/models/users.py @@ -31,10 +31,11 @@ class UserRank(enum.Enum): NEW_MEMBER = 2 MEMBER = 3 TRUSTED_MEMBER = 4 - EDITOR = 5 - BOT = 6 - MODERATOR = 7 - ADMIN = 8 + APPROVER = 5 + EDITOR = 6 + BOT = 7 + MODERATOR = 8 + ADMIN = 9 def atLeast(self, min): return self.value >= min.value @@ -59,7 +60,6 @@ class UserRank(enum.Enum): class Permission(enum.Enum): EDIT_PACKAGE = "EDIT_PACKAGE" - APPROVE_CHANGES = "APPROVE_CHANGES" DELETE_PACKAGE = "DELETE_PACKAGE" CHANGE_AUTHOR = "CHANGE_AUTHOR" CHANGE_NAME = "CHANGE_NAME" @@ -96,13 +96,14 @@ class Permission(enum.Enum): return False if self == Permission.APPROVE_NEW or \ - self == Permission.APPROVE_CHANGES or \ self == Permission.APPROVE_RELEASE or \ self == Permission.APPROVE_SCREENSHOT or \ - self == Permission.EDIT_TAGS or \ - self == Permission.CREATE_TAG or \ self == Permission.SEE_THREAD: + return user.rank.atLeast(UserRank.APPROVER) + + elif self == Permission.EDIT_TAGS or self == Permission.CREATE_TAG: return user.rank.atLeast(UserRank.EDITOR) + else: raise Exception("Non-global permission checked globally. Use Package.checkPerm or User.checkPerm instead.") @@ -186,8 +187,7 @@ class User(db.Model, UserMixin): def canAccessTodoList(self): return Permission.APPROVE_NEW.check(self) or \ - Permission.APPROVE_RELEASE.check(self) or \ - Permission.APPROVE_CHANGES.check(self) + Permission.APPROVE_RELEASE.check(self) def isClaimed(self): return self.rank.atLeast(UserRank.NEW_MEMBER) diff --git a/app/scss/components.scss b/app/scss/components.scss index 554e009c..76ddb77f 100644 --- a/app/scss/components.scss +++ b/app/scss/components.scss @@ -70,7 +70,7 @@ } .NOT_JOINED a, .NOT_JOINED { - color: #7ac !important; + color: #aaa !important; } .ADMIN a, .ADMIN{ @@ -81,6 +81,10 @@ color: #e90 !important; } +.APPROVER a, .APPROVER { + color: #69f !important; +} + .EDITOR a, .EDITOR { color: #b6f !important; } diff --git a/app/templates/base.html b/app/templates/base.html index 44d547b7..8a9d2148 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -6,7 +6,7 @@ {% block title %}title{% endblock %} - {{ config.USER_APP_NAME }} - + diff --git a/app/templates/notifications/list.html b/app/templates/notifications/list.html index 13858def..455d780a 100644 --- a/app/templates/notifications/list.html +++ b/app/templates/notifications/list.html @@ -63,7 +63,7 @@ Notifications {% if editor_notifications %} -

Editor Notifications

+

Editor/Approver Notifications

{% for n in editor_notifications %} diff --git a/app/templates/packages/view.html b/app/templates/packages/view.html index ea017428..422facf2 100644 --- a/app/templates/packages/view.html +++ b/app/templates/packages/view.html @@ -200,7 +200,7 @@ {% if review_thread.private %}

This thread is only visible to the package owner and users of - Editor rank or above. + Approver rank or above.

{% endif %} @@ -450,7 +450,7 @@ Report a problem with this listing {% endif %} - {% if package.checkPerm(current_user, "EDIT_PACKAGE") %} + {% if package.checkPerm(current_user, "EDIT_PACKAGE") or package.checkPerm(current_user, "APPROVE_NEW") %} See audit log diff --git a/app/templates/threads/new.html b/app/templates/threads/new.html index c0fe5626..2516f9d0 100644 --- a/app/templates/threads/new.html +++ b/app/templates/threads/new.html @@ -37,7 +37,7 @@ {{ render_checkbox_field(form.private, class_="my-3") }}

- Only you, the package author, and users of Editor rank + Only you, the package author, and users of Approver rank and above can read private threads.

diff --git a/app/templates/threads/view.html b/app/templates/threads/view.html index 226a0dd5..23c32327 100644 --- a/app/templates/threads/view.html +++ b/app/templates/threads/view.html @@ -63,7 +63,7 @@ {% if thread.private %} This thread is only visible to its creator, the package owner, and users of - Editor rank or above. + Approver rank or above. {% endif %} diff --git a/app/templates/todo/todo_base.html b/app/templates/todo/todo_base.html index 4f144460..e29e283e 100644 --- a/app/templates/todo/todo_base.html +++ b/app/templates/todo/todo_base.html @@ -1,7 +1,7 @@ {% extends "base.html" %} {% block container %} - {% if current_user.rank.atLeast(current_user.rank.EDITOR) %} + {% if current_user.rank.atLeast(current_user.rank.APPROVER) %}