def stats(): """ Display some statistics aboue the packages in the DB. """ collections = pkgdblib.search_collection(SESSION, "*", "Active") collections.extend(pkgdblib.search_collection(SESSION, "*", "Under Development")) collections = pkgdblib.count_collection(SESSION) collections_fedora = pkgdblib.count_fedora_collection(SESSION) cnt = 1 collections_fedora_lbl = [] collections_fedora_data = [] for item in collections_fedora: collections_fedora_lbl.append([cnt, str(item[0])]) collections_fedora_data.append([cnt, float(item[1])]) cnt += 1 # Top maintainers top_maintainers = pkgdblib.get_top_maintainers(SESSION) # Top point of contact top_poc = pkgdblib.get_top_poc(SESSION) return flask.render_template( "stats.html", collections=collections, collections_fedora_lbl=collections_fedora_lbl, collections_fedora_data=collections_fedora_data, top_maintainers=top_maintainers, top_poc=top_poc, )
def stats(): ''' Display some statistics aboue the packages in the DB. ''' collections = pkgdblib.search_collection(SESSION, '*', 'Active') collections.extend( pkgdblib.search_collection(SESSION, '*', 'Under Development')) collections = pkgdblib.count_collection(SESSION) collections_fedora = pkgdblib.count_fedora_collection(SESSION) cnt = 1 collections_fedora_lbl = [] collections_fedora_data = [] for item in collections_fedora: collections_fedora_lbl.append([cnt, str(item[0])]) collections_fedora_data.append([cnt, float(item[1])]) cnt += 1 # Top maintainers top_maintainers = pkgdblib.get_top_maintainers(SESSION) # Top point of contact top_poc = pkgdblib.get_top_poc(SESSION) return flask.render_template( 'stats.html', collections=collections, collections_fedora_lbl=collections_fedora_lbl, collections_fedora_data=collections_fedora_data, top_maintainers=top_maintainers, top_poc=top_poc, )
def list_collections(motif=None, page=1): ''' Display the list of collections corresponding to the motif. ''' pattern = flask.request.args.get('motif', motif) or '*' limit = flask.request.args.get('limit', APP.config['ITEMS_PER_PAGE']) try: limit = abs(int(limit)) except ValueError: limit = APP.config['ITEMS_PER_PAGE'] flask.flash('Incorrect limit provided, using default', 'errors') collections = pkgdblib.search_collection( SESSION, pattern=pattern, page=page, limit=limit, ) collections_count = pkgdblib.search_collection( SESSION, pattern=pattern, page=page, limit=limit, count=True ) total_page = int(ceil(collections_count / float(limit))) return flask.render_template( 'list_collections.html', collections=collections, motif=motif, total_page=total_page, page=page )
def list_collections(motif=None, page=1): ''' Display the list of collections corresponding to the motif. ''' pattern = flask.request.args.get('motif', motif) or '*' limit = flask.request.args.get('limit', APP.config['ITEMS_PER_PAGE']) try: limit = abs(int(limit)) except ValueError: limit = APP.config['ITEMS_PER_PAGE'] flask.flash('Incorrect limit provided, using default', 'errors') collections = pkgdblib.search_collection( SESSION, pattern=pattern, page=page, limit=limit, ) collections_count = pkgdblib.search_collection(SESSION, pattern=pattern, page=page, limit=limit, count=True) total_page = int(ceil(collections_count / float(limit))) return flask.render_template('list_collections.html', collections=collections, motif=motif, total_page=total_page, page=page)
def api_critpath(): '''Return the list of package marked as critpath for all active release of fedora. :kwarg out_format: Specify if the output if text or json. ''' out_format = flask.request.args.get('format', 'text') if out_format not in ('text', 'json'): out_format = 'text' if request_wants_json(): out_format = 'json' output = {} active_collections = pkgdblib.search_collection( SESSION, '*', status='Under Development') active_collections.extend( pkgdblib.search_collection(SESSION, '*', status='Active')) for collection in active_collections: if collection.name != 'Fedora': continue pkgs = pkgdblib.get_critpath_packages( SESSION, branch=collection.branchname) if not pkgs: continue output[collection.branchname] = [pkg.package.name for pkg in pkgs] if out_format == 'json': output = {"pkgs": output} return flask.jsonify(output) else: output_str = "" keys = output.keys() keys.reverse() for key in keys: output_str += "== %s ==\n" % key for pkg in output[key]: output_str += "* %s\n" % pkg return flask.Response( output_str, content_type="text/plain;charset=UTF-8" )
def api_critpath(): '''Return the list of package marked as critpath for all active release of fedora. :kwarg out_format: Specify if the output if text or json. ''' out_format = flask.request.args.get('format', 'text') if out_format not in ('text', 'json'): out_format = 'text' if request_wants_json(): out_format = 'json' output = {} active_collections = pkgdblib.search_collection(SESSION, '*', status='Under Development') active_collections.extend( pkgdblib.search_collection(SESSION, '*', status='Active')) for collection in active_collections: if collection.name != 'Fedora': continue pkgs = pkgdblib.get_critpath_packages(SESSION, branch=collection.branchname) if not pkgs: continue output[collection.branchname] = [pkg.package.name for pkg in pkgs] if out_format == 'json': output = {"pkgs": output} return flask.jsonify(output) else: output_str = "" keys = output.keys() keys.reverse() for key in keys: output_str += "== %s ==\n" % key for pkg in output[key]: output_str += "* %s\n" % pkg return flask.Response(output_str, content_type="text/plain;charset=UTF-8")
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 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. ''' 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 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 collection_info(collection): ''' Display 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') return flask.render_template( 'collection.html', collection=collection, )
def api_packager_stats(packagername=None): ''' User's stats ------------ Give some stats about the ACLs of the user. :: /api/packager/stats/<fas_username>/ /api/packager/stats/?packagername=<username> Accept GET queries only. :arg packagername: String of the packager name. :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. Sample response: :: /api/packager/stats/pingou { "EL-6": { "co-maintainer": 8, "point of contact": 12 }, "master": { "co-maintainer": 12, "point of contact": 60 }, "f19": { "co-maintainer": 12, "point of contact": 60 }, "f20": { "co-maintainer": 12, "point of contact": 60 }, "output": "ok" } /api/packager/stats/?packagername=random { "EL-6": { "co-maintainer": 0, "point of contact": 0 }, "master": { "co-maintainer": 0, "point of contact": 0 }, "f19": { "co-maintainer": 0, "point of contact": 0 }, "f20": { "co-maintainer": 0, "point of contact": 0 }, "output": "ok" } ''' httpcode = 200 output = {} packagername = flask.request.args.get('packagername', None) or packagername eol = flask.request.args.get('eol', False) if packagername: if not eol: collections = pkgdblib.search_collection( SESSION, '*', status='Active') collections.extend(pkgdblib.search_collection( SESSION, '*', status='Under Development')) else: collections = pkgdblib.search_collection(SESSION, '*') for collection in collections: packages_co = pkgdblib.get_package_maintained( SESSION, packager=packagername, poc=False, branch=collection.branchname ) packages = pkgdblib.get_package_maintained( SESSION, packager=packagername, poc=True, branch=collection.branchname ) output[collection.branchname] = { 'point of contact': len(packages), 'co-maintainer': len(packages_co) } output['output'] = 'ok' else: output = {'output': 'notok', 'error': 'Invalid request'} httpcode = 500 jsonout = flask.jsonify(output) jsonout.status_code = httpcode return jsonout
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_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 api_critpath(): ''' Critical path packages ---------------------- Return the list of package marked as critpath for some or all active releases of fedora. :: /api/critpath :kwarg branches: Return the list of packages marked as critpath in the specified branch(es). :kwarg format: Specify if the output if text or json. ''' out_format = flask.request.args.get('format', 'text') branches = flask.request.args.getlist('branches') if out_format not in ('text', 'json'): out_format = 'text' if request_wants_json(): out_format = 'json' output = {} if not branches: active_collections = pkgdblib.search_collection( SESSION, '*', status='Under Development') active_collections.extend( pkgdblib.search_collection(SESSION, '*', status='Active')) else: active_collections = [] for branch in branches: active_collections.extend( pkgdblib.search_collection(SESSION, branch) ) for collection in active_collections: if collection.name != 'Fedora': continue pkgs = pkgdblib.get_critpath_packages( SESSION, branch=collection.branchname) if not pkgs: continue output[collection.branchname] = [pkg.package.name for pkg in pkgs] if out_format == 'json': output = {"pkgs": output} return flask.jsonify(output) else: output_str = [] keys = output.keys() keys.reverse() for key in keys: output_str.append("== %s ==\n" % key) for pkg in output[key]: output_str.append("* %s\n" % pkg) return flask.Response( ''.join(output_str), content_type="text/plain;charset=UTF-8" )
def api_collection_list(pattern=None): ''' List collections ---------------- List the collections based on a pattern. If no pattern is provided, it will return all the collection. :: /api/collections/<pattern>/ /api/collections/?pattern=<pattern> Accepts GET queries only. :arg pattern: a pattern to which the collection searched should match. :arg clt_status: restrict the search to one or more collection status. Sample response: :: /api/collections { "collections": [ { "allow_retire": false, "branchname": "f20", "date_created": "2014-05-14 12:36:15", "date_updated": "2014-05-14 12:36:15", "dist_tag": ".fc20", "koji_name": "f20", "name": "Fedora", "status": "Active", "version": "20" }, { "allow_retire": true, "branchname": "f17", "date_created": "2014-05-14 12:36:15", "date_updated": "2014-05-14 12:36:15", "dist_tag": ".fc17", "koji_name": "f17", "name": "Fedora", "status": "EOL", "version": "17" }, { "allow_retire": true, "branchname": "el6", "date_created": "2014-05-14 12:36:15", "date_updated": "2014-05-14 12:36:15", "dist_tag": ".el6", "koji_name": "dist-6E-epel", "name": "Fedora EPEL", "status": "Active", "version": "6" } ] } :: /api/collections?pattern=el* { "collections": [ { "allow_retire": true, "branchname": "el4", "date_created": "2014-05-14 12:36:15", "date_updated": "2014-05-14 12:36:15", "dist_tag": ".el4", "koji_name": "dist-4E-epel", "name": "Fedora EPEL", "status": "EOL", "version": "4" }, { "allow_retire": true, "branchname": "el5", "date_created": "2014-05-14 12:36:15", "date_updated": "2014-05-14 12:36:15", "dist_tag": ".el5", "koji_name": "dist-5E-epel", "name": "Fedora EPEL", "status": "Active", "version": "5" }, { "allow_retire": true, "branchname": "el6", "date_created": "2014-05-14 12:36:15", "date_updated": "2014-05-14 12:36:15", "dist_tag": ".el6", "koji_name": "dist-6E-epel", "name": "Fedora EPEL", "status": "Active", "version": "6" } ] } ''' httpcode = 200 output = {} pattern = flask.request.args.get('pattern', None) or pattern status = flask.request.args.getlist('clt_status', None) if pattern: if status: collections = [] for stat in status: collections.extend(pkgdblib.search_collection( SESSION, pattern=pattern, status=stat) ) else: collections = pkgdblib.search_collection( SESSION, pattern=pattern) else: if status: collections = [] for stat in status: collections.extend(pkgdblib.search_collection( SESSION, pattern='*', status=stat) ) else: collections = model.Collection.all(SESSION) output = {'collections': [collec.to_json() for collec in collections] } output['output'] = 'ok' jsonout = flask.jsonify(output) jsonout.status_code = httpcode return jsonout
def api_packager_stats(packagername=None): ''' User's stats ------------ Give some stats about the ACLs of the user. :: /api/packager/stats/<fas_username>/ /api/packager/stats/?packagername=<username> Accept GET queries only. :arg packagername: String of the packager name. Sample response: :: /api/packager/stats/pingou { "EL-6": { "co-maintainer": 8, "point of contact": 12 }, "devel": { "co-maintainer": 12, "point of contact": 60 }, "f19": { "co-maintainer": 12, "point of contact": 60 }, "f20": { "co-maintainer": 12, "point of contact": 60 }, "output": "ok" } /api/packager/stats/?packagername=random { "EL-6": { "co-maintainer": 0, "point of contact": 0 }, "devel": { "co-maintainer": 0, "point of contact": 0 }, "f19": { "co-maintainer": 0, "point of contact": 0 }, "f20": { "co-maintainer": 0, "point of contact": 0 }, "output": "ok" } ''' httpcode = 200 output = {} packagername = flask.request.args.get('packagername', None) or packagername if packagername: collections = pkgdblib.search_collection(SESSION, '*', status='Active', limit=10000) collections.extend( pkgdblib.search_collection(SESSION, '*', status='Under Development', limit=10000)) for collection in collections: packages_co = pkgdblib.get_package_maintained( SESSION, packager=packagername, poc=False, branch=collection.branchname) packages = pkgdblib.get_package_maintained( SESSION, packager=packagername, poc=True, branch=collection.branchname) output[collection.branchname] = { 'point of contact': len(packages), 'co-maintainer': len(packages_co) } output['output'] = 'ok' else: output = {'output': 'notok', 'error': 'Invalid request'} httpcode = 500 jsonout = flask.jsonify(output) jsonout.status_code = httpcode return jsonout
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/ 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_collection_list(pattern=None): ''' List collections ---------------- List the collections based on a pattern. If no pattern is provided, it will return all the collection. :: /api/collections/<pattern>/ /api/collections/?pattern=<pattern> Accepts GET queries only. :arg pattern: a pattern to which the collection searched should match. :arg clt_status: restrict the search to one or more collection status. Sample response: :: /api/collections { "collections": [ { "allow_retire": false, "branchname": "f20", "date_created": "2014-05-14 12:36:15", "date_updated": "2014-05-14 12:36:15", "dist_tag": ".fc20", "koji_name": "f20", "name": "Fedora", "status": "Active", "version": "20" }, { "allow_retire": true, "branchname": "f17", "date_created": "2014-05-14 12:36:15", "date_updated": "2014-05-14 12:36:15", "dist_tag": ".fc17", "koji_name": "f17", "name": "Fedora", "status": "EOL", "version": "17" }, { "allow_retire": true, "branchname": "el6", "date_created": "2014-05-14 12:36:15", "date_updated": "2014-05-14 12:36:15", "dist_tag": ".el6", "koji_name": "dist-6E-epel", "name": "Fedora EPEL", "status": "Active", "version": "6" } ] } :: /api/collections?pattern=el* { "collections": [ { "allow_retire": true, "branchname": "el4", "date_created": "2014-05-14 12:36:15", "date_updated": "2014-05-14 12:36:15", "dist_tag": ".el4", "koji_name": "dist-4E-epel", "name": "Fedora EPEL", "status": "EOL", "version": "4" }, { "allow_retire": true, "branchname": "el5", "date_created": "2014-05-14 12:36:15", "date_updated": "2014-05-14 12:36:15", "dist_tag": ".el5", "koji_name": "dist-5E-epel", "name": "Fedora EPEL", "status": "Active", "version": "5" }, { "allow_retire": true, "branchname": "el6", "date_created": "2014-05-14 12:36:15", "date_updated": "2014-05-14 12:36:15", "dist_tag": ".el6", "koji_name": "dist-6E-epel", "name": "Fedora EPEL", "status": "Active", "version": "6" } ] } ''' httpcode = 200 output = {} pattern = flask.request.args.get('pattern', None) or pattern status = flask.request.args.getlist('clt_status', None) if pattern: if status: collections = [] for stat in status: collections.extend( pkgdblib.search_collection(SESSION, pattern=pattern, status=stat)) else: collections = pkgdblib.search_collection(SESSION, pattern=pattern) else: if status: collections = [] for stat in status: collections.extend( pkgdblib.search_collection(SESSION, pattern='*', status=stat)) else: collections = model.Collection.all(SESSION) output = {'collections': [collec.to_json() for collec in collections]} output['output'] = 'ok' jsonout = flask.jsonify(output) jsonout.status_code = httpcode return jsonout
def api_critpath(): ''' Critical path packages ---------------------- Return the list of package marked as critpath for some or all active releases of fedora. :: /api/critpath :kwarg branches: Return the list of packages marked as critpath in the specified branch(es). :kwarg format: Specify if the output if text or json. ''' out_format = flask.request.args.get('format', 'text') branches = flask.request.args.getlist('branches') if out_format not in ('text', 'json'): out_format = 'text' if request_wants_json(): out_format = 'json' output = {} if not branches: active_collections = pkgdblib.search_collection( SESSION, '*', status='Under Development') active_collections.extend( pkgdblib.search_collection(SESSION, '*', status='Active')) else: active_collections = [] for branch in branches: active_collections.extend( pkgdblib.search_collection(SESSION, branch)) for collection in active_collections: if collection.name != 'Fedora': continue pkgs = pkgdblib.get_critpath_packages(SESSION, branch=collection.branchname) if not pkgs: continue output[collection.branchname] = [pkg.package.name for pkg in pkgs] if out_format == 'json': output = {"pkgs": output} return flask.jsonify(output) else: output_str = [] keys = output.keys() keys.reverse() for key in keys: output_str.append("== %s ==\n" % key) for pkg in output[key]: output_str.append("* %s\n" % pkg) return flask.Response(''.join(output_str), content_type="text/plain;charset=UTF-8")
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_branch_request(package, namespace='rpms'): ''' New branch request ------------------ Request a new branch for package in pkgdb. :: /api/request/branch/<namespace>/<package> Accepts POST queries only. :arg package: The name of the package :arg branches: The list of branches desired for this package. :arg namespace: The namespace of the package (default to ``rpms``). Sample response: :: { 'messages': [ 'Branch f17 created for user pingou', ], 'output': 'ok' } { "messages": [ "Branch el6 requested for user pingou" ], "output": "ok" } { "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", ], "output": "notok" } ''' httpcode = 200 output = {} 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() output['output'] = 'notok' output['error'] = 'No package found: %s/%s' % (namespace, package) httpcode = 404 else: branches = [ pkg.collection.branchname for pkg in package_acl if pkg.collection.status != 'EOL' ] collections = pkgdblib.search_collection( SESSION, '*', 'Under Development') collections.extend(pkgdblib.search_collection( SESSION, '*', 'Active')) branches_possible = [ collec.branchname for collec in collections if collec.branchname not in branches] form = forms.BranchForm( collections=branches_possible, csrf_enabled=False, ) if form.validate_on_submit(): try: messages = [] for branch in form.branches.data: msg = pkgdblib.add_new_branch_request( session=SESSION, namespace=namespace, pkg_name=package.name, clt_to=branch, user=flask.g.fas_user) if msg: messages.append(msg) SESSION.commit() output['output'] = 'ok' output['messages'] = messages except pkgdblib.PkgdbException, err: # pragma: no cover SESSION.rollback() output['output'] = 'notok' output['error'] = str(err) httpcode = 400 except SQLAlchemyError, err: # pragma: no cover SESSION.rollback() APP.logger.exception(err) output['output'] = 'notok' output['error'] = 'Could not save the request to the '\ 'database for branch: %s' % branch httpcode = 400
def api_collection_list(pattern=None): ''' List collections ---------------- List the collections based on a pattern. If no pattern is provided, it will return all the collection. :: /api/collections/<pattern>/ /api/collections/?pattern=<pattern> Accept GET queries only. :arg pattern: a pattern to which the collection searched should match. :arg clt_status: restrict the search to one or more collection status. Sample response: :: /api/collections { "collections": [ { "status": "Active", "branchname": "f20", "version": "20", "name": "Fedora" }, { "status": "EOL", "branchname": "F-17", "version": "17", "name": "Fedora" }, { "status": "Active", "branchname": "EL-6", "version": "6", "name": "Fedora EPEL" } ] } :: /api/collections?pattern=EL* { "collections": [ { "status": "EOL", "branchname": "EL-4", "version": "4", "name": "Fedora EPEL" }, { "status": "Active", "branchname": "EL-5", "version": "5", "name": "Fedora EPEL" }, { "status": "Active", "branchname": "EL-6", "version": "6", "name": "Fedora EPEL" } ] } ''' httpcode = 200 output = {} pattern = flask.request.args.get('pattern', None) or pattern status = flask.request.args.getlist('clt_status', None) if pattern: if status: collections = [] for stat in status: collections.extend(pkgdblib.search_collection( SESSION, pattern=pattern, status=stat) ) else: collections = pkgdblib.search_collection( SESSION, pattern=pattern) else: collections = model.Collection.all(SESSION) output = {'collections': [collec.to_json() for collec in collections] } output['output'] = 'ok' jsonout = flask.jsonify(output) jsonout.status_code = httpcode return jsonout
def api_packager_stats(packagername=None): ''' User's stats ------------ Give some stats about the ACLs of the user. :: /api/packager/stats/<fas_username>/ /api/packager/stats/?packagername=<username> Accepts GET queries only. :arg packagername: String of the packager name. :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. Sample response: :: /api/packager/stats/pingou { "EL-6": { "co-maintainer": 8, "point of contact": 12 }, "master": { "co-maintainer": 12, "point of contact": 60 }, "f19": { "co-maintainer": 12, "point of contact": 60 }, "f20": { "co-maintainer": 12, "point of contact": 60 }, "output": "ok" } /api/packager/stats/?packagername=random { "EL-6": { "co-maintainer": 0, "point of contact": 0 }, "master": { "co-maintainer": 0, "point of contact": 0 }, "f19": { "co-maintainer": 0, "point of contact": 0 }, "f20": { "co-maintainer": 0, "point of contact": 0 }, "output": "ok" } ''' httpcode = 200 output = {} packagername = flask.request.args.get('packagername', None) or packagername eol = flask.request.args.get('eol', False) if packagername: if not eol: collections = pkgdblib.search_collection(SESSION, '*', status='Active') collections.extend( pkgdblib.search_collection(SESSION, '*', status='Under Development')) else: collections = pkgdblib.search_collection(SESSION, '*') for collection in collections: packages_co = pkgdblib.get_package_maintained( SESSION, packager=packagername, poc=False, branch=collection.branchname) packages = pkgdblib.get_package_maintained( SESSION, packager=packagername, poc=True, branch=collection.branchname) output[collection.branchname] = { 'point of contact': len(packages), 'co-maintainer': len(packages_co) } output['output'] = 'ok' else: output = {'output': 'notok', 'error': 'Invalid request'} httpcode = 500 jsonout = flask.jsonify(output) jsonout.status_code = httpcode return jsonout
def api_collection_list(pattern=None): ''' List collections ---------------- List the collections based on a pattern. If no pattern is provided, it will return all the collection. :: /api/collections/<pattern>/ /api/collections/?pattern=<pattern> Accept GET queries only. :arg pattern: a pattern to which the collection searched should match. :arg status: restrict the search to certain status. Sample response: :: /api/collections { "collections": [ { "status": "Active", "branchname": "f20", "version": "20", "name": "Fedora" }, { "status": "EOL", "branchname": "F-17", "version": "17", "name": "Fedora" }, { "status": "Active", "branchname": "EL-6", "version": "6", "name": "Fedora EPEL" } ] } :: /api/collections?pattern=EL* { "collections": [ { "status": "EOL", "branchname": "EL-4", "version": "4", "name": "Fedora EPEL" }, { "status": "Active", "branchname": "EL-5", "version": "5", "name": "Fedora EPEL" }, { "status": "Active", "branchname": "EL-6", "version": "6", "name": "Fedora EPEL" } ] } ''' httpcode = 200 output = {} pattern = flask.request.args.get('pattern', None) or pattern status = flask.request.args.get('status', None) if pattern: if status: status = status.split(',') collections = [] for stat in status: collections.extend(pkgdblib.search_collection( SESSION, pattern=pattern, status=stat) ) else: collections = pkgdblib.search_collection( SESSION, pattern=pattern) else: collections = model.Collection.all(SESSION) output = {'collections': [collec.to_json() for collec in collections] } jsonout = flask.jsonify(output) jsonout.status_code = httpcode return jsonout
def api_packager_stats(packagername=None): ''' User's stats ------------ Give some stats about the ACLs of the user. :: /api/packager/stats/<fas_username>/ /api/packager/stats/?packagername=<username> Accept GET queries only. :arg packagername: String of the packager name. Sample response: :: /api/packager/stats/pingou { "EL-6": { "co-maintainer": 8, "point of contact": 12 }, "devel": { "co-maintainer": 12, "point of contact": 60 }, "f19": { "co-maintainer": 12, "point of contact": 60 }, "f20": { "co-maintainer": 12, "point of contact": 60 }, "output": "ok" } /api/packager/stats/?packagername=random { "EL-6": { "co-maintainer": 0, "point of contact": 0 }, "devel": { "co-maintainer": 0, "point of contact": 0 }, "f19": { "co-maintainer": 0, "point of contact": 0 }, "f20": { "co-maintainer": 0, "point of contact": 0 }, "output": "ok" } ''' httpcode = 200 output = {} packagername = flask.request.args.get('packagername', None) or packagername if packagername: collections = pkgdblib.search_collection( SESSION, '*', status='Active', limit=10000) collections.extend(pkgdblib.search_collection( SESSION, '*', status='Under Development', limit=10000)) for collection in collections: packages_co = pkgdblib.get_package_maintained( SESSION, packager=packagername, poc=False, branch=collection.branchname ) packages = pkgdblib.get_package_maintained( SESSION, packager=packagername, poc=True, branch=collection.branchname ) output[collection.branchname] = { 'point of contact': len(packages), 'co-maintainer': len(packages_co) } output['output'] = 'ok' else: output = {'output': 'notok', 'error': 'Invalid request'} httpcode = 500 jsonout = flask.jsonify(output) jsonout.status_code = httpcode return jsonout