def collection_new(): ''' Page to create a new collection. ''' clt_status = pkgdblib.get_status(SESSION, 'clt_status')['clt_status'] form = pkgdb2.forms.AddCollectionForm(clt_status=clt_status) if form.validate_on_submit(): clt_name = form.collection_name.data clt_version = form.collection_version.data clt_status = form.collection_status.data clt_branchname = form.collection_branchname.data clt_disttag = form.collection_distTag.data clt_gitbranch = form.collection_git_branch_name.data clt_koji_name = form.collection_kojiname.data try: message = pkgdblib.add_collection( SESSION, clt_name=clt_name, clt_version=clt_version, clt_status=clt_status, clt_branchname=clt_branchname, clt_disttag=clt_disttag, clt_gitbranch=clt_gitbranch, clt_koji_name=clt_koji_name, user=flask.g.fas_user, ) SESSION.commit() flask.flash(message) return flask.redirect(flask.url_for('.list_collections')) # In theory we should never hit this except pkgdblib.PkgdbException, err: # pragma: no cover SESSION.rollback() flask.flash(str(err), 'errors')
def collection_new(): ''' Page to create a new collection. ''' clt_status = pkgdblib.get_status(SESSION, 'clt_status')['clt_status'] form = pkgdb2.forms.AddCollectionForm(clt_status=clt_status) if form.validate_on_submit(): clt_name = form.collection_name.data clt_version = form.collection_version.data clt_status = form.collection_status.data clt_branchname = form.collection_branchname.data clt_disttag = form.collection_distTag.data clt_gitbranch = form.collection_git_branch_name.data clt_koji_name = form.collection_kojiname.data try: message = pkgdblib.add_collection( SESSION, clt_name=clt_name, clt_version=clt_version, clt_status=clt_status, clt_branchname=clt_branchname, clt_disttag=clt_disttag, clt_gitbranch=clt_gitbranch, clt_koji_name=clt_koji_name, user=flask.g.fas_user, ) SESSION.commit() flask.flash(message) return flask.redirect(flask.url_for('.list_collections')) # In theory we should never hit this except pkgdblib.PkgdbException, err: # pragma: no cover SESSION.rollback() flask.flash(str(err), 'errors')
def admin_namespaces(): """ Shows all the existing namespaces. """ namespaces = pkgdblib.get_status(SESSION, "namespaces")["namespaces"] form = pkgdb2.forms.NamespaceForm() return flask.render_template("admin_namespaces.html", namespaces=namespaces, form=form)
def admin_action_edit_status(action_id): """ Edit Admin Action status update """ admin_action = pkgdblib.get_admin_action(SESSION, action_id) if not admin_action: flask.flash("No action found with this identifier.", "errors") return flask.render_template("msg.html") action_status = pkgdblib.get_status(SESSION, "admin_status")["admin_status"] form = pkgdb2.forms.EditActionStatusForm(status=action_status, obj=admin_action) form.id.data = action_id if form.validate_on_submit(): try: message = pkgdblib.edit_action_status( SESSION, admin_action, action_status=form.status.data, user=flask.g.fas_user, message=form.message.data ) SESSION.commit() flask.flash(message) except pkgdblib.PkgdbException, err: # pragma: no cover # We can only reach here in two cases: # 1) the user is not an admin, but that's taken care of # by the decorator # 2) we have a SQLAlchemy problem when storing the info # in the DB which we cannot test SESSION.rollback() flask.flash(err, "errors") return flask.render_template("msg.html") return flask.redirect(flask.url_for(".admin_actions"))
def api_collection_status(collection): ''' Update collection status ------------------------ Update the status of collection. :: /api/collection/<collection branchname>/status/ Accepts POST query only. :arg branch: String of the collection branch name to change. :arg clt_status: String of the status to change the collection to Sample response: :: { "output": "ok", "messages": ["Collection updated to \"EOL\""] } { "output": "notok", "error": ["You are not allowed to edit collections"] } ''' httpcode = 200 output = {} clt_status = pkgdblib.get_status(SESSION, 'clt_status')['clt_status'] form = forms.CollectionStatusForm( csrf_enabled=False, clt_status=clt_status, ) if form.validate_on_submit(): clt_branchname = form.branch.data clt_status = form.clt_status.data if collection == clt_branchname: try: message = pkgdblib.update_collection_status( SESSION, clt_branchname, clt_status, user=flask.g.fas_user) SESSION.commit() output['output'] = 'ok' output['messages'] = [message] except pkgdblib.PkgdbException, err: SESSION.rollback() output['output'] = 'notok' output['error'] = str(err) httpcode = 500 else: output['output'] = 'notok' output['error'] = "You're trying to update the " \ "wrong collection" httpcode = 500
def giveup_acl(namespace, package, acl): ''' Request acls for a specific package. ''' form = pkgdb2.forms.ConfirmationForm() if form.validate_on_submit(): pkg_acl = pkgdblib.get_status(SESSION, 'pkg_acl')['pkg_acl'] if acl not in pkg_acl: flask.flash('Invalid ACL provided %s.' % acl, 'errors') return flask.render_template('msg.html') try: pkg = pkgdblib.search_package( SESSION, namespace=namespace, pkg_name=package, limit=1)[0] except IndexError: flask.flash('No package found by this name', 'error') return flask.redirect(flask.url_for( '.package_info', namespace=namespace, package=package)) pkg_branchs = set([ pkglist.collection.branchname for pkglist in pkg.listings if pkglist.collection.status in ['Active', 'Under Development'] and flask.g.fas_user.username in [tmpacl.fas_name for tmpacl in pkglist.acls] ]) if not pkg_branchs: flask.flash( 'No active branches found for you for the ACL: %s' % acl, 'error') return flask.redirect(flask.url_for( '.package_info', namespace=namespace, package=package)) for branch in pkg_branchs: print package, namespace, branch, acl, flask.g.fas_user.username try: pkgdblib.set_acl_package( SESSION, namespace=namespace, pkg_name=package, pkg_branch=branch, pkg_user=flask.g.fas_user.username, acl=acl, status='Obsolete', user=flask.g.fas_user, ) flask.flash( 'Your ACL %s is obsoleted on branch %s of package %s' % (acl, branch, package)) except pkgdblib.PkgdbException, err: # pragma: no cover flask.flash(str(err), 'error') SESSION.rollback() try: SESSION.commit() # Keep it in, but normally we shouldn't hit this except pkgdblib.PkgdbException, err: # pragma: no cover SESSION.rollback() flask.flash(str(err), 'error')
def package_give_acls(namespace, package): ''' Give acls to a specified user for a specific package. ''' try: pkg = pkgdblib.search_package(SESSION, namespace=namespace, pkg_name=package, limit=1)[0] except IndexError: flask.flash('No package found by this name', 'error') return flask.redirect(flask.url_for('.list_packages')) collections = [ pkglist.collection for pkglist in pkg.listings if pkglist.collection.status != 'EOL' ] acls = pkgdblib.get_status(SESSION) form = pkgdb2.forms.SetAclPackageForm( collections_obj=collections, pkg_acl=acls['pkg_acl'], acl_status=acls['acl_status'], namespaces=acls['namespaces'], ) form.pkgname.data = package if str(form.namespace.data) in ['None', '']: form.namespace.data = 'rpms' if form.validate_on_submit(): pkg_branchs = form.branches.data pkg_acls = form.acl.data pkg_user = form.user.data acl_status = form.acl_status.data try: for (collec, acl) in itertools.product(pkg_branchs, pkg_acls): if acl in APP.config['AUTO_APPROVE']: acl_status = 'Approved' pkgdblib.set_acl_package( SESSION, namespace=namespace, pkg_name=package, pkg_branch=collec, pkg_user=pkg_user, acl=acl, status=acl_status, user=flask.g.fas_user, ) SESSION.commit() flask.flash('ACLs updated') return flask.redirect( flask.url_for('.package_info', namespace=namespace, package=package)) except pkgdblib.PkgdbException, err: SESSION.rollback() flask.flash(str(err), 'error')
def giveup_acl(package, acl): ''' Request acls for a specific package. ''' form = pkgdb2.forms.ConfirmationForm() if form.validate_on_submit(): pkg_acl = pkgdblib.get_status(SESSION, 'pkg_acl')['pkg_acl'] if acl not in pkg_acl: flask.flash('Invalid ACL provided %s.' % acl, 'errors') return flask.render_template('msg.html') try: pkg = pkgdblib.search_package( SESSION, pkg_name=package, limit=1)[0] except IndexError: flask.flash('No package found by this name', 'error') return flask.redirect( flask.url_for('.package_info', package=package)) pkg_branchs = set([ pkglist.collection.branchname for pkglist in pkg.listings if pkglist.collection.status in ['Active', 'Under Development'] and flask.g.fas_user.username in [tmpacl.fas_name for tmpacl in pkglist.acls] ]) if not pkg_branchs: flask.flash( 'No active branches found for you for the ACL: %s' % acl, 'error') return flask.redirect( flask.url_for('.package_info', package=package)) for branch in pkg_branchs: try: pkgdblib.set_acl_package( SESSION, pkg_name=package, pkg_branch=branch, pkg_user=flask.g.fas_user.username, acl=acl, status='Obsolete', user=flask.g.fas_user, ) flask.flash( 'Your ACL %s is obsoleted on branch %s of package %s' % (acl, branch, package)) except pkgdblib.PkgdbException, err: flask.flash(str(err), 'error') SESSION.rollback() try: SESSION.commit() # Keep it in, but normally we shouldn't hit this except pkgdblib.PkgdbException, err: # pragma: no cover SESSION.rollback() flask.flash(str(err), 'error')
def update_acl(package, user, branch=None): ''' Update the acls for a specific user on a package. ''' pending_acls = pkgdblib.get_acl_user_package(SESSION, user, package, status=None) pending_acls2 = [] if branch is not None: for acls in pending_acls: if acls['collection'] == branch: pending_acls2.append(acls) else: for acls in pending_acls: if acls['collection_status'] != 'EOL': pending_acls2.append(acls) pending_acls = pending_acls2 collections = set([item['collection'] for item in pending_acls]) status = pkgdblib.get_status(SESSION, ['pkg_acl', 'acl_status']) form = pkgdb2.forms.UpdateAclPackageForm( collections=collections, pkg_acl_list=status['pkg_acl'], acl_status=status['acl_status'], ) if form.validate_on_submit(): pkg_branchs = form.pkg_branch.data pkg_acls = form.pkg_acl.data acl_status = form.acl_status.data try: for (collec, acl) in itertools.product(pkg_branchs, pkg_acls): if acl_status == 'Awaiting Review' and \ acl in APP.config['AUTO_APPROVE']: acl_status = 'Approved' pkgdblib.set_acl_package( SESSION, pkg_name=package, pkg_branch=collec, pkg_user=user, acl=acl, status=acl_status, user=flask.g.fas_user, ) flask.flash('ACLs updated') SESSION.commit() return flask.redirect( flask.url_for('.package_info', package=package)) # Let's keep this in although we should never see it except pkgdblib.PkgdbException, err: # pragma: no cover SESSION.rollback() flask.flash(str(err), 'errors')
def request_acl(namespace, package): ''' Request acls for a specific package. ''' try: package_acl = pkgdblib.get_acl_package(SESSION, namespace, package) package = pkgdblib.search_package(SESSION, namespace, package, limit=1)[0] except (NoResultFound, IndexError): SESSION.rollback() flask.flash('No package of this name found.', 'errors') return flask.render_template('msg.html') collections = [ acl.collection for acl in package_acl if acl.collection.status in ['Active', 'Under Development'] ] pkg_acl = pkgdblib.get_status(SESSION, 'pkg_acl')['pkg_acl'] form = pkgdb2.forms.RequestAclPackageForm(collections=collections, pkg_acl_list=pkg_acl) if form.validate_on_submit(): pkg_branchs = form.branches.data pkg_acls = form.acl.data try: for (collec, acl) in itertools.product(pkg_branchs, pkg_acls): acl_status = 'Awaiting Review' if acl in APP.config['AUTO_APPROVE']: acl_status = 'Approved' elif 'packager' not in flask.g.fas_user.groups: flask.flash( 'You must be a packager to apply to the' ' ACL: %s on %s' % (acl, collec), 'errors') continue pkgdblib.set_acl_package( SESSION, namespace=namespace, pkg_name=package.name, pkg_branch=collec, pkg_user=flask.g.fas_user.username, acl=acl, status=acl_status, user=flask.g.fas_user, ) SESSION.commit() flask.flash('ACLs updated') return flask.redirect( flask.url_for('.package_info', namespace=package.namespace, package=package.name)) except pkgdblib.PkgdbException, err: SESSION.rollback() flask.flash(str(err), 'error')
def package_give_acls(namespace, package): ''' Give acls to a specified user for a specific package. ''' try: pkg = pkgdblib.search_package( SESSION, namespace=namespace, pkg_name=package, limit=1)[0] except IndexError: flask.flash('No package found by this name', 'error') return flask.redirect( flask.url_for('.list_packages')) collections = [ pkglist.collection for pkglist in pkg.listings if pkglist.collection.status != 'EOL'] acls = pkgdblib.get_status(SESSION) form = pkgdb2.forms.SetAclPackageForm( collections_obj=collections, pkg_acl=acls['pkg_acl'], acl_status=acls['acl_status'], namespaces=acls['namespaces'], ) form.pkgname.data = package if str(form.namespace.data) in ['None', '']: form.namespace.data = 'rpms' if form.validate_on_submit(): pkg_branchs = form.branches.data pkg_acls = form.acl.data pkg_user = form.user.data acl_status = form.acl_status.data try: for (collec, acl) in itertools.product(pkg_branchs, pkg_acls): if acl in APP.config['AUTO_APPROVE']: acl_status = 'Approved' pkgdblib.set_acl_package( SESSION, namespace=namespace, pkg_name=package, pkg_branch=collec, pkg_user=pkg_user, acl=acl, status=acl_status, user=flask.g.fas_user, ) SESSION.commit() flask.flash('ACLs updated') return flask.redirect(flask.url_for( '.package_info', namespace=namespace, package=package)) except pkgdblib.PkgdbException, err: SESSION.rollback() flask.flash(str(err), 'error')
def update_acl(package, user, branch=None): ''' Update the acls for a specific user on a package. ''' pending_acls = pkgdblib.get_acl_user_package( SESSION, user, package, status=None) pending_acls2 = [] if branch is not None: for acls in pending_acls: if acls['collection'] == branch: pending_acls2.append(acls) else: for acls in pending_acls: if acls['collection_status'] != 'EOL': pending_acls2.append(acls) pending_acls = pending_acls2 collections = set([item['collection'] for item in pending_acls]) status = pkgdblib.get_status(SESSION, ['pkg_acl', 'acl_status']) form = pkgdb2.forms.UpdateAclPackageForm( collections=collections, pkg_acl_list=status['pkg_acl'], acl_status=status['acl_status'], ) if form.validate_on_submit(): pkg_branchs = form.pkg_branch.data pkg_acls = form.pkg_acl.data acl_status = form.acl_status.data try: for (collec, acl) in itertools.product(pkg_branchs, pkg_acls): if acl_status == 'Awaiting Review' and \ acl in APP.config['AUTO_APPROVE']: acl_status = 'Approved' pkgdblib.set_acl_package( SESSION, pkg_name=package, pkg_branch=collec, pkg_user=user, acl=acl, status=acl_status, user=flask.g.fas_user, ) flask.flash('ACLs updated') SESSION.commit() return flask.redirect( flask.url_for('.package_info', package=package)) # Let's keep this in although we should never see it except pkgdblib.PkgdbException, err: # pragma: no cover SESSION.rollback() flask.flash(str(err), 'errors')
def request_acl_all_branch(namespace, package, acl): ''' Request the specified ACL on all branches of the specified package. ''' form = pkgdb2.forms.ConfirmationForm() if form.validate_on_submit(): pkg_acl = pkgdblib.get_status(SESSION, 'pkg_acl')['pkg_acl'] if acl not in pkg_acl: flask.flash('Invalid ACL provided %s.' % acl, 'errors') return flask.render_template('msg.html') try: pkg = pkgdblib.search_package( SESSION, namespace=namespace, pkg_name=package, limit=1)[0] except IndexError: flask.flash('No package found by this name', 'error') return flask.render_template('msg.html') pkg_branchs = set([ pkglist.collection.branchname for pkglist in pkg.listings if pkglist.collection.status in ['Active', 'Under Development'] and pkglist.status == 'Approved' ]) for branch in pkg_branchs: acl_status = 'Awaiting Review' pkger_grp = APP.config.get('PKGER_GROUP', 'packager') if acl in APP.config['AUTO_APPROVE']: acl_status = 'Approved' elif pkger_grp not in flask.g.fas_user.groups: flask.flash( 'You must be a %s to apply to the ACL: %s on %s' % ( pkger_grp, acl, package), 'error') try: pkgdblib.set_acl_package( SESSION, namespace=namespace, pkg_name=package, pkg_branch=branch, pkg_user=flask.g.fas_user.username, acl=acl, status=acl_status, user=flask.g.fas_user, ) flask.flash( 'ACL %s requested on branch %s' % (acl, branch)) SESSION.commit() except PkgdbException as err: SESSION.rollback() flask.flash(str(err), 'error') return flask.redirect(flask.url_for( '.package_info', namespace=namespace, package=package))
def request_acl_all_branch(namespace, package, acl): ''' Request the specified ACL on all branches of the specified package. ''' form = pkgdb2.forms.ConfirmationForm() if form.validate_on_submit(): pkg_acl = pkgdblib.get_status(SESSION, 'pkg_acl')['pkg_acl'] if acl not in pkg_acl: flask.flash('Invalid ACL provided %s.' % acl, 'errors') return flask.render_template('msg.html') try: pkg = pkgdblib.search_package(SESSION, namespace=namespace, pkg_name=package, limit=1)[0] except IndexError: flask.flash('No package found by this name', 'error') return flask.render_template('msg.html') pkg_branchs = set([ pkglist.collection.branchname for pkglist in pkg.listings if pkglist.collection.status in ['Active', 'Under Development'] and pkglist.status == 'Approved' ]) for branch in pkg_branchs: acl_status = 'Awaiting Review' pkger_grp = APP.config.get('PKGER_GROUP', 'packager') if acl in APP.config['AUTO_APPROVE']: acl_status = 'Approved' elif pkger_grp not in flask.g.fas_user.groups: flask.flash( 'You must be a %s to apply to the ACL: %s on %s' % (pkger_grp, acl, package), 'error') try: pkgdblib.set_acl_package( SESSION, namespace=namespace, pkg_name=package, pkg_branch=branch, pkg_user=flask.g.fas_user.username, acl=acl, status=acl_status, user=flask.g.fas_user, ) flask.flash('ACL %s requested on branch %s' % (acl, branch)) SESSION.commit() except PkgdbException as err: SESSION.rollback() flask.flash(str(err), 'error') return flask.redirect( flask.url_for('.package_info', namespace=namespace, package=package))
def collection_edit(collection): ''' Allows to edit the information about the specified collection. ''' try: collection = pkgdblib.search_collection(SESSION, collection)[0] except IndexError: flask.flash('No collection of this name found.', 'errors') return flask.render_template('msg.html') clt_status = pkgdblib.get_status(SESSION, 'clt_status')['clt_status'] form = pkgdb2.forms.AddCollectionForm( clt_status=clt_status ) if form.validate_on_submit(): clt_name = form.clt_name.data clt_version = form.version.data clt_status = form.clt_status.data clt_branchname = form.branchname.data clt_disttag = form.dist_tag.data clt_koji_name = form.kojiname.data clt_allow_retire = form.allow_retire.data try: pkgdblib.edit_collection( SESSION, collection=collection, clt_name=clt_name, clt_version=clt_version, clt_status=clt_status, clt_branchname=clt_branchname, clt_disttag=clt_disttag, clt_koji_name=clt_koji_name, clt_allow_retire=clt_allow_retire, user=flask.g.fas_user, ) SESSION.commit() flask.flash('Collection "%s" edited' % clt_branchname) return flask.redirect(flask.url_for( '.collection_info', collection=collection.branchname)) # In theory we should never hit this except PkgdbException as err: # pragma: no cover SESSION.rollback() flask.flash(str(err), 'errors') elif flask.request.method == 'GET': form = pkgdb2.forms.AddCollectionForm( clt_status=clt_status, collection=collection ) return flask.render_template( 'collection_edit.html', form=form, collection=collection, )
def request_acl(package): ''' Request acls for a specific package. ''' try: package_acl = pkgdblib.get_acl_package(SESSION, package) package = pkgdblib.search_package(SESSION, package, limit=1)[0] except (NoResultFound, IndexError): SESSION.rollback() flask.flash('No package of this name found.', 'errors') return flask.render_template('msg.html') collections = [ acl.collection for acl in package_acl if acl.collection.status in ['Active', 'Under Development'] ] pkg_acl = pkgdblib.get_status(SESSION, 'pkg_acl')['pkg_acl'] form = pkgdb2.forms.RequestAclPackageForm( collections=collections, pkg_acl_list=pkg_acl ) if form.validate_on_submit(): pkg_branchs = form.branches.data pkg_acls = form.acl.data try: for (collec, acl) in itertools.product(pkg_branchs, pkg_acls): acl_status = 'Awaiting Review' if acl in APP.config['AUTO_APPROVE']: acl_status = 'Approved' elif 'packager' not in flask.g.fas_user.groups: flask.flash( 'You must be a packager to apply to the' ' ACL: %s on %s' % (acl, collec), 'errors') continue pkgdblib.set_acl_package( SESSION, pkg_name=package.name, pkg_branch=collec, pkg_user=flask.g.fas_user.username, acl=acl, status=acl_status, user=flask.g.fas_user, ) SESSION.commit() flask.flash('ACLs updated') return flask.redirect( flask.url_for('.package_info', package=package.name)) except pkgdblib.PkgdbException, err: SESSION.rollback() flask.flash(str(err), 'error')
def admin_namespaces(): """ Shows all the existing namespaces. """ namespaces = pkgdblib.get_status(SESSION, 'namespaces')['namespaces'] form = pkgdb2.forms.NamespaceForm() return flask.render_template( 'admin_namespaces.html', namespaces=namespaces, form=form, )
def collection_edit(collection): ''' Allows to edit the information about the specified collection. ''' try: collection = pkgdblib.search_collection(SESSION, collection)[0] except IndexError: flask.flash('No collection of this name found.', 'errors') return flask.render_template('msg.html') clt_status = pkgdblib.get_status(SESSION, 'clt_status')['clt_status'] form = pkgdb2.forms.AddCollectionForm(clt_status=clt_status) if form.validate_on_submit(): clt_name = form.clt_name.data clt_version = form.version.data clt_status = form.clt_status.data clt_branchname = form.branchname.data clt_disttag = form.dist_tag.data clt_koji_name = form.kojiname.data clt_allow_retire = form.allow_retire.data try: pkgdblib.edit_collection( SESSION, collection=collection, clt_name=clt_name, clt_version=clt_version, clt_status=clt_status, clt_branchname=clt_branchname, clt_disttag=clt_disttag, clt_koji_name=clt_koji_name, clt_allow_retire=clt_allow_retire, user=flask.g.fas_user, ) SESSION.commit() flask.flash('Collection "%s" edited' % clt_branchname) return flask.redirect( flask.url_for('.collection_info', collection=collection.branchname)) # In theory we should never hit this except PkgdbException as err: # pragma: no cover SESSION.rollback() flask.flash(str(err), 'errors') elif flask.request.method == 'GET': form = pkgdb2.forms.AddCollectionForm(clt_status=clt_status, collection=collection) return flask.render_template( 'collection_edit.html', form=form, collection=collection, )
def admin_action_edit_status(action_id): """ Edit Admin Action status update """ admin_action = pkgdblib.get_admin_action(SESSION, action_id) if not admin_action: flask.flash('No action found with this identifier.', 'errors') return flask.render_template('msg.html') action_status = pkgdblib.get_status( SESSION, 'admin_status')['admin_status'] form = pkgdb2.forms.EditActionStatusForm( status=action_status, obj=admin_action ) form.id.data = action_id if form.validate_on_submit(): try: message = pkgdblib.edit_action_status( SESSION, admin_action, action_status=form.status.data, user=flask.g.fas_user, message=form.message.data, ) SESSION.commit() flask.flash(message) except PkgdbException as err: # pragma: no cover # We can only reach here in two cases: # 1) the user is not an admin, but that's taken care of # by the decorator # 2) we have a SQLAlchemy problem when storing the info # in the DB which we cannot test SESSION.rollback() flask.flash(err, 'errors') return flask.render_template('msg.html') return flask.redirect( flask.url_for('.admin_actions') ) return flask.render_template( 'actions_update.html', admin_action=admin_action, action_id=action_id, form=form, )
def request_acl(package): ''' Request acls for a specific package. ''' collections = pkgdblib.search_collection( SESSION, '*', 'Under Development') collections.extend(pkgdblib.search_collection(SESSION, '*', 'Active')) pkg_acl = pkgdblib.get_status(SESSION, 'pkg_acl')['pkg_acl'] form = pkgdb2.forms.RequestAclPackageForm( collections=collections, pkg_acl_list=pkg_acl ) if form.validate_on_submit(): pkg_branchs = form.pkg_branch.data pkg_acls = form.pkg_acl.data try: for (collec, acl) in itertools.product(pkg_branchs, pkg_acls): acl_status = 'Awaiting Review' if acl in APP.config['AUTO_APPROVE']: acl_status = 'Approved' elif 'packager' not in flask.g.fas_user.groups: flask.flash( 'You must be a packager to apply to the' ' ACL: %s on %s' % (acl, collec), 'errors') continue pkgdblib.set_acl_package( SESSION, pkg_name=package, pkg_branch=collec, pkg_user=flask.g.fas_user.username, acl=acl, status=acl_status, user=flask.g.fas_user, ) SESSION.commit() flask.flash('ACLs updated') return flask.redirect( flask.url_for('.package_info', package=package)) except pkgdblib.PkgdbException, err: SESSION.rollback() flask.flash(str(err), 'error')
def inject_is_admin(): """ Inject whether the user is a pkgdb2 admin or not in every page (every template). """ justlogedin = flask.session.get('_justloggedin', False) if justlogedin: # pragma: no cover flask.g.pending_acls = pkgdblib.get_pending_acl_user( SESSION, flask.g.fas_user.username) flask.session['_justloggedin'] = None justlogedout = flask.session.get('_justloggedout', False) if justlogedout: flask.session['_justloggedout'] = None namespaces = pkgdblib.get_status(SESSION, 'namespaces')['namespaces'] return dict( is_admin=is_pkgdb_admin(flask.g.fas_user), version=__version__, namespaces=namespaces, )
def inject_is_admin(): """ Inject whether the user is a pkgdb2 admin or not in every page (every template). """ justlogedin = flask.session.get('_justloggedin', False) if justlogedin: # pragma: no cover flask.g.pending_acls = pkgdblib.get_pending_acl_user( SESSION, flask.g.fas_user.username) flask.session['_justloggedin'] = None justlogedout = flask.session.get('_justloggedout', False) if justlogedout: flask.session['_justloggedout'] = None namespaces = pkgdblib.get_status(SESSION, 'namespaces')['namespaces'] return dict( is_admin=is_pkgdb_admin(flask.g.fas_user), version=__version__, namespaces=namespaces, )
def request_acl(package): ''' Request acls for a specific package. ''' collections = pkgdblib.search_collection(SESSION, '*', 'Under Development') collections.extend(pkgdblib.search_collection(SESSION, '*', 'Active')) pkg_acl = pkgdblib.get_status(SESSION, 'pkg_acl')['pkg_acl'] form = pkgdb2.forms.RequestAclPackageForm(collections=collections, pkg_acl_list=pkg_acl) if form.validate_on_submit(): pkg_branchs = form.pkg_branch.data pkg_acls = form.pkg_acl.data try: for (collec, acl) in itertools.product(pkg_branchs, pkg_acls): acl_status = 'Awaiting Review' if acl in APP.config['AUTO_APPROVE']: acl_status = 'Approved' elif 'packager' not in flask.g.fas_user.groups: flask.flash( 'You must be a packager to apply to the' ' ACL: %s on %s' % (acl, collec), 'errors') continue pkgdblib.set_acl_package( SESSION, pkg_name=package, pkg_branch=collec, pkg_user=flask.g.fas_user.username, acl=acl, status=acl_status, user=flask.g.fas_user, ) SESSION.commit() flask.flash('ACLs updated') return flask.redirect( flask.url_for('.package_info', package=package)) except pkgdblib.PkgdbException, err: SESSION.rollback() flask.flash(str(err), 'error')
def api_collection_new(): ''' New collection -------------- Create a new collection. :: /api/collection/new/ Accept POST queries only. :arg collection_name: String of the collection name to be created. :arg collection_version: String of the version of the collection. :arg collection_status: String of the name of the user owner of the collection. :arg collection_publishURLTemplate: :arg collection_pendingURLTemplate: :arg collection_summary: A summary description of the collection. :arg collection_description: A description of the collection. :arg collection_branchname: The short name of the collection (ie: F-18). :arg collection_distTag: The dist tag used by rpm for this collection (ie: .fc18). :arg collection_git_branch_name: The git branch name for this collection (ie: f18). :arg collection_kojiname: the name of the collection in koji. Sample response: :: { "output": "ok", "messages": ["Collection F-20 created"] } { "output": "notok", "error": ["You are not allowed to create collections"] } ''' httpcode = 200 output = {} clt_status = pkgdblib.get_status(SESSION, 'clt_status')['clt_status'] form = forms.AddCollectionForm( csrf_enabled=False, clt_status=clt_status, ) if form.validate_on_submit(): clt_name = form.collection_name.data clt_version = form.collection_version.data clt_status = form.collection_status.data clt_branchname = form.collection_branchname.data clt_disttag = form.collection_distTag.data clt_gitbranch = form.collection_git_branch_name.data clt_koji_name = form.collection_kojiname.data try: message = pkgdblib.add_collection( SESSION, clt_name=clt_name, clt_version=clt_version, clt_status=clt_status, clt_branchname=clt_branchname, clt_disttag=clt_disttag, clt_gitbranch=clt_gitbranch, clt_koji_name=clt_koji_name, user=flask.g.fas_user, ) SESSION.commit() output['output'] = 'ok' output['messages'] = [message] # Apparently we're pretty tight on checks and looks like we cannot # raise this exception in a normal situation except pkgdblib.PkgdbException, err: # pragma: no cover SESSION.rollback() output['output'] = 'notok' output['error'] = str(err) httpcode = 500
def api_admin_action_edit_status(): ''' Edit Admin Action status update ------------------------------- Edit the status of an Admin Action. :: /admin/action/status Accept POST queries only. :arg id: An integer representing the identifier of the admin action to update in the database. The identifier is returned in the API, see ``List admin actions``. :arg status: The status to which the action should be updated. Can be any of: ``Approved``, ``Awaiting Review``, ``Blocked``, ``Denied``, ``Pending`` and ``Obsolete``. ..note:: The ``Obsolete`` status can only be set by the person who made the request. Sample response: :: { "output": "ok", "messages": ["Admin action status updated to: Approved"] } { "output": "notok", "error": ["You are not an admin"] } ''' httpcode = 200 output = {} action_status = pkgdblib.get_status(SESSION, 'admin_status')['admin_status'] form = pkgdb2.forms.EditActionStatusForm( csrf_enabled=False, status=action_status, ) if form.validate_on_submit(): action_id = form.id.data admin_action = pkgdblib.get_admin_action(SESSION, action_id) if not admin_action: output['output'] = 'notok' output['error'] = 'No Admin action with this identifier found' httpcode = 500 else: try: message = pkgdblib.edit_action_status( SESSION, admin_action, action_status=form.status.data, user=flask.g.fas_user, message=form.message.data, ) SESSION.commit() output['output'] = 'ok' output['messages'] = [message] except pkgdblib.PkgdbException, err: # pragma: no cover # We can only reach here in two cases: # 1) the user is not an admin, but that's taken care of # by the decorator # 2) we have a SQLAlchemy problem when storing the info # in the DB which we cannot test SESSION.rollback() output['output'] = 'notok' output['error'] = str(err) httpcode = 500
def api_package_edit(): ''' Edit a package -------------- Edit a package. :: /api/package/edit/ Accept POST queries only. :arg pkgname: String of the package name to be created. :arg summary: String of the summary description of the package. :arg description: String describing the package (same as in the spec file). :arg review_url: the URL of the package review on the bugzilla. :arg status: status of the package can be one of: 'Approved', 'Awaiting Review', 'Denied', 'Obsolete', 'Removed' :arg upstream_url: the URL of the upstream project Sample response: :: { "output": "ok", "messages": ["Package edited"] } { "output": "notok", "error": ["You're not allowed to edit this package"] } ''' httpcode = 200 output = {} pkg_status = pkgdblib.get_status(SESSION, 'pkg_status')['pkg_status'] form = forms.EditPackageForm( csrf_enabled=False, pkg_status_list=pkg_status, ) if form.validate_on_submit(): pkg_name = form.pkgname.data package = None try: package = pkgdblib.search_package(SESSION, pkg_name, limit=1)[0] except (NoResultFound, IndexError): SESSION.rollback() output['output'] = 'notok' output['error'] = 'No package of this name found' httpcode = 500 if package: pkg_summary = form.summary.data pkg_description = form.description.data pkg_review_url = form.review_url.data pkg_status = form.status.data if pkg_status == 'None': pkg_status = None pkg_upstream_url = form.upstream_url.data try: message = pkgdblib.edit_package( SESSION, package, pkg_name=pkg_name, pkg_summary=pkg_summary, pkg_description=pkg_description, pkg_review_url=pkg_review_url, pkg_upstream_url=pkg_upstream_url, pkg_status=pkg_status, user=flask.g.fas_user ) SESSION.commit() output['output'] = 'ok' output['messages'] = [message] except pkgdblib.PkgdbException, err: # pragma: no cover # We can only reach here in two cases: # 1) the user is not an admin, but that's taken care of # by the decorator # 2) we have a SQLAlchemy problem when storing the info # in the DB which we cannot test SESSION.rollback() output['output'] = 'notok' output['error'] = str(err) httpcode = 500
def api_package_edit(): ''' Edit a package -------------- Edit a package. :: /api/package/edit/ Accepts POST queries only. :arg pkgname: String of the package name to be created. :arg summary: String of the summary description of the package. :arg description: String describing the package (same as in the spec file). :arg review_url: the URL of the package review on the bugzilla. :arg status: status of the package can be one of: 'Approved', 'Awaiting Review', 'Denied', 'Obsolete', 'Removed' :arg upstream_url: the URL of the upstream project Sample response: :: { "output": "ok", "messages": ["Package edited"] } { "output": "notok", "error": ["You're not allowed to edit this package"] } ''' httpcode = 200 output = {} pkg_status = pkgdblib.get_status(SESSION, 'pkg_status')['pkg_status'] form = forms.EditPackageForm( csrf_enabled=False, pkg_status_list=pkg_status, ) if form.validate_on_submit(): pkg_name = form.pkgname.data package = None try: package = pkgdblib.search_package(SESSION, pkg_name, limit=1)[0] except (NoResultFound, IndexError): SESSION.rollback() output['output'] = 'notok' output['error'] = 'No package of this name found' httpcode = 500 if package: pkg_summary = form.summary.data pkg_description = form.description.data pkg_review_url = form.review_url.data pkg_status = form.status.data if pkg_status == 'None': pkg_status = None pkg_upstream_url = form.upstream_url.data try: message = pkgdblib.edit_package( SESSION, package, pkg_name=pkg_name, pkg_summary=pkg_summary, pkg_description=pkg_description, pkg_review_url=pkg_review_url, pkg_upstream_url=pkg_upstream_url, pkg_status=pkg_status, user=flask.g.fas_user) SESSION.commit() output['output'] = 'ok' output['messages'] = [message] except pkgdblib.PkgdbException, err: # pragma: no cover # We can only reach here in two cases: # 1) the user is not an admin, but that's taken care of # by the decorator # 2) we have a SQLAlchemy problem when storing the info # in the DB which we cannot test SESSION.rollback() output['output'] = 'notok' output['error'] = str(err) httpcode = 500
def api_acl_update(): ''' Update package ACL ------------------ Update the ACL for a given package. :: /api/package/acl/ Accept POST queries only. :arg pkg_name: String of the package name. :arg pkg_branch: List of strings with the name of the branches to change, update. :arg pkg_acl: List of strings of the ACL to change/update. Possible acl are: 'commit', 'build', 'watchbugzilla', 'watchcommits', 'approveacls', 'checkout'. :arg acl_status: String of the type of action required. Possible status are: 'Approved', 'Awaiting Review', 'Denied', 'Obsolete', 'Removed'. :kwarg pkg_user: the name of the user that is the target of this ACL change/update. This will only work if: 1) you are an admin, 2) you are changing one of your package. Sample response: :: { "output": "ok", "messages": ["user: $USER set acl: $ACL of package: $PACKAGE " "from: $PREVIOUS_STATUS to $NEW_STATUS on branch: " "$BRANCH"] } { "output": "notok", "error": ["You are not allowed to update ACLs of someone else."] } ''' httpcode = 200 output = {} status = pkgdblib.get_status(SESSION, ['pkg_acl', 'acl_status']) form = forms.SetAclPackageForm( csrf_enabled=False, pkg_acl=status['pkg_acl'], acl_status=status['acl_status'], ) if form.validate_on_submit(): pkg_name = form.pkg_name.data pkg_branch = form.pkg_branch.data.split(',') pkg_acl = form.pkg_acl.data.split(',') acl_status = form.acl_status.data pkg_user = form.pkg_user.data try: messages = [] for (acl, branch) in itertools.product(pkg_acl, pkg_branch): message = pkgdblib.set_acl_package( SESSION, pkg_name=pkg_name, pkg_branch=branch, acl=acl, status=acl_status, pkg_user=pkg_user, user=flask.g.fas_user, ) messages.append(message) SESSION.commit() output['output'] = 'ok' output['messages'] = messages except pkgdblib.PkgdbException, err: SESSION.rollback() output['output'] = 'notok' output['error'] = str(err) httpcode = 500
def package_info(package): ''' Display the information about the specified package. ''' packagename = package package = None try: package_acl = pkgdblib.get_acl_package(SESSION, packagename) package = pkgdblib.search_package(SESSION, packagename, limit=1)[0] except (NoResultFound, IndexError): SESSION.rollback() flask.flash('No package of this name found.', 'errors') return flask.render_template('msg.html') planned_acls = set(pkgdblib.get_status(SESSION, 'pkg_acl')['pkg_acl']) branches = set() commit_acls = {} watch_acls = {} admins = {} pending_admins = {} pocs = {} committers = [] for pkg in package_acl: if pkg.collection.status == 'EOL': # pragma: no cover continue collection_name = '%s %s' % (pkg.collection.name, pkg.collection.version) branches.add(collection_name) if pkg.point_of_contact not in pocs: pocs[pkg.point_of_contact] = set() pocs[pkg.point_of_contact].add(collection_name) for acl in pkg.acls: if acl.acl == 'approveacls' and acl.status == 'Approved': if acl.fas_name not in admins: admins[acl.fas_name] = set() admins[acl.fas_name].add(collection_name) elif acl.acl == 'approveacls' and acl.status == 'Awaiting Review': if acl.fas_name not in pending_admins: pending_admins[acl.fas_name] = set() pending_admins[acl.fas_name].add(collection_name) if acl.acl == 'commit': dic = commit_acls if acl.status == 'Approved': committers.append(acl.fas_name) elif acl.acl.startswith('watch') and acl.status == 'Approved': dic = watch_acls else: # pragma: no cover -- pass isn't `covered` by coverage # We managed approveacls earlier continue if acl.fas_name not in dic: dic[acl.fas_name] = {} if collection_name not in dic[acl.fas_name]: dic[acl.fas_name][collection_name] = {} dic[acl.fas_name][collection_name][acl.acl] = \ acl.status for aclname in planned_acls: for user in commit_acls: if collection_name in commit_acls[user] and \ aclname not in commit_acls[user][collection_name]: commit_acls[user][collection_name][aclname] = None for aclname in planned_acls: for user in watch_acls: if collection_name in watch_acls[user] and \ aclname not in watch_acls[user][collection_name]: watch_acls[user][collection_name][aclname] = None statuses = set([ listing.status for listing in package.sorted_listings if listing.collection.status != 'EOL' ]) collections = pkgdb2.lib.search_collection(SESSION, '*', 'Under Development') collections.extend(pkgdb2.lib.search_collection(SESSION, '*', 'Active')) branches_possible = [ collec.branchname for collec in collections if '%s %s' % (collec.name, collec.version) not in branches ] requester = False if is_authenticated(): for req in package.requests: if req.user == flask.g.fas_user.username: requester = True break return flask.render_template( 'package.html', package=package, commit_acls=commit_acls, watch_acls=watch_acls, pocs=pocs, admins=admins, statuses=statuses, pending_admins=pending_admins, branches=branches, branches_possible=branches_possible, committers=committers, form=pkgdb2.forms.ConfirmationForm(), requester=requester, )
def api_collection_new(): ''' New collection -------------- Create a new collection. :: /api/collection/new/ Accepts POST queries only. :arg clt_name: String of the collection name to be created. :arg version: String of the version of the collection. :arg clt_status: String of the name of the user owner of the collection. :arg summary: A summary description of the collection. :arg description: A description of the collection. :arg branchname: The short name of the collection (ie: F-18). :arg dist_tag: The dist tag used by rpm for this collection (ie: .fc18). :arg kojiname: the name of the collection in koji. :kwarg allow_retire: a boolean specifying if the collection should allow retiring a package or not. Defaults to ``False``. Sample response: :: { "output": "ok", "messages": ["Collection F-20 created"] } { "output": "notok", "error": ["You are not allowed to create collections"] } ''' httpcode = 200 output = {} clt_status = pkgdblib.get_status(SESSION, 'clt_status')['clt_status'] form = forms.AddCollectionForm( csrf_enabled=False, clt_status=clt_status, ) if form.validate_on_submit(): clt_name = form.clt_name.data clt_version = form.version.data clt_status = form.clt_status.data clt_branchname = form.branchname.data clt_disttag = form.dist_tag.data clt_koji_name = form.kojiname.data clt_allow_retire = form.allow_retire.data or False try: message = pkgdblib.add_collection( SESSION, clt_name=clt_name, clt_version=clt_version, clt_status=clt_status, clt_branchname=clt_branchname, clt_disttag=clt_disttag, clt_koji_name=clt_koji_name, clt_allow_retire=clt_allow_retire, user=flask.g.fas_user, ) SESSION.commit() output['output'] = 'ok' output['messages'] = [message] # Apparently we're pretty tight on checks and looks like we cannot # raise this exception in a normal situation except PkgdbException as err: # pragma: no cover SESSION.rollback() output['output'] = 'notok' output['error'] = str(err) httpcode = 500 else: output['output'] = 'notok' output['error'] = 'Invalid input submitted' if form.errors: detail = [] for error in form.errors: detail.append('%s: %s' % (error, '; '.join(form.errors[error]))) output['error_detail'] = detail httpcode = 500 jsonout = flask.jsonify(output) jsonout.status_code = httpcode return jsonout
def api_package_request(): ''' New package request ------------------- Request for an admin to include a new package in pkgdb. :: /api/request/package Accepts POST queries only. :arg pkgname: The name of the package to create. :arg summary: The summary of the package. :arg description: The description of the package. :arg upstream_url: The URL of the upstream website of the package. :arg review_url: The URL where the package review was done. :arg branches: The list of branches desired for this package. Note: if the ``master`` isn't requested, it will be added automatically. :kwarg namespace: The namespace of the package to create (defaults to ``rpms``). Sample response: :: { "output": "ok", "messages": [ 'user: pingou request package: guake on branch master', 'user: pingou request package: guake on branch f18', ] } { "output": "notok", 'error': 'User "pingou" is not in the packager group', } { "error": "Invalid input submitted", "error_detail": [ "branches: 'foobar' is not a valid choice for this field", "review_url: This field is required." ], "output": "notok" } ''' httpcode = 200 output = {} collections = pkgdblib.search_collection( SESSION, '*', 'Under Development') collections.reverse() active_collections = pkgdblib.search_collection(SESSION, '*', 'Active') active_collections.reverse() # We want all the branch `Under Development` as well as all the `Active` # branch but we can only have at max 2 Fedora branch active at the same # time. In other words, when Fedora n+1 is released one can no longer # request a package to be added to Fedora n-1 cnt = 0 for collection in active_collections: if collection.name.lower() == 'fedora': if cnt >= 2: continue cnt += 1 collections.append(collection) namespaces = pkgdblib.get_status(SESSION, 'namespaces')['namespaces'] form = forms.RequestPackageForm( csrf_enabled=False, collections=collections, namespaces=namespaces, ) if str(form.namespace.data) in ['None', '']: form.namespace.data = 'rpms' if form.validate_on_submit(): pkg_name = form.pkgname.data pkg_summary = form.summary.data pkg_description = form.description.data pkg_review_url = form.review_url.data pkg_status = 'Approved' pkg_critpath = False pkg_collection = form.branches.data if not 'master' in pkg_collection: pkg_collection.append('master') pkg_poc = flask.g.fas_user.username pkg_upstream_url = form.upstream_url.data pkg_namespace = form.namespace.data bz = APP.config.get('PKGDB2_BUGZILLA_URL') if bz not in pkg_review_url: try: int(pkg_review_url) pkg_review_url = bz + '/' + pkg_review_url except (TypeError, ValueError): pass try: messages = [] for clt in pkg_collection: message = pkgdblib.add_new_package_request( SESSION, pkg_name=pkg_name, pkg_summary=pkg_summary, pkg_description=pkg_description, pkg_review_url=pkg_review_url, pkg_status=pkg_status, pkg_critpath=pkg_critpath, pkg_collection=clt, pkg_poc=pkg_poc, pkg_upstream_url=pkg_upstream_url, pkg_namespace=pkg_namespace, user=flask.g.fas_user, ) if message: messages.append(message) SESSION.commit() output['output'] = 'ok' output['messages'] = messages except pkgdblib.PkgdbException, err: SESSION.rollback() output['output'] = 'notok' output['error'] = str(err) httpcode = 400
def api_acl_update(): """ Update package ACL ------------------ Update the ACL for a given package. :: /api/package/acl/ Accept POST queries only. :arg pkgname: String of the package name. :arg branches: List of strings with the name of the branches to change, update. :arg acl: List of strings of the ACL to change/update. Possible acl are: 'commit', 'build', 'watchbugzilla', 'watchcommits', 'approveacls', 'checkout'. :arg acl_status: String of the type of action required. Possible status are: 'Approved', 'Awaiting Review', 'Denied', 'Obsolete', 'Removed'. :kwarg user: the name of the user that is the target of this ACL change/update. This will only work if: 1) you are an admin, 2) you are changing one of your package. Sample response: :: { "output": "ok", "messages": ["user: $USER set acl: $ACL of package: $PACKAGE " "from: $PREVIOUS_STATUS to $NEW_STATUS on branch: " "$BRANCH"] } { "output": "notok", "error": ["You are not allowed to update ACLs of someone else."] } """ httpcode = 200 output = {} status = pkgdblib.get_status(SESSION, ["pkg_acl", "acl_status"]) collections = pkgdblib.search_collection(SESSION, "*", "Under Development") collections.extend(pkgdblib.search_collection(SESSION, "*", "Active")) form = forms.SetAclPackageForm( csrf_enabled=False, collections=[col.branchname for col in collections], pkg_acl=status["pkg_acl"], acl_status=status["acl_status"], ) if form.validate_on_submit(): pkg_name = form.pkgname.data pkg_branch = form.branches.data pkg_acl = form.acl.data acl_status = form.acl_status.data pkg_user = form.user.data try: messages = [] for (branch, acl) in itertools.product(pkg_branch, pkg_acl): acl_status2 = acl_status if acl_status2 == "Awaiting Review" and acl in APP.config["AUTO_APPROVE"]: acl_status2 = "Approved" message = pkgdblib.set_acl_package( SESSION, pkg_name=pkg_name, pkg_branch=branch, acl=acl, status=acl_status2, pkg_user=pkg_user, user=flask.g.fas_user, ) if message: messages.append(message) else: messages.append("Nothing to update on branch: %s for acl: %s" % (branch, acl)) SESSION.commit() output["output"] = "ok" output["messages"] = messages except pkgdblib.PkgdbException, err: SESSION.rollback() output["output"] = "notok" output["error"] = str(err) httpcode = 500
def api_collection_new(): ''' New collection -------------- Create a new collection. :: /api/collection/new/ Accepts POST queries only. :arg clt_name: String of the collection name to be created. :arg version: String of the version of the collection. :arg clt_status: String of the name of the user owner of the collection. :arg summary: A summary description of the collection. :arg description: A description of the collection. :arg branchname: The short name of the collection (ie: F-18). :arg dist_tag: The dist tag used by rpm for this collection (ie: .fc18). :arg kojiname: the name of the collection in koji. :kwarg allow_retire: a boolean specifying if the collection should allow retiring a package or not. Defaults to ``False``. Sample response: :: { "output": "ok", "messages": ["Collection F-20 created"] } { "output": "notok", "error": ["You are not allowed to create collections"] } ''' httpcode = 200 output = {} clt_status = pkgdblib.get_status(SESSION, 'clt_status')['clt_status'] form = forms.AddCollectionForm( csrf_enabled=False, clt_status=clt_status, ) if form.validate_on_submit(): clt_name = form.clt_name.data clt_version = form.version.data clt_status = form.clt_status.data clt_branchname = form.branchname.data clt_disttag = form.dist_tag.data clt_koji_name = form.kojiname.data clt_allow_retire = form.allow_retire.data or False try: message = pkgdblib.add_collection( SESSION, clt_name=clt_name, clt_version=clt_version, clt_status=clt_status, clt_branchname=clt_branchname, clt_disttag=clt_disttag, clt_koji_name=clt_koji_name, clt_allow_retire=clt_allow_retire, user=flask.g.fas_user, ) SESSION.commit() output['output'] = 'ok' output['messages'] = [message] # Apparently we're pretty tight on checks and looks like we cannot # raise this exception in a normal situation except PkgdbException as err: # pragma: no cover SESSION.rollback() output['output'] = 'notok' output['error'] = str(err) httpcode = 500 else: output['output'] = 'notok' output['error'] = 'Invalid input submitted' if form.errors: detail = [] for error in form.errors: detail.append('%s: %s' % (error, '; '.join(form.errors[error]))) output['error_detail'] = detail httpcode = 500 jsonout = flask.jsonify(output) jsonout.status_code = httpcode return jsonout
packager=packager or None, action=action, status=status, page=page, limit=limit, order="desc", ) cnt_actions = pkgdblib.search_actions( SESSION, package=package or None, packager=packager or None, action=action, status=status, count=True ) except pkgdblib.PkgdbException, err: flask.flash(err, "errors") total_page = int(ceil(cnt_actions / float(limit))) action_status = pkgdblib.get_status(SESSION, "admin_status")["admin_status"] action_status.insert(0, "All") return flask.render_template( "list_actions.html", actions=actions, cnt_actions=cnt_actions, total_page=total_page, page=page, package=package or "", packager=packager or "", action=action, status=status, statuses=action_status, )
def admin_actions(): """ Return the actions requested and requiring intervention from an admin. """ package = flask.request.args.get('package', None) packager = flask.request.args.get('packager', None) action = flask.request.args.get('action', None) status = flask.request.args.get('status', 'Awaiting Review') limit = flask.request.args.get('limit', APP.config['ITEMS_PER_PAGE']) page = flask.request.args.get('page', 1) try: page = abs(int(page)) except ValueError: page = 1 try: limit = abs(int(limit)) except ValueError: limit = APP.config['ITEMS_PER_PAGE'] flask.flash('Incorrect limit provided, using default', 'errors') actions = [] cnt_actions = 0 try: actions = pkgdblib.search_actions( SESSION, package=package or None, packager=packager or None, action=action, status=status, page=page, limit=limit, order='desc', ) cnt_actions = pkgdblib.search_actions( SESSION, package=package or None, packager=packager or None, action=action, status=status, count=True ) except PkgdbException as err: flask.flash(err, 'errors') total_page = int(ceil(cnt_actions / float(limit))) action_status = pkgdblib.get_status( SESSION, 'admin_status')['admin_status'] action_status.insert(0, 'All') return flask.render_template( 'list_actions.html', actions=actions, cnt_actions=cnt_actions, total_page=total_page, page=page, package=package or '', packager=packager or '', action=action, status=status, statuses=action_status, )
def package_request_new(): ''' Page to request a new package. ''' collections = pkgdb2.lib.search_collection(SESSION, '*', 'Under Development') collections.reverse() active_collections = pkgdb2.lib.search_collection(SESSION, '*', 'Active') active_collections.reverse() # We want all the branch `Under Development` as well as all the `Active` # branch but we can only have at max 2 Fedora branch active at the same # time. In other words, when Fedora n+1 is released one can no longer # request a package to be added to Fedora n-1 cnt = 0 for collection in active_collections: if collection.name.lower() == 'fedora': if cnt >= 2: continue cnt += 1 collections.append(collection) namespaces = pkgdblib.get_status(SESSION, 'namespaces')['namespaces'] form = pkgdb2.forms.RequestPackageForm( collections=collections, namespaces=namespaces, ) if form.validate_on_submit(): pkg_name = form.pkgname.data pkg_summary = form.summary.data pkg_description = form.description.data pkg_review_url = form.review_url.data pkg_status = 'Approved' pkg_critpath = False pkg_collection = form.branches.data pkg_namespace = form.namespace.data if not 'master' in pkg_collection: flask.flash('Adding a request for `master` branch, this branch is ' 'mandatory') pkg_collection.append('master') pkg_poc = flask.g.fas_user.username pkg_upstream_url = form.upstream_url.data monitoring_status = form.monitoring_status.data koschei = form.koschei.data comaintainers = form.comaintainers.data.strip() or None bz = APP.config.get('PKGDB2_BUGZILLA_URL') if bz not in pkg_review_url: try: int(pkg_review_url) pkg_review_url = bz + '/' + pkg_review_url except (TypeError, ValueError): pass try: messages = [] for clt in pkg_collection: message = pkgdblib.add_new_package_request( SESSION, pkg_namespace=pkg_namespace, pkg_name=pkg_name, pkg_summary=pkg_summary, pkg_description=pkg_description, pkg_review_url=pkg_review_url, pkg_status=pkg_status, pkg_critpath=pkg_critpath, pkg_collection=clt, pkg_poc=pkg_poc, pkg_upstream_url=pkg_upstream_url, monitoring_status=monitoring_status, koschei=koschei, comaintainers=comaintainers, user=flask.g.fas_user, ) if message: messages.append(message) SESSION.commit() for message in messages: flask.flash(message) return flask.redirect(flask.url_for('.index')) # Keep it in, but normally we shouldn't hit this except pkgdblib.PkgdbException, err: # pragma: no cover SESSION.rollback() flask.flash(str(err), 'error')
def package_info(namespace, package): ''' Display the information about the specified package. ''' packagename = package package = None try: package_acl = pkgdblib.get_acl_package( SESSION, namespace, packagename) package = pkgdblib.search_package( SESSION, namespace, packagename, limit=1)[0] except (NoResultFound, IndexError): SESSION.rollback() flask.flash('No package of this name found.', 'errors') return flask.render_template('msg.html') planned_acls = set( pkgdblib.get_status(SESSION, 'pkg_acl')['pkg_acl']) branches = set() commit_acls = {} watch_acls = {} admins = {} pending_admins = {} pocs = {} committers = [] for pkg in package_acl: if pkg.collection.status == 'EOL': # pragma: no cover continue collection_name = '%s %s' % ( pkg.collection.name, pkg.collection.version) branches.add(collection_name) if pkg.point_of_contact not in pocs: pocs[pkg.point_of_contact] = set() pocs[pkg.point_of_contact].add(collection_name) for acl in pkg.acls: if acl.acl == 'approveacls' and acl.status == 'Approved': if acl.fas_name not in admins: admins[acl.fas_name] = set() admins[acl.fas_name].add(collection_name) elif acl.acl == 'approveacls' and acl.status == 'Awaiting Review': if acl.fas_name not in pending_admins: pending_admins[acl.fas_name] = set() pending_admins[acl.fas_name].add(collection_name) if acl.acl == 'commit': dic = commit_acls if acl.status == 'Approved': committers.append(acl.fas_name) elif acl.acl.startswith('watch') and acl.status == 'Approved': dic = watch_acls else: # pragma: no cover -- pass isn't `covered` by coverage # We managed approveacls earlier continue if acl.fas_name not in dic: dic[acl.fas_name] = {} if collection_name not in dic[acl.fas_name]: dic[acl.fas_name][collection_name] = {} dic[acl.fas_name][collection_name][acl.acl] = \ acl.status for aclname in planned_acls: for user in commit_acls: if collection_name in commit_acls[user] and \ aclname not in commit_acls[user][collection_name]: commit_acls[user][collection_name][aclname] = None for aclname in planned_acls: for user in watch_acls: if collection_name in watch_acls[user] and \ aclname not in watch_acls[user][collection_name]: watch_acls[user][collection_name][aclname] = None statuses = set([ listing.status for listing in package.sorted_listings if listing.collection.status != 'EOL' ]) collections = pkgdb2.lib.search_collection( SESSION, '*', 'Under Development') collections.extend(pkgdb2.lib.search_collection(SESSION, '*', 'Active')) branches_possible = [ collec.branchname for collec in collections if '%s %s' % (collec.name, collec.version) not in branches] requester = False if is_authenticated(): for req in package.requests: if req.user == flask.g.fas_user.username: requester = True break return flask.render_template( 'package.html', package=package, commit_acls=commit_acls, watch_acls=watch_acls, pocs=pocs, admins=admins, statuses=statuses, pending_admins=pending_admins, branches=branches, branches_possible=branches_possible, committers=committers, form=pkgdb2.forms.ConfirmationForm(), requester=requester, )
def package_request_new(): ''' Page to request a new package. ''' collections = pkgdb2.lib.search_collection( SESSION, '*', 'Under Development') collections.reverse() active_collections = pkgdb2.lib.search_collection( SESSION, '*', 'Active') active_collections.reverse() # We want all the branch `Under Development` as well as all the `Active` # branch but we can only have at max 2 Fedora branch active at the same # time. In other words, when Fedora n+1 is released one can no longer # request a package to be added to Fedora n-1 cnt = 0 for collection in active_collections: if collection.name.lower() == 'fedora': if cnt >= 2: continue cnt += 1 collections.append(collection) namespaces = pkgdblib.get_status(SESSION, 'namespaces')['namespaces'] default_ns = APP.config.get('DEFAULT_NAMESPACE', 'rpms') # Ensure the `rpms` namespace is always the first in the list (the default) if default_ns in namespaces: namespaces.pop(namespaces.index(default_ns)) namespaces.insert(0, default_ns) form = pkgdb2.forms.RequestPackageForm( collections=collections, namespaces=namespaces, ) if form.validate_on_submit(): pkg_name = form.pkgname.data pkg_summary = form.summary.data pkg_description = form.description.data pkg_review_url = form.review_url.data pkg_status = 'Approved' pkg_critpath = False pkg_collection = form.branches.data pkg_namespace = form.namespace.data if not 'master' in pkg_collection: flask.flash( 'Adding a request for `master` branch, this branch is ' 'mandatory') pkg_collection.append('master') pkg_poc = flask.g.fas_user.username pkg_upstream_url = form.upstream_url.data monitoring_status = form.monitoring_status.data koschei = form.koschei.data comaintainers = form.comaintainers.data.strip() or None bz = APP.config.get('PKGDB2_BUGZILLA_URL') pkg_review_url = pkgdblib.check_bz_url(bz, pkg_review_url) try: messages = [] for clt in pkg_collection: message = pkgdblib.add_new_package_request( SESSION, pkg_namespace=pkg_namespace, pkg_name=pkg_name, pkg_summary=pkg_summary, pkg_description=pkg_description, pkg_review_url=pkg_review_url, pkg_status=pkg_status, pkg_critpath=pkg_critpath, pkg_collection=clt, pkg_poc=pkg_poc, pkg_upstream_url=pkg_upstream_url, monitoring_status=monitoring_status, koschei=koschei, comaintainers=comaintainers, user=flask.g.fas_user, ) if message: messages.append(message) SESSION.commit() for message in messages: flask.flash(message) return flask.redirect(flask.url_for('.index')) # Keep it in, but normally we shouldn't hit this except PkgdbException as err: # pragma: no cover SESSION.rollback() flask.flash(str(err), 'error') return flask.render_template( 'package_request.html', form=form, )
def api_collection_status(collection): ''' Update collection status ------------------------ Update the status of collection. :: /api/collection/<collection branchname>/status/ Accepts POST query only. :arg branch: String of the collection branch name to change. :arg clt_status: String of the status to change the collection to Sample response: :: { "output": "ok", "messages": ["Collection updated to \"EOL\""] } { "output": "notok", "error": ["You are not allowed to edit collections"] } ''' httpcode = 200 output = {} clt_status = pkgdblib.get_status(SESSION, 'clt_status')['clt_status'] form = forms.CollectionStatusForm( csrf_enabled=False, clt_status=clt_status, ) if form.validate_on_submit(): clt_branchname = form.branch.data clt_status = form.clt_status.data if collection == clt_branchname: try: message = pkgdblib.update_collection_status( SESSION, clt_branchname, clt_status, user=flask.g.fas_user ) SESSION.commit() output['output'] = 'ok' output['messages'] = [message] except PkgdbException as err: SESSION.rollback() output['output'] = 'notok' output['error'] = str(err) httpcode = 500 else: output['output'] = 'notok' output['error'] = "You're trying to update the " \ "wrong collection" httpcode = 500 else: output['output'] = 'notok' output['error'] = 'Invalid input submitted' if form.errors: detail = [] for error in form.errors: detail.append('%s: %s' % (error, '; '.join(form.errors[error]))) output['error_detail'] = detail httpcode = 500 jsonout = flask.jsonify(output) jsonout.status_code = httpcode return jsonout
def api_collection_new(): ''' New collection -------------- Create a new collection. :: /api/collection/new/ Accept POST queries only. :arg clt_name: String of the collection name to be created. :arg version: String of the version of the collection. :arg clt_status: String of the name of the user owner of the collection. :arg summary: A summary description of the collection. :arg description: A description of the collection. :arg branchname: The short name of the collection (ie: F-18). :arg dist_tag: The dist tag used by rpm for this collection (ie: .fc18). :arg kojiname: the name of the collection in koji. Sample response: :: { "output": "ok", "messages": ["Collection F-20 created"] } { "output": "notok", "error": ["You are not allowed to create collections"] } ''' httpcode = 200 output = {} clt_status = pkgdblib.get_status(SESSION, 'clt_status')['clt_status'] form = forms.AddCollectionForm( csrf_enabled=False, clt_status=clt_status, ) if form.validate_on_submit(): clt_name = form.clt_name.data clt_version = form.version.data clt_status = form.clt_status.data clt_branchname = form.branchname.data clt_disttag = form.dist_tag.data clt_koji_name = form.kojiname.data try: message = pkgdblib.add_collection( SESSION, clt_name=clt_name, clt_version=clt_version, clt_status=clt_status, clt_branchname=clt_branchname, clt_disttag=clt_disttag, clt_koji_name=clt_koji_name, user=flask.g.fas_user, ) SESSION.commit() output['output'] = 'ok' output['messages'] = [message] # Apparently we're pretty tight on checks and looks like we cannot # raise this exception in a normal situation except pkgdblib.PkgdbException, err: # pragma: no cover SESSION.rollback() output['output'] = 'notok' output['error'] = str(err) httpcode = 500
def api_acl_update(): ''' Update package ACL ------------------ Update the ACL for a given package. :: /api/package/acl/ Accepts POST queries only. :arg pkgname: String of the package name. :arg branches: List of strings with the name of the branches to change, update. :arg acl: List of strings of the ACL to change/update. Possible acl are: 'commit', 'build', 'watchbugzilla', 'watchcommits', 'approveacls', 'checkout'. :arg acl_status: String of the type of action required. Possible status are: 'Approved', 'Awaiting Review', 'Denied', 'Obsolete', 'Removed'. :kwarg user: the name of the user that is the target of this ACL change/update. This will only work if: 1) you are an admin, 2) you are changing one of your package. :kwarg namespace: The namespace of the packages (defaults to ``rpms``). Sample response: :: { "output": "ok", "messages": ["user: $USER set acl: $ACL of package: $PACKAGE " "from: $PREVIOUS_STATUS to $NEW_STATUS on branch: " "$BRANCH"] } { "output": "notok", "error": ["You are not allowed to update ACLs of someone else."] } ''' httpcode = 200 output = {} status = pkgdblib.get_status( SESSION, ['pkg_acl', 'acl_status', 'namespaces']) collections = pkgdblib.search_collection( SESSION, '*', 'Under Development') collections.extend(pkgdblib.search_collection(SESSION, '*', 'Active')) form = forms.SetAclPackageForm( csrf_enabled=False, collections=[col.branchname for col in collections], pkg_acl=status['pkg_acl'], acl_status=status['acl_status'], namespaces=status['namespaces'], ) if str(form.namespace.data) in ['None', '']: form.namespace.data = 'rpms' if form.validate_on_submit(): namespace = form.namespace.data pkg_name = form.pkgname.data pkg_branch = form.branches.data pkg_acl = form.acl.data acl_status = form.acl_status.data pkg_user = form.user.data try: messages = [] for (branch, acl) in itertools.product(pkg_branch, pkg_acl): acl_status2 = acl_status if acl_status2 == 'Awaiting Review' and \ acl in APP.config['AUTO_APPROVE']: acl_status2 = 'Approved' message = pkgdblib.set_acl_package( SESSION, namespace=namespace, pkg_name=pkg_name, pkg_branch=branch, acl=acl, status=acl_status2, pkg_user=pkg_user, user=flask.g.fas_user, ) if message: messages.append(message) else: messages.append( 'Nothing to update on branch: %s for acl: %s' % (branch, acl)) SESSION.commit() output['output'] = 'ok' output['messages'] = messages except PkgdbException as err: SESSION.rollback() output['output'] = 'notok' output['error'] = str(err) httpcode = 500 else: output['output'] = 'notok' output['error'] = 'Invalid input submitted' if form.errors: detail = [] for error in form.errors: detail.append('%s: %s' % (error, '; '.join(form.errors[error]))) output['error_detail'] = detail httpcode = 500 jsonout = flask.jsonify(output) jsonout.status_code = httpcode return jsonout
def api_packager_acl(packagername=None): ''' User's ACL ---------- List the ACLs of the user. :: /api/packager/acl/<fas_username>/ /api/packager/acl/?packagername=<username> Accepts GET queries only. :arg packagername: String of the packager name. :kwarg acls: One or more ACL to filter the ACLs retrieved. Options are: ``approveacls``, ``commit``, ``watchbugzilla``, ``watchcommits``. :kwarg eol: a boolean to specify whether to include results for EOL collections or not. Defaults to False. If ``True``, it will return results for all collections (including EOL). If ``False``, it will return results only for non-EOL collections. :kwarg poc: a boolean specifying whether the results should be restricted to ACL for which the provided packager is the point of contact or not. Defaults to None. If ``True`` it will only return ACLs for packages on which the provided packager is point of contact. If ``False`` it will only return ACLs for packages on which the provided packager is not the point of contact. If ``None`` it will not filter the ACLs returned based on the point of contact of the package (thus every packages is returned). :kwarg page: The page number to return (useful in combination to limit). :kwarg limit: An integer to limit the number of results, defaults to 250, maximum is 500 (acls). :kwarg count: A boolean to return the number of packages instead of the list. Defaults to False. *Results are paginated* Sample response: :: /api/packager/acl/pingou { "output": "ok", "page": 1, "page_total": 12 "acls": [ { "status": "Approved", "fas_name": "pingou", "packagelist": { "point_of_contact": "pingou", "critpath": False, "collection": { "status": "EOL", "branchname": "f16", "version": "16", "name": "Fedora" }, "package": { "status": "Approved", "upstream_url": null, "description": null, "summary": "Data of T- and B-cell Acute Lymphocytic " "Leukemia", "creation_date": 1384775354.0, "review_url": null, "name": "R-ALL" } }, "acl": "watchcommits" }, { "status": "Approved", "fas_name": "pingou", "packagelist": { "point_of_contact": "pingou", "critpath": False, "collection": { "status": "EOL", "branchname": "f16", "version": "16", "name": "Fedora" }, "package": { "status": "Approved", "upstream_url": null, "description": null, "summary": "Data of T- and B-cell Acute Lymphocytic " "Leukemia", "creation_date": 1384775354.0, "review_url": null, "name": "R-ALL" } }, "acl": "watchbugzilla" } ] } /api/packager/acl/?packagername=random { "output": "notok", "error": "No ACL found for this user", "page": 1 } ''' httpcode = 200 output = {} packagername = flask.request.args.get('packagername', None) or packagername acls = flask.request.args.getlist('acls', None) eol = flask.request.args.get('eol', False) poc = flask.request.args.get('poc', None) if poc is not None: if poc in ['False', '0', 0]: poc = False poc = bool(poc) pkg_acl = pkgdblib.get_status(SESSION, 'pkg_acl')['pkg_acl'] for acl in acls: if acl not in pkg_acl: output = { 'output': 'notok', 'error': 'Invalid request, "%s" is an invalid acl' % acl } httpcode = 500 jsonout = flask.jsonify(output) jsonout.status_code = httpcode return jsonout page = flask.request.args.get('page', 1) limit = get_limit() count = flask.request.args.get('count', False) if packagername: packagers = pkgdblib.get_acl_packager(SESSION, packager=packagername, acls=acls, eol=eol, poc=poc, page=page, limit=limit, count=count) if packagers: output['output'] = 'ok' if count: output['acls_count'] = packagers else: tmp = [] for pkg in packagers: dic = pkg[0].to_json(pkglist=False) dic['packagelist'] = pkg[1].to_json(acls=False) tmp.append(dic) output['acls'] = tmp total_acl = pkgdblib.get_acl_packager(SESSION, packager=packagername, acls=acls, eol=eol, poc=poc, count=True) if count: output['page_total'] = 1 else: output['page_total'] = int(ceil(total_acl / float(limit))) else: output = {'output': 'notok', 'error': 'No ACL found for this user'} httpcode = 404 else: output = {'output': 'notok', 'error': 'Invalid request'} httpcode = 500 output['page'] = page if 'page_total' not in output: output['page_total'] = 1 jsonout = flask.jsonify(output) jsonout.status_code = httpcode return jsonout
def update_acl(package, update_acl): ''' Update the acls of a package. ''' packagename = package package = None try: package_acl = pkgdblib.get_acl_package(SESSION, packagename) package = pkgdblib.search_package(SESSION, packagename, limit=1)[0] except (NoResultFound, IndexError): SESSION.rollback() flask.flash('No package of this name found.', 'errors') return flask.render_template('msg.html') statues = pkgdblib.get_status(SESSION) planned_acls = set(statues['pkg_acl']) acl_status = list(set(statues['acl_status'])) acl_status.insert(0, '') if update_acl not in planned_acls: flask.flash('Invalid ACL to update.', 'errors') return flask.redirect( flask.url_for('.package_info', package=package.name)) branches = {} branches_inv = {} commit_acls = {} admins = {} committers = [] for pkg in package_acl: if pkg.collection.status == 'EOL': # pragma: no cover continue collection_name = '%s %s' % (pkg.collection.name, pkg.collection.version) if collection_name not in branches: branches[collection_name] = pkg.collection.branchname if pkg.collection.branchname not in branches_inv: branches_inv[pkg.collection.branchname] = collection_name for acl in pkg.acls: if acl.acl == 'approveacls' and acl.status == 'Approved': if acl.fas_name not in admins: admins[acl.fas_name] = set() admins[acl.fas_name].add(collection_name) if acl.acl != update_acl: continue committers.append(acl.fas_name) if acl.fas_name not in commit_acls: commit_acls[acl.fas_name] = {} if collection_name not in commit_acls[acl.fas_name]: commit_acls[acl.fas_name][collection_name] = {} commit_acls[acl.fas_name][collection_name][acl.acl] = \ acl.status for aclname in planned_acls: for user in commit_acls: if collection_name in commit_acls[user] and \ aclname not in commit_acls[user][collection_name]: commit_acls[user][collection_name][aclname] = None # If the user is not an admin, he/she can only access his/her ACLs username = flask.g.fas_user.username if username not in admins and not is_pkgdb_admin(flask.g.fas_user): tmp = {username: []} if username in commit_acls: tmp = {username: commit_acls[username]} commit_acls = tmp form = pkgdb2.forms.ConfirmationForm() if form.validate_on_submit(): sub_acls = flask.request.values.getlist('acls') sub_users = flask.request.values.getlist('user') sub_branches = flask.request.values.getlist('branch') changed = False if sub_acls and len(sub_acls) == (len(sub_users) * len(sub_branches)): cnt = 0 for cnt_u in range(len(sub_users)): for cnt_b in range(len(sub_branches)): lcl_acl = sub_acls[cnt] lcl_user = sub_users[cnt_u] lcl_branch = sub_branches[cnt_b] if lcl_acl not in acl_status: flask.flash('Invalid ACL: %s' % lcl_acl, 'error') cnt += 1 continue if lcl_user not in commit_acls: flask.flash('Invalid user: %s' % lcl_user, 'error') cnt += 1 continue if lcl_branch not in branches_inv or ( branches_inv[lcl_branch] in commit_acls[lcl_user] and commit_acls[lcl_user][branches_inv[lcl_branch]] [update_acl] == lcl_acl): cnt += 1 continue if not lcl_acl: if branches_inv[lcl_branch] \ not in commit_acls[lcl_user]: cnt += 1 continue elif branches_inv[lcl_branch] \ in commit_acls[lcl_user] \ and username != lcl_user: flask.flash('Only the user can remove his/her ACL', 'error') cnt += 1 continue try: pkgdblib.set_acl_package( SESSION, pkg_name=package.name, pkg_branch=lcl_branch, pkg_user=lcl_user, acl=update_acl, status=lcl_acl, user=flask.g.fas_user, ) SESSION.commit() flask.flash("%s's %s ACL updated on %s" % (lcl_user, update_acl, lcl_branch)) changed = True except pkgdblib.PkgdbException, err: SESSION.rollback() flask.flash(str(err), 'error') cnt += 1 SESSION.commit() if not changed: flask.flash('Nothing to update') return flask.redirect( flask.url_for('.package_info', package=package.name)) else: flask.flash('Invalid input submitted', 'error')
def packager_requests(packager): ''' Display the requests made by the specified packager. ''' action = flask.request.args.get('action') or None package = flask.request.args.get('package') or None status = flask.request.args.get('status', 'All') limit = flask.request.args.get('limit', APP.config['ITEMS_PER_PAGE']) page = flask.request.args.get('page', 1) try: page = abs(int(page)) except ValueError: page = 1 try: limit = abs(int(limit)) except ValueError: limit = APP.config['ITEMS_PER_PAGE'] flask.flash('Incorrect limit provided, using default', 'errors') actions = [] cnt_actions = 0 try: actions = pkgdblib.search_actions( SESSION, packager=packager, package=package, action=action, status=status, page=page, limit=limit, order='desc', ) cnt_actions = pkgdblib.search_actions( SESSION, packager=packager, package=package, action=action, status=status, page=page, limit=limit, count=True, ) except PkgdbException as err: flask.flash(err, 'errors') total_page = int(ceil(cnt_actions / float(limit))) action_status = pkgdblib.get_status(SESSION, 'admin_status')['admin_status'] action_status.insert(0, 'All') return flask.render_template( 'list_actions.html', select='packagers', actions=actions, cnt_actions=cnt_actions, total_page=total_page, page=page, package=package or '', packager=packager, action=action, status=status, statuses=action_status, )
def api_admin_action_edit_status(): ''' Edit Admin Action status update ------------------------------- Edit the status of an Admin Action. :: /admin/action/status Accept POST queries only. :arg id: An integer representing the identifier of the admin action to update in the database. The identifier is returned in the API, see ``List admin actions``. :arg status: The status to which the action should be updated. Can be any of: ``Approved``, ``Awaiting Review``, ``Blocked``, ``Denied``, ``Pending`` and ``Obsolete``. ..note:: The ``Obsolete`` status can only be set by the person who made the request. Sample response: :: { "output": "ok", "messages": ["Admin action status updated to: Approved"] } { "output": "notok", "error": ["You are not an admin"] } ''' httpcode = 200 output = {} action_status = pkgdblib.get_status( SESSION, 'admin_status')['admin_status'] form = pkgdb2.forms.EditActionStatusForm( csrf_enabled=False, status=action_status, ) if form.validate_on_submit(): action_id = form.id.data admin_action = pkgdblib.get_admin_action(SESSION, action_id) if not admin_action: output['output'] = 'notok' output['error'] = 'No Admin action with this identifier found' httpcode = 500 else: try: message = pkgdblib.edit_action_status( SESSION, admin_action, action_status=form.status.data, user=flask.g.fas_user, message=form.message.data, ) SESSION.commit() output['output'] = 'ok' output['messages'] = [message] except PkgdbException as err: # pragma: no cover # We can only reach here in two cases: # 1) the user is not an admin, but that's taken care of # by the decorator # 2) we have a SQLAlchemy problem when storing the info # in the DB which we cannot test SESSION.rollback() output['output'] = 'notok' output['error'] = str(err) httpcode = 500 else: output['output'] = 'notok' output['error'] = 'Invalid input submitted' if form.errors: detail = [] for error in form.errors: detail.append('%s: %s' % (error, '; '.join(form.errors[error]))) output['error_detail'] = detail httpcode = 500 jsonout = flask.jsonify(output) jsonout.status_code = httpcode return jsonout
status=status, page=page, limit=limit, ) cnt_actions = pkgdblib.search_actions(SESSION, package=package or None, packager=packager or None, action=action, status=status, count=True) except pkgdblib.PkgdbException, err: flask.flash(err, 'errors') total_page = int(ceil(cnt_actions / float(limit))) action_status = pkgdblib.get_status(SESSION, 'admin_status')['admin_status'] action_status.insert(0, 'All') return flask.render_template( 'list_actions.html', actions=actions, cnt_actions=cnt_actions, total_page=total_page, page=page, package=package or '', packager=packager or '', action=action, status=status, statuses=action_status, )
def api_package_new(): ''' New package ----------- Create a new package. :: /api/package/new/ Accepts POST queries only. :arg pkgname: String of the package name to be created. :arg summary: String of the summary description of the package. :arg description: String describing the package (same as in the spec file). :arg review_url: the URL of the package review on the bugzilla. :arg status: status of the package can be one of: 'Approved', 'Awaiting Review', 'Denied', 'Obsolete', 'Removed' :arg branches: one or more branch names of the collection in which this package is added. :arg poc: FAS username of the point of contact :arg upstream_url: the URL of the upstream project :arg critpath: boolean specifying if the package is in the critpath Sample response: :: { "output": "ok", "messages": ["Package created"] } { "output": "notok", "error": ["You're not allowed to add a package"] } ''' httpcode = 200 output = {} collections = pkgdblib.search_collection(SESSION, '*', 'Under Development') collections.extend(pkgdblib.search_collection(SESSION, '*', 'Active')) pkg_status = pkgdblib.get_status(SESSION, 'pkg_status')['pkg_status'] form = forms.AddPackageForm( csrf_enabled=False, collections=collections, pkg_status_list=pkg_status, ) if form.validate_on_submit(): pkg_name = form.pkgname.data pkg_summary = form.summary.data pkg_description = form.description.data pkg_review_url = form.review_url.data pkg_status = form.status.data pkg_collection = form.branches.data pkg_poc = form.poc.data pkg_upstream_url = form.upstream_url.data pkg_critpath = form.critpath.data try: message = pkgdblib.add_package(SESSION, pkg_name=pkg_name, pkg_summary=pkg_summary, pkg_description=pkg_description, pkg_review_url=pkg_review_url, pkg_status=pkg_status, pkg_collection=pkg_collection, pkg_poc=pkg_poc, pkg_upstream_url=pkg_upstream_url, pkg_critpath=pkg_critpath, user=flask.g.fas_user) SESSION.commit() output['output'] = 'ok' output['messages'] = [message] except pkgdblib.PkgdbException, err: SESSION.rollback() output['output'] = 'notok' output['error'] = str(err) httpcode = 500
def api_acl_update(): ''' Update package ACL ------------------ Update the ACL for a given package. :: /api/package/acl/ Accept POST queries only. :arg pkg_name: String of the package name. :arg pkg_branch: List of strings with the name of the branches to change, update. :arg pkg_acl: List of strings of the ACL to change/update. Possible acl are: 'commit', 'build', 'watchbugzilla', 'watchcommits', 'approveacls', 'checkout'. :arg acl_status: String of the type of action required. Possible status are: 'Approved', 'Awaiting Review', 'Denied', 'Obsolete', 'Removed'. :kwarg pkg_user: the name of the user that is the target of this ACL change/update. This will only work if: 1) you are an admin, 2) you are changing one of your package. Sample response: :: { "output": "ok", "messages": ["user: $USER set acl: $ACL of package: $PACKAGE " "from: $PREVIOUS_STATUS to $NEW_STATUS on branch: " "$BRANCH"] } { "output": "notok", "error": ["You are not allowed to update ACLs of someone else."] } ''' httpcode = 200 output = {} status = pkgdblib.get_status(SESSION, ['pkg_acl', 'acl_status']) form = forms.SetAclPackageForm( csrf_enabled=False, pkg_acl=status['pkg_acl'], acl_status=status['acl_status'], ) if form.validate_on_submit(): pkg_name = form.pkg_name.data pkg_branch = form.pkg_branch.data.split(',') pkg_acl = form.pkg_acl.data.split(',') acl_status = form.acl_status.data pkg_user = form.pkg_user.data try: messages = [] for (acl, branch) in itertools.product(pkg_acl, pkg_branch): message = pkgdblib.set_acl_package( SESSION, pkg_name=pkg_name, pkg_branch=branch, acl=acl, status=acl_status, pkg_user=pkg_user, user=flask.g.fas_user, ) messages.append(message) SESSION.commit() output['output'] = 'ok' output['messages'] = messages except pkgdblib.PkgdbException, err: SESSION.rollback() output['output'] = 'notok' output['error'] = str(err) httpcode = 500
def api_package_new(): ''' New package ----------- Create a new package. :: /api/package/new/ Accept POST queries only. :arg pkgname: String of the package name to be created. :arg summary: String of the summary description of the package. :arg description: String describing the package (same as in the spec file). :arg review_url: the URL of the package review on the bugzilla. :arg status: status of the package can be one of: 'Approved', 'Awaiting Review', 'Denied', 'Obsolete', 'Removed' :arg branches: one or more branch names of the collection in which this package is added. :arg poc: FAS username of the point of contact :arg upstream_url: the URL of the upstream project :arg critpath: boolean specifying if the package is in the critpath Sample response: :: { "output": "ok", "messages": ["Package created"] } { "output": "notok", "error": ["You're not allowed to add a package"] } ''' httpcode = 200 output = {} collections = pkgdblib.search_collection( SESSION, '*', 'Under Development') collections.extend(pkgdblib.search_collection(SESSION, '*', 'Active')) pkg_status = pkgdblib.get_status(SESSION, 'pkg_status')['pkg_status'] form = forms.AddPackageForm( csrf_enabled=False, collections=collections, pkg_status_list=pkg_status, ) if form.validate_on_submit(): pkg_name = form.pkgname.data pkg_summary = form.summary.data pkg_description = form.description.data pkg_review_url = form.review_url.data pkg_status = form.status.data pkg_collection = form.branches.data pkg_poc = form.poc.data pkg_upstream_url = form.upstream_url.data pkg_critpath = form.critpath.data try: message = pkgdblib.add_package( SESSION, pkg_name=pkg_name, pkg_summary=pkg_summary, pkg_description=pkg_description, pkg_review_url=pkg_review_url, pkg_status=pkg_status, pkg_collection=pkg_collection, pkg_poc=pkg_poc, pkg_upstream_url=pkg_upstream_url, pkg_critpath=pkg_critpath, user=flask.g.fas_user ) SESSION.commit() output['output'] = 'ok' output['messages'] = [message] except pkgdblib.PkgdbException, err: SESSION.rollback() output['output'] = 'notok' output['error'] = str(err) httpcode = 500
def packager_requests(packager): ''' Display the requests made by the specified packager. ''' action = flask.request.args.get('action') or None package = flask.request.args.get('package') or None status = flask.request.args.get('status', 'All') limit = flask.request.args.get('limit', APP.config['ITEMS_PER_PAGE']) page = flask.request.args.get('page', 1) try: page = abs(int(page)) except ValueError: page = 1 try: limit = abs(int(limit)) except ValueError: limit = APP.config['ITEMS_PER_PAGE'] flask.flash('Incorrect limit provided, using default', 'errors') actions = [] cnt_actions = 0 try: actions = pkgdblib.search_actions( SESSION, packager=packager, package=package, action=action, status=status, page=page, limit=limit, order='desc', ) cnt_actions = pkgdblib.search_actions( SESSION, packager=packager, package=package, action=action, status=status, page=page, limit=limit, count=True, ) except PkgdbException as err: flask.flash(err, 'errors') total_page = int(ceil(cnt_actions / float(limit))) action_status = pkgdblib.get_status( SESSION, 'admin_status')['admin_status'] action_status.insert(0, 'All') return flask.render_template( 'list_actions.html', select='packagers', actions=actions, cnt_actions=cnt_actions, total_page=total_page, page=page, package=package or '', packager=packager, action=action, status=status, statuses=action_status, )
def api_collection_status(collection): ''' Update collection status ------------------------ Update the status of collection. :: /api/collection/<collection branchname>/status/ Accept POST query only. :arg collection_branchname: String of the collection branch name to change. :arg collection_status: String of the status to change the collection to Sample response: :: { "output": "ok", "messages": ["Collection updated to \"EOL\""] } { "output": "notok", "error": ["You are not allowed to edit collections"] } ''' httpcode = 200 output = {} clt_status = pkgdblib.get_status(SESSION, 'clt_status')['clt_status'] form = forms.CollectionStatusForm( csrf_enabled=False, clt_status=clt_status, ) if form.validate_on_submit(): clt_branchname = form.collection_branchname.data clt_status = form.collection_status.data if collection == clt_branchname: try: message = pkgdblib.update_collection_status( SESSION, clt_branchname, clt_status, user=flask.g.fas_user ) SESSION.commit() output['output'] = 'ok' output['messages'] = [message] except pkgdblib.PkgdbException, err: SESSION.rollback() output['output'] = 'notok' output['error'] = str(err) httpcode = 500 else: output['output'] = 'notok' output['error'] = "You're trying to update the " \ "wrong collection" httpcode = 500
def api_packager_acl(packagername=None): ''' User's ACL ---------- List the ACLs of the user. :: /api/packager/acl/<fas_username>/ /api/packager/acl/?packagername=<username> Accept GET queries only. :arg packagername: String of the packager name. :kwarg acls: One or more ACL to filter the ACLs retrieved. Options are: ``approveacls``, ``commit``, ``watchbugzilla``, ``watchcommits``. :kwarg eol: a boolean to specify whether to include results for EOL collections or not. Defaults to False. If ``True``, it will return results for all collections (including EOL). If ``False``, it will return results only for non-EOL collections. :kwarg poc: a boolean specifying whether the results should be restricted to ACL for which the provided packager is the point of contact or not. Defaults to None. If ``True`` it will only return ACLs for packages on which the provided packager is point of contact. If ``False`` it will only return ACLs for packages on which the provided packager is not the point of contact. If ``None`` it will not filter the ACLs returned based on the point of contact of the package (thus every packages is returned). :kwarg page: The page number to return (useful in combination to limit). :kwarg limit: An integer to limit the number of results, defaults to 250, maximum is 500 (acls). :kwarg count: A boolean to return the number of packages instead of the list. Defaults to False. *Results are paginated* Sample response: :: /api/packager/acl/pingou { "output": "ok", "page": 1, "page_total": 12 "acls": [ { "status": "Approved", "fas_name": "pingou", "packagelist": { "point_of_contact": "pingou", "critpath": False, "collection": { "status": "EOL", "branchname": "f16", "version": "16", "name": "Fedora" }, "package": { "status": "Approved", "upstream_url": null, "description": null, "summary": "Data of T- and B-cell Acute Lymphocytic " "Leukemia", "creation_date": 1384775354.0, "review_url": null, "name": "R-ALL" } }, "acl": "watchcommits" }, { "status": "Approved", "fas_name": "pingou", "packagelist": { "point_of_contact": "pingou", "critpath": False, "collection": { "status": "EOL", "branchname": "f16", "version": "16", "name": "Fedora" }, "package": { "status": "Approved", "upstream_url": null, "description": null, "summary": "Data of T- and B-cell Acute Lymphocytic " "Leukemia", "creation_date": 1384775354.0, "review_url": null, "name": "R-ALL" } }, "acl": "watchbugzilla" } ] } /api/packager/acl/?packagername=random { "output": "notok", "error": "No ACL found for this user", "page": 1 } ''' httpcode = 200 output = {} packagername = flask.request.args.get('packagername', None) or packagername acls = flask.request.args.getlist('acls', None) eol = flask.request.args.get('eol', False) poc = flask.request.args.get('poc', None) if poc is not None: if poc in ['False', '0', 0]: poc = False poc = bool(poc) pkg_acl = pkgdblib.get_status(SESSION, 'pkg_acl')['pkg_acl'] for acl in acls: if acl not in pkg_acl: output = { 'output': 'notok', 'error': 'Invalid request, "%s" is an invalid acl' % acl} httpcode = 500 jsonout = flask.jsonify(output) jsonout.status_code = httpcode return jsonout page = flask.request.args.get('page', 1) limit = get_limit() count = flask.request.args.get('count', False) if packagername: packagers = pkgdblib.get_acl_packager( SESSION, packager=packagername, acls=acls, eol=eol, poc=poc, page=page, limit=limit, count=count) if packagers: output['output'] = 'ok' if count: output['acls_count'] = packagers else: output['acls'] = [pkg.to_json() for pkg in packagers] total_acl = pkgdblib.get_acl_packager( SESSION, packager=packagername, acls=acls, eol=eol, poc=poc, count=True) if count: output['page_total'] = 1 else: output['page_total'] = int(ceil(total_acl / float(limit))) else: output = {'output': 'notok', 'error': 'No ACL found for this user'} httpcode = 404 else: output = {'output': 'notok', 'error': 'Invalid request'} httpcode = 500 output['page'] = page if 'page_total' not in output: output['page_total'] = 1 jsonout = flask.jsonify(output) jsonout.status_code = httpcode return jsonout
limit=limit, ) cnt_actions = pkgdblib.search_actions( SESSION, package=package or None, packager=packager or None, action=action, status=status, count=True ) except pkgdblib.PkgdbException, err: flask.flash(err, 'errors') total_page = int(ceil(cnt_actions / float(limit))) action_status = pkgdblib.get_status( SESSION, 'admin_status')['admin_status'] action_status.insert(0, 'All') return flask.render_template( 'list_actions.html', actions=actions, cnt_actions=cnt_actions, total_page=total_page, page=page, package=package or '', packager=packager or '', action=action, status=status, statuses=action_status, )
def update_acl(namespace, package, update_acl): ''' Update the acls of a package. ''' packagename = package package = None try: package_acl = pkgdblib.get_acl_package( SESSION, namespace, packagename) package = pkgdblib.search_package( SESSION, namespace, packagename, limit=1)[0] except (NoResultFound, IndexError): SESSION.rollback() flask.flash('No package of this name found.', 'errors') return flask.render_template('msg.html') statues = pkgdblib.get_status(SESSION) planned_acls = set(statues['pkg_acl']) acl_status = list(set(statues['acl_status'])) acl_status.insert(0, '') if update_acl not in planned_acls: flask.flash('Invalid ACL to update.', 'errors') return flask.redirect(flask.url_for( '.package_info', namespace=package.namespace, package=package.name) ) branches = {} branches_inv = {} commit_acls = {} admins = {} committers = [] for pkg in package_acl: if pkg.collection.status == 'EOL': # pragma: no cover continue collection_name = '%s %s' % ( pkg.collection.name, pkg.collection.version) if collection_name not in branches: branches[collection_name] = pkg.collection.branchname if pkg.collection.branchname not in branches_inv: branches_inv[pkg.collection.branchname] = collection_name for acl in pkg.acls: if acl.acl == 'approveacls' and acl.status == 'Approved': if acl.fas_name not in admins: admins[acl.fas_name] = set() admins[acl.fas_name].add(collection_name) if acl.acl != update_acl: continue committers.append(acl.fas_name) if acl.fas_name not in commit_acls: commit_acls[acl.fas_name] = {} if collection_name not in commit_acls[acl.fas_name]: commit_acls[acl.fas_name][collection_name] = {} commit_acls[acl.fas_name][collection_name][acl.acl] = \ acl.status for aclname in planned_acls: for user in commit_acls: if collection_name in commit_acls[user] and \ aclname not in commit_acls[user][collection_name]: commit_acls[user][collection_name][aclname] = None # If the user is not an admin, he/she can only access his/her ACLs username = flask.g.fas_user.username if username not in admins and not is_pkgdb_admin(flask.g.fas_user): tmp = {username: []} if username in commit_acls: tmp = {username: commit_acls[username]} commit_acls = tmp form = pkgdb2.forms.ConfirmationForm() if form.validate_on_submit(): sub_acls = flask.request.values.getlist('acls') sub_users = flask.request.values.getlist('user') sub_branches = flask.request.values.getlist('branch') changed = False if sub_acls and len(sub_acls) == (len(sub_users) * len(sub_branches)): cnt = 0 for cnt_u in range(len(sub_users)): for cnt_b in range(len(sub_branches)): lcl_acl = sub_acls[cnt] lcl_user = sub_users[cnt_u] lcl_branch = sub_branches[cnt_b] if lcl_acl not in acl_status: flask.flash('Invalid ACL: %s' % lcl_acl, 'error') cnt += 1 continue if lcl_user not in commit_acls: flask.flash('Invalid user: %s' % lcl_user, 'error') cnt += 1 continue if lcl_branch not in branches_inv or ( branches_inv[lcl_branch] in commit_acls[lcl_user] and commit_acls[lcl_user][ branches_inv[lcl_branch]][ update_acl] == lcl_acl): cnt += 1 continue if not lcl_acl: if branches_inv[lcl_branch] \ not in commit_acls[lcl_user]: cnt += 1 continue elif branches_inv[lcl_branch] \ in commit_acls[lcl_user] \ and username != lcl_user: flask.flash( 'Only the user can remove his/her ACL', 'error') cnt += 1 continue try: pkgdblib.set_acl_package( SESSION, namespace=namespace, pkg_name=package.name, pkg_branch=lcl_branch, pkg_user=lcl_user, acl=update_acl, status=lcl_acl, user=flask.g.fas_user, ) SESSION.commit() flask.flash("%s's %s ACL updated on %s" % ( lcl_user, update_acl, lcl_branch)) changed = True except PkgdbException as err: SESSION.rollback() flask.flash(str(err), 'error') cnt += 1 SESSION.commit() if not changed: flask.flash('Nothing to update') return flask.redirect(flask.url_for( '.package_info', namespace=package.namespace, package=package.name) ) else: flask.flash('Invalid input submitted', 'error') return flask.render_template( 'acl_update.html', acl=update_acl, acl_status=acl_status, package=package, form=form, branches=branches, commit_acls=commit_acls, admins=admins, committers=committers, )