]> git.lizzy.rs Git - cheatdb.git/commitdiff
Add support for package maintainers
authorrubenwardy <rw@rubenwardy.com>
Wed, 8 Jul 2020 21:45:24 +0000 (22:45 +0100)
committerrubenwardy <rw@rubenwardy.com>
Wed, 8 Jul 2020 21:45:24 +0000 (22:45 +0100)
Fixes #159

app/blueprints/packages/packages.py
app/flatpages/help/ranks_permissions.md
app/models.py
app/templates/packages/edit_maintainers.html [new file with mode: 0644]
app/templates/packages/view.html
migrations/versions/cb6ab141c522_.py [new file with mode: 0644]

index 700fc44caa46e3be8f52942676b6d3f767bba677..853153c85bf3dc6de4a1ed03ecbf77cae087b7cd 100644 (file)
@@ -382,3 +382,37 @@ def remove(package):
                return redirect(package.getDetailsURL())
        else:
                abort(400)
+
+
+
+class PackageMaintainersForm(FlaskForm):
+       maintainers_str  = StringField("Maintainers (Comma-separated)", [Optional()])
+       submit        = SubmitField("Save")
+
+
+@bp.route("/packages/<author>/<name>/edit-maintainers/", methods=["GET", "POST"])
+@login_required
+@is_package_page
+def edit_maintainers(package):
+       if not package.checkPerm(current_user, Permission.EDIT_MAINTAINERS):
+               flash("You do not have permission to edit maintainers", "danger")
+               return redirect(package.getDetailsURL())
+
+       form = PackageMaintainersForm(formdata=request.form)
+       if request.method == "GET":
+               form.maintainers_str.data = ", ".join([ x.username for x in package.maintainers ])
+
+       if request.method == "POST" and form.validate():
+               usernames = [x.strip() for x in form.maintainers_str.data.split(",")]
+               users = User.query.filter(func.lower(User.username).in_(usernames)).all()
+               package.maintainers.clear()
+               package.maintainers.extend(users)
+               package.maintainers.append(package.author)
+               db.session.commit()
+
+               return redirect(package.getDetailsURL())
+
+       users = User.query.filter(User.rank >= UserRank.NEW_MEMBER).order_by(db.asc(User.username)).all()
+
+       return render_template("packages/edit_maintainers.html", \
+                       package=package, form=form, users=users)
index 1740c5515e7713b67f76dbabdaa98f0413fe5487..93a337c9dd94e9949fe198bbbe35e1c6aed0fa9d 100644 (file)
@@ -11,7 +11,7 @@ title: Ranks and Permissions
 
 ## Breakdown
 
-<table class="fancyTable">
+<table class="table">
        <thead>
                <tr>
                        <th>Rank</th>
@@ -85,7 +85,7 @@ title: Ranks and Permissions
                        <th>✓</th>
                </tr>
                <tr>
-                       <td>Add/Delete Screenshot</td>
+                       <td>Edit Maintainers</td>
                        <th>✓</th> <!-- new -->
                        <th></th>
                        <th>✓</th> <!-- member -->
@@ -93,30 +93,15 @@ title: Ranks and Permissions
                        <th>✓</th> <!-- trusted member -->
                        <th></th>
                        <th>✓</th> <!-- editor -->
-                       <th>✓</th>
-                       <th>✓</th> <!-- moderator -->
-                       <th>✓</th>
-                       <th>✓</th> <!-- admin -->
-                       <th>✓</th>
-               </tr>
-               <tr>
-                       <td>Approve Screenshot</td>
-                       <th></th> <!-- new -->
-                       <th></th>
-                       <th></th> <!-- member -->
                        <th></th>
-                       <th>✓</th> <!-- trusted member -->
-                       <th></th>
-                       <th>✓</th> <!-- editor -->
-                       <th>✓</th>
                        <th>✓</th> <!-- moderator -->
                        <th>✓</th>
                        <th>✓</th> <!-- admin -->
                        <th>✓</th>
                </tr>
                <tr>
-                       <td>Approve EditRequest</td>
-                       <th></th> <!-- new -->
+                       <td>Add/Delete Screenshot</td>
+                       <th></th> <!-- new -->
                        <th></th>
                        <th>✓</th> <!-- member -->
                        <th></th>
@@ -130,10 +115,10 @@ title: Ranks and Permissions
                        <th>✓</th>
                </tr>
                <tr>
-                       <td>Edit EditRequest</td>
-                       <th>✓<sup>1</sup></th> <!-- new -->
+                       <td>Approve Screenshot</td>
+                       <th></th> <!-- new -->
                        <th></th>
-                       <th></th> <!-- member -->
+                       <th></th> <!-- member -->
                        <th></th>
                        <th>✓</th> <!-- trusted member -->
                        <th></th>
index f3e65a266b9fa08321d51d6ac6ebec3092189c92..0cb90c96c3b37d0c2a5c3f18bc77741b4dca39e3 100644 (file)
@@ -93,6 +93,7 @@ class Permission(enum.Enum):
        UNAPPROVE_PACKAGE  = "UNAPPROVE_PACKAGE"
        TOPIC_DISCARD      = "TOPIC_DISCARD"
        CREATE_TOKEN       = "CREATE_TOKEN"
+       EDIT_MAINTAINERS   = "EDIT_MAINTAINERS"
        CHANGE_PROFILE_URLS = "CHANGE_PROFILE_URLS"
 
        # Only return true if the permission is valid for *all* contexts
@@ -323,6 +324,11 @@ tags = db.Table("tags",
     db.Column("package_id", db.Integer, db.ForeignKey("package.id"), primary_key=True)
 )
 
+maintainers = db.Table("maintainers",
+    db.Column("user_id", db.Integer, db.ForeignKey("user.id"), primary_key=True),
+    db.Column("package_id", db.Integer, db.ForeignKey("package.id"), primary_key=True)
+)
+
 class Dependency(db.Model):
        id              = db.Column(db.Integer, primary_key=True)
        depender_id     = db.Column(db.Integer, db.ForeignKey("package.id"),     nullable=True)
@@ -454,6 +460,8 @@ class Package(db.Model):
        requests = db.relationship("EditRequest", backref="package",
                        lazy="dynamic")
 
+       maintainers = db.relationship("User", secondary=maintainers, lazy="subquery")
+
        def __init__(self, package=None):
                if package is None:
                        return
@@ -633,6 +641,10 @@ class Package(db.Model):
                return url_for("packages.download",
                                author=self.author.username, name=self.name)
 
+       def getEditMaintainersURL(self):
+               return url_for("packages.edit_maintainers",
+                               author=self.author.username, name=self.name)
+
        def getDownloadRelease(self, version=None):
                for rel in self.releases:
                        if rel.approved and (version is None or
@@ -658,19 +670,17 @@ class Package(db.Model):
                        raise Exception("Unknown permission given to Package.checkPerm()")
 
                isOwner = user == self.author
+               isMaintainer = isOwner or user.rank.atLeast(UserRank.EDITOR) or user in self.maintainers
 
                if perm == Permission.CREATE_THREAD:
                        return user.rank.atLeast(UserRank.MEMBER)
 
                # Members can edit their own packages, and editors can edit any packages
-               if perm == Permission.MAKE_RELEASE or perm == Permission.ADD_SCREENSHOTS:
-                       return isOwner or user.rank.atLeast(UserRank.EDITOR)
+               elif perm == Permission.MAKE_RELEASE or perm == Permission.ADD_SCREENSHOTS:
+                       return isMaintainer
 
-               if perm == Permission.EDIT_PACKAGE or perm == Permission.APPROVE_CHANGES or perm == Permission.APPROVE_RELEASE:
-                       if isOwner:
-                               return user.rank.atLeast(UserRank.MEMBER if self.approved else UserRank.NEW_MEMBER)
-                       else:
-                               return user.rank.atLeast(UserRank.EDITOR)
+               elif perm == Permission.EDIT_PACKAGE or perm == Permission.APPROVE_CHANGES or perm == Permission.APPROVE_RELEASE:
+                       return isMaintainer 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:
@@ -681,10 +691,10 @@ class Package(db.Model):
                        return user.rank.atLeast(UserRank.EDITOR)
 
                elif perm == Permission.APPROVE_SCREENSHOT:
-                       if isOwner:
-                               return user.rank.atLeast(UserRank.TRUSTED_MEMBER if self.approved else UserRank.NEW_MEMBER)
-                       else:
-                               return user.rank.atLeast(UserRank.EDITOR)
+                       return isMaintainer and user.rank.atLeast(UserRank.TRUSTED_MEMBER if self.approved else UserRank.NEW_MEMBER)
+
+               elif perm == Permission.EDIT_MAINTAINERS:
+                       return isOwner or user.rank.atLeast(UserRank.MODERATOR)
 
                # Moderators can delete packages
                elif perm == Permission.DELETE_PACKAGE or perm == Permission.UNAPPROVE_PACKAGE \
@@ -1077,10 +1087,12 @@ class Thread(db.Model):
                elif type(perm) != Permission:
                        raise Exception("Unknown permission given to Thread.checkPerm()")
 
-               isOwner = user == self.author or (self.package is not None and self.package.author == user)
+               isMaintainer = user == self.author or (self.package is not None and self.package.author == user)
+               if self.package:
+                       isMaintainer = isMaintainer or user in self.package.maintainers
 
                if perm == Permission.SEE_THREAD:
-                       return not self.private or isOwner or user.rank.atLeast(UserRank.EDITOR)
+                       return not self.private or isMaintainer or user.rank.atLeast(UserRank.EDITOR)
 
                else:
                        raise Exception("Permission {} is not related to threads".format(perm.name))
diff --git a/app/templates/packages/edit_maintainers.html b/app/templates/packages/edit_maintainers.html
new file mode 100644 (file)
index 0000000..c3b51d8
--- /dev/null
@@ -0,0 +1,19 @@
+{% extends "base.html" %}
+
+{% block title %}
+       {{ _("Edit Maintainers") }}
+{% endblock %}
+
+{% from "macros/forms.html" import render_submit_field, render_field %}
+
+{% block content %}
+       <h1>{{ _("Edit Maintainers") }}</h1>
+
+       <form method="POST" action="" class="tableform">
+               {{ form.hidden_tag() }}
+
+               {{ render_field(form.maintainers_str) }}
+
+               <div>{{ render_submit_field(form.submit) }}</div>
+       </form>
+{% endblock %}
index f6889e04487ad8e2284254bf2674c686ea788e3d..3885aca87b5b9cf1b7bf585924110db01a98b226 100644 (file)
                                                <td>Added</td>
                                                <td>{{ package.created_at | datetime }}</td>
                                        </tr>
+                                       <tr>
+                                               <td>Maintainers</td>
+                                               <td>
+                                                       {% if package.checkPerm(current_user, "EDIT_MAINTAINERS") %}
+                                                               <a class="btn btn-primary btn-sm ml-1 float-right" href="{{ package.getEditMaintainersURL() }}"><i class="fas fa-edit"></i></a>
+                                                       {% endif %}
+
+                                                       {% for user in package.maintainers %}
+                                                               <a class="badge badge-primary"
+                                                                       href="{{ url_for('users.profile', username=package.author.username) }}">
+                                                                       {{ user.display_name }}
+                                                               </a>
+                                                       {% endfor %}
+                                               </td>
+                                       </tr>
                                </table>
                        </div>
 
diff --git a/migrations/versions/cb6ab141c522_.py b/migrations/versions/cb6ab141c522_.py
new file mode 100644 (file)
index 0000000..33da88b
--- /dev/null
@@ -0,0 +1,45 @@
+"""empty message
+
+Revision ID: cb6ab141c522
+Revises: 7a48dbd05780
+Create Date: 2020-07-08 21:03:51.856561
+
+"""
+from alembic import op
+import sqlalchemy as sa
+from sqlalchemy import orm
+from app.models import Package
+
+
+# revision identifiers, used by Alembic.
+revision = 'cb6ab141c522'
+down_revision = '7a48dbd05780'
+branch_labels = None
+depends_on = None
+
+
+def upgrade():
+       # ### commands auto generated by Alembic - please adjust! ###
+       op.create_table('maintainers',
+       sa.Column('user_id', sa.Integer(), nullable=False),
+       sa.Column('package_id', sa.Integer(), nullable=False),
+       sa.ForeignKeyConstraint(['package_id'], ['package.id'], ),
+       sa.ForeignKeyConstraint(['user_id'], ['user.id'], ),
+       sa.PrimaryKeyConstraint('user_id', 'package_id')
+       )
+
+       bind = op.get_bind()
+       session = orm.Session(bind=bind)
+
+       for package in session.query(Package).all():
+               package.maintainers.append(package.author)
+
+       session.commit()
+
+       # ### end Alembic commands ###
+
+
+def downgrade():
+       # ### commands auto generated by Alembic - please adjust! ###
+       op.drop_table('maintainers')
+       # ### end Alembic commands ###