]> git.lizzy.rs Git - cheatdb.git/blobdiff - app/views/packages.py
Add file upload for releases
[cheatdb.git] / app / views / packages.py
index 4543503f0f07486aef0bc3feb694a794129a9208..4e221a5663911a06f69476ccb195d23306e9f50c 100644 (file)
@@ -6,28 +6,72 @@ from app.models import *
 
 from flask_wtf import FlaskForm
 from wtforms import *
+from wtforms.validators import *
 
+def isFilenameAllowed(filename, exts):
+       return "." in filename and \
+                  filename.rsplit(".", 1)[1].lower() in exts
 
-# TODO: the following could be made into one route, except I'm not sure how
+
+# TODO: the following could be made into one route, except I"m not sure how
 # to do the menu
 
-@app.route('/mods/')
-@menu.register_menu(app, '.mods', 'Mods', order=10)
+def doPackageList(type):
+       title = "Packages"
+       query = Package.query
+
+       if type is not None:
+               title = type.value + "s"
+               query = query.filter_by(type=type, approved=True)
+
+       search = request.args.get("q")
+       if search is not None:
+               query = query.filter(Package.title.contains(search))
+
+       return render_template("packages/list.html", title=title, packages=query.all(), query=search)
+
+@app.route("/packages/")
+def packages_page():
+       return doPackageList(None)
+
+@app.route("/mods/")
+@menu.register_menu(app, ".mods", "Mods", order=11)
 def mods_page():
-       packages = Package.query.filter_by(type=PackageType.MOD).all()
-       return render_template('packages.html', title="Mods", packages=packages)
+       return doPackageList(PackageType.MOD)
 
-@app.route('/games/')
-@menu.register_menu(app, '.games', 'Games', order=11)
+@app.route("/games/")
+@menu.register_menu(app, ".games", "Games", order=12)
 def games_page():
-       packages = Package.query.filter_by(type=PackageType.GAME).all()
-       return render_template('packages.html', title="Games", packages=packages)
+       return doPackageList(PackageType.GAME)
 
-@app.route('/texturepacks/')
-@menu.register_menu(app, '.txp', 'Texture Packs', order=12)
+@app.route("/texturepacks/")
+@menu.register_menu(app, ".txp", "Texture Packs", order=13)
 def txp_page():
-       packages = Package.query.filter_by(type=PackageType.TXP).all()
-       return render_template('packages.html', title="Texture Packs", packages=packages)
+       return doPackageList(PackageType.TXP)
+
+def canSeeWorkQueue():
+       return Permission.APPROVE_NEW.check(current_user) or \
+               Permission.APPROVE_RELEASE.check(current_user) or \
+                       Permission.APPROVE_CHANGES.check(current_user)
+
+@menu.register_menu(app, ".todo", "Work Queue", order=20, visible_when=canSeeWorkQueue)
+@app.route("/todo/")
+@login_required
+def todo_page():
+       canApproveNew = Permission.APPROVE_NEW.check(current_user)
+       canApproveRel = Permission.APPROVE_RELEASE.check(current_user)
+
+       packages = None
+       if canApproveNew:
+               packages = Package.query.filter_by(approved=False).all()
+
+       releases = None
+       if canApproveRel:
+               releases = PackageRelease.query.filter_by(approved=False).all()
+
+       return render_template("todo.html", title="Reports and Work Queue",
+               approve_new=packages, releases=releases,
+               canApproveNew=canApproveNew, canApproveRel=canApproveRel)
 
 
 def getPageByInfo(type, author, name):
@@ -54,48 +98,102 @@ def package_page(type, author, name):
        package = getPageByInfo(type, author, name)
        releases = getReleases(package)
 
-       return render_template('package_details.html', package=package, releases=releases)
+       return render_template("packages/view.html", package=package, releases=releases)
+
+@app.route("/<type>s/<author>/<name>/download/")
+def package_download_page(type, author, name):
+       package = getPageByInfo(type, author, name)
+       release = package.getDownloadRelease()
+
+       if release is None:
+               wantsJson = "application/zip" in request.accept_mimetypes and \
+                               not "text/html" in request.accept_mimetypes
+
+               if wantsJson:
+                       return "", 204
+               else:
+                       flash("No download available.", "error")
+                       return redirect(package.getDetailsURL())
+       else:
+               return redirect(release.url, code=302)
 
 
 class PackageForm(FlaskForm):
-       name         = StringField("Name")
-       title        = StringField("Title")
-       shortDesc    = StringField("Short Description")
-       desc         = StringField("Long Description")
-       type         = SelectField("Type", choices=PackageType.choices(), coerce=PackageType.coerce)
-       repo         = StringField("Repo URL")
-       website      = StringField("Website URL")
-       issueTracker = StringField("Issue Tracker URL")
-       forums       = StringField("Forum Topic ID")
-       submit       = SubmitField('Save')
-
-@app.route("/<type>s/<author>/<name>/edit/", methods=['GET', 'POST'])
+       name             = StringField("Name", [InputRequired(), Length(1, 20), Regexp("^[a-z0-9_]", 0, "Lower case letters (a-z), digits (0-9), and underscores (_) only")])
+       title           = StringField("Title", [InputRequired(), Length(3, 50)])
+       shortDesc       = StringField("Short Description", [InputRequired(), Length(1,200)])
+       desc             = TextAreaField("Long Description", [Optional(), Length(0,10000)])
+       type             = SelectField("Type", [InputRequired()], choices=PackageType.choices(), coerce=PackageType.coerce, default=PackageType.MOD)
+       repo             = StringField("Repo URL", [Optional(), URL()])
+       website   = StringField("Website URL", [Optional(), URL()])
+       issueTracker = StringField("Issue Tracker URL", [Optional(), URL()])
+       forums     = IntegerField("Forum Topic ID", [InputRequired(), NumberRange(0,999999)])
+       submit     = SubmitField("Save")
+
+@menu.register_menu(app, ".new", "Create", order=21, visible_when=lambda: current_user.is_authenticated)
+@app.route("/new/", methods=["GET", "POST"])
+@app.route("/<type>s/<author>/<name>/edit/", methods=["GET", "POST"])
 @login_required
-def edit_package_page(type, author, name):
-       package = getPageByInfo(type, author, name)
-       if not package.checkPerm(current_user, Permission.EDIT_PACKAGE):
-               return redirect(package.getDetailsURL())
+def create_edit_package_page(type=None, author=None, name=None):
+       package = None
+       form = None
+       if type is None:
+               form = PackageForm(formdata=request.form)
+       else:
+               package = getPageByInfo(type, author, name)
+               if not package.checkPerm(current_user, Permission.EDIT_PACKAGE):
+                       return redirect(package.getDetailsURL())
+
+               form = PackageForm(formdata=request.form, obj=package)
 
        # Initial form class from post data and default data
-       form = PackageForm(formdata=request.form, obj=package)
        if request.method == "POST" and form.validate():
                # Successfully submitted!
+               if not package:
+                       package = Package()
+                       package.author = current_user
+                       # package.approved = package.checkPerm(current_user, Permission.APPROVE_NEW)
+
                form.populate_obj(package) # copy to row
                db.session.commit() # save
                return redirect(package.getDetailsURL()) # redirect
 
-       return render_template('package_edit.html', package=package, form=form)
+       return render_template("packages/create_edit.html", package=package, form=form)
+
+@app.route("/<type>s/<author>/<name>/approve/")
+@login_required
+def approve_package_page(type=None, author=None, name=None):
+       package = getPageByInfo(type, author, name)
+
+       if not package.checkPerm(current_user, Permission.APPROVE_NEW):
+               flash("You don't have permission to do that.", "error")
+
+       elif package.approved:
+               flash("Package has already been approved", "error")
+
+       else:
+               package.approved = True
+               db.session.commit()
 
 
-class PackageReleaseForm(FlaskForm):
-       name         = StringField("Name")
-       title        = StringField("Title")
-       uploadOpt    = RadioField ("File", choices=[("vcs", "From VCS Commit or Branch"), ("upload", "File Upload")])
-       vcsLabel     = StringField("VCS Commit or Branch", default="master")
+       return redirect(package.getDetailsURL())
+
+class CreatePackageReleaseForm(FlaskForm):
+       name             = StringField("Name")
+       title           = StringField("Title")
+       uploadOpt       = RadioField ("File", choices=[("vcs", "From VCS Commit or Branch"), ("upload", "File Upload")])
+       vcsLabel         = StringField("VCS Commit or Branch", default="master")
        fileUpload   = FileField("File Upload")
-       submit       = SubmitField('Save')
+       submit     = SubmitField("Save")
+
+class EditPackageReleaseForm(FlaskForm):
+       name             = StringField("Name")
+       title           = StringField("Title")
+       url               = StringField("URL", [URL])
+       approved         = BooleanField("Is Approved")
+       submit     = SubmitField("Save")
 
-@app.route("/<type>s/<author>/<name>/releases/new/", methods=['GET', 'POST'])
+@app.route("/<type>s/<author>/<name>/releases/new/", methods=["GET", "POST"])
 @login_required
 def create_release_page(type, author, name):
        package = getPageByInfo(type, author, name)
@@ -103,8 +201,10 @@ def create_release_page(type, author, name):
                return redirect(package.getDetailsURL())
 
        # Initial form class from post data and default data
-       form = PackageReleaseForm(formdata=request.form)
+       form = CreatePackageReleaseForm()
        if request.method == "POST" and form.validate():
+               for key, value in request.files.items() :
+                       print (key, value)
                if form["uploadOpt"].data == "vcs":
                        rel = PackageRelease()
                        rel.package = package
@@ -112,8 +212,63 @@ def create_release_page(type, author, name):
                        rel.url = form["vcsLabel"].data
                        # TODO: get URL to commit from branch name
                        db.session.commit()
-                       return redirect(package.getDetailsURL()) # redirect
+                       return redirect(package.getDetailsURL())
                else:
-                       raise Exception("Unimplemented option = file upload")
+                       file = form.fileUpload.data
+                       if not file or file.filename == "":
+                               flash("No selected file", "error")
+                       elif not isFilenameAllowed(file.filename, ["zip"]):
+                               flash("Please select a zip file", "error")
+                       else:
+                               import random, string, os
+                               filename = ''.join(random.choice(string.ascii_lowercase + string.ascii_uppercase + string.digits) for _ in range(10)) + ".zip"
+                               file.save(os.path.join(app.config["UPLOAD_FOLDER"], filename))
+
+                               rel = PackageRelease()
+                               rel.package = package
+                               rel.title = form["title"].data
+                               rel.url = "/uploads/" + filename
+                               db.session.commit()
+                               return redirect(package.getDetailsURL())
+
+       return render_template("packages/release_new.html", package=package, form=form)
+
+@app.route("/<type>s/<author>/<name>/releases/<id>/", methods=["GET", "POST"])
+@login_required
+def edit_release_page(type, author, name, id):
+       user = User.query.filter_by(username=author).first()
+       if user is None:
+               abort(404)
+
+       release = PackageRelease.query.filter_by(id=id).first()
+       if release is None:
+               abort(404)
+
+       package = release.package
+       if package.name != name or package.type != PackageType[type.upper()]:
+               abort(404)
+
+       canEdit = package.checkPerm(current_user, Permission.MAKE_RELEASE)
+       canApprove = package.checkPerm(current_user, Permission.APPROVE_RELEASE)
+       if not (canEdit or canApprove):
+               return redirect(package.getDetailsURL())
+
+       # Initial form class from post data and default data
+       form = EditPackageReleaseForm(formdata=request.form, obj=release)
+       if request.method == "POST" and form.validate():
+               wasApproved = release.approved
+               if canEdit:
+                       release.title = form["title"].data
+
+               if package.checkPerm(current_user, Permission.CHANGE_RELEASE_URL):
+                       release.url = form["url"].data
+
+               if canApprove:
+                       release.approved = form["approved"].data
+               else:
+                       release.approved = wasApproved
+
+               db.session.commit()
+               return redirect(package.getDetailsURL())
 
-       return render_template('package_release_new.html', package=package, form=form)
+       return render_template("packages/release_edit.html", package=package, release=release, form=form)