def package_orphan(package, collection): ''' Gives the possibility to orphan or take 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') for acl in package_acl: if acl.collection.branchname == collection: try: pkgdblib.update_pkg_poc( session=SESSION, pkg_name=package.name, pkg_branch=acl.collection.branchname, pkg_poc='orphan', user=flask.g.fas_user ) flask.flash( 'You are no longer point of contact on branch: %s' % collection) except pkgdblib.PkgdbException, err: flask.flash(str(err), 'error') SESSION.rollback() break
def package_retire(package, collection): ''' Gives the possibility to orphan or take 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') for acl in package_acl: if acl.collection.branchname == collection: if acl.point_of_contact == 'orphan': try: pkgdblib.update_pkg_status( session=SESSION, pkg_name=package.name, pkg_branch=acl.collection.branchname, status='Retired', user=flask.g.fas_user) flask.flash('This package has been retired on branch: %s' % collection) except pkgdblib.PkgdbException, err: flask.flash(str(err), 'error') SESSION.rollback() break else: flask.flash('This package has not been orphaned on ' 'branch: %s' % collection)
def package_request_branch(namespace, package, full=True): ''' Gives the possibility to request a new branch for this package. ''' if not bool(full) or str(full) in ['0', 'False']: full = False 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') branches = [ pkg.collection.branchname for pkg in package_acl if pkg.collection.status != 'EOL' ] collections = pkgdb2.lib.search_collection( SESSION, '*', 'Under Development') collections.extend(pkgdb2.lib.search_collection(SESSION, '*', 'Active')) # List the possible branches that this package does not already have. branches_possible = [ collec.branchname for collec in collections if collec.branchname not in branches] # Further limit that list to only the branches allowed for this namespace. namespace_policy = APP.config.get('PKGDB2_NAMESPACE_POLICY') policy = namespace_policy.get(pkg.package.namespace) if policy: branches_possible = [b for b in branches_possible if b in policy] form = pkgdb2.forms.BranchForm(collections=branches_possible) if form.validate_on_submit(): for branch in form.branches.data: try: msg = pkgdblib.add_new_branch_request( session=SESSION, namespace=package.namespace, pkg_name=package.name, clt_to=branch, user=flask.g.fas_user) SESSION.commit() flask.flash(msg) except pkgdblib.PkgdbException, err: # pragma: no cover flask.flash(str(err), 'error') SESSION.rollback() except SQLAlchemyError, err: # pragma: no cover APP.logger.exception(err) flask.flash( 'Could not save the request to the database for ' 'branch: %s' % branch, 'error') SESSION.rollback()
def package_orphan(package, collection): ''' Gives the possibility to orphan or take 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') for acl in package_acl: if acl.collection.branchname == collection: try: pkgdblib.update_pkg_poc(session=SESSION, pkg_name=package.name, pkg_branch=acl.collection.branchname, pkg_poc='orphan', user=flask.g.fas_user) flask.flash( 'You are no longer point of contact on branch: %s' % collection) except pkgdblib.PkgdbException, err: flask.flash(str(err), 'error') SESSION.rollback() break
def package_retire(package, full=True): ''' Gives the possibility to orphan or take a package. ''' if not bool(full) or str(full) in ['0', 'False']: full = False 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') if not is_pkgdb_admin(flask.g.fas_user): flask.flash( 'Only Admins are allowed to retire package here, ' 'you should use `fedpkg retire`.', 'errors') return flask.redirect( flask.url_for('.package_info', package=package.name)) collections = [ acl.collection.branchname for acl in package_acl if acl.collection.status in ['Active', 'Under Development'] and acl.status == 'Orphaned' ] form = pkgdb2.forms.BranchForm(collections=collections) if form.validate_on_submit(): for acl in package_acl: if acl.collection.branchname in form.branches.data: if acl.point_of_contact == 'orphan': try: pkgdblib.update_pkg_status( session=SESSION, pkg_name=package.name, pkg_branch=acl.collection.branchname, status='Retired', user=flask.g.fas_user) flask.flash( 'This package has been retired on branch: %s' % acl.collection.branchname) except pkgdblib.PkgdbException, err: # pragma: no cover # We should never hit this flask.flash(str(err), 'error') SESSION.rollback() APP.logger.exception(err) else: # pragma: no cover flask.flash('This package has not been orphaned on ' 'branch: %s' % acl.collection.branchname) try: SESSION.commit() # Keep it in, but normally we shouldn't hit this except pkgdblib.PkgdbException, err: # pragma: no cover # We should never hit this SESSION.rollback() APP.logger.exception(err) flask.flash(str(err), 'error')
def package_retire(package, collection): ''' Gives the possibility to orphan or take 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') for acl in package_acl: if acl.collection.branchname == collection: if acl.point_of_contact == 'orphan': try: pkgdblib.update_pkg_status( session=SESSION, pkg_name=package.name, pkg_branch=acl.collection.branchname, status='Retired', user=flask.g.fas_user ) flask.flash( 'This package has been retired on branch: %s' % collection) except pkgdblib.PkgdbException, err: flask.flash(str(err), 'error') SESSION.rollback() break else: flask.flash( 'This package has not been orphaned on ' 'branch: %s' % collection)
def package_orphan(namespace, package, full=True): ''' Gives the possibility to orphan or take a package. ''' if not bool(full) or str(full) in ['0', 'False']: full = False 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.branchname for acl in package_acl if acl.collection.status in ['Active', 'Under Development'] and acl.status == 'Approved' and ( is_pkgdb_admin(flask.g.fas_user) or acl.point_of_contact == flask.g.fas_user.username or ( acl.point_of_contact.startswith('group::') and is_pkg_admin( SESSION, flask.g.fas_user, namespace, package.name) ) ) ] form = pkgdb2.forms.BranchForm(collections=collections) if form.validate_on_submit(): for branch in form.branches.data: try: pkgdblib.update_pkg_poc( session=SESSION, namespace=namespace, pkg_name=package.name, pkg_branch=branch, pkg_poc='orphan', user=flask.g.fas_user ) flask.flash( 'You are no longer point of contact on branch: %s' % branch) except pkgdblib.PkgdbBugzillaException, err: # pragma: no cover APP.logger.exception(err) flask.flash(str(err), 'error') SESSION.rollback() except pkgdblib.PkgdbException, err: # pragma: no cover flask.flash(str(err), 'error') SESSION.rollback()
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 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 package_take(namespace, package, full=True): ''' Make someone Point of contact of an orphaned package. ''' if not bool(full) or str(full) in ['0', 'False']: full = False 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.branchname for acl in package_acl if acl.collection.status in ['Active', 'Under Development'] and acl.status == 'Orphaned' ] if not collections: flask.flash('No branches orphaned found', 'error') return flask.redirect(flask.url_for( '.package_info', namespace=package.namespace, package=package.name) ) form = pkgdb2.forms.BranchForm(collections=collections) if form.validate_on_submit(): for branch in form.branches.data: try: pkgdblib.unorphan_package( session=SESSION, namespace=package.namespace, pkg_name=package.name, pkg_branch=branch, pkg_user=flask.g.fas_user.username, user=flask.g.fas_user ) SESSION.commit() flask.flash('You have taken the package %s on branch %s' % ( package.name, branch)) except pkgdblib.PkgdbBugzillaException, err: # pragma: no cover APP.logger.exception(err) flask.flash(str(err), 'error') SESSION.rollback() except pkgdblib.PkgdbException, err: # pragma: no cover flask.flash(str(err), 'error') SESSION.rollback()
def package_unretire(package, full=True): ''' Asks an admin to unretire the package. ''' if not bool(full) or str(full) in ['0', 'False']: full = False 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.branchname for acl in package_acl if acl.collection.status in ['Active', 'Under Development'] and acl.status == 'Retired' ] form = pkgdb2.forms.BranchForm(collections=collections) if form.validate_on_submit(): for acl in package_acl: if acl.collection.branchname in form.branches.data: if acl.point_of_contact == 'orphan': try: pkgdblib.add_unretire_request( session=SESSION, pkg_name=package.name, pkg_branch=acl.collection.branchname, user=flask.g.fas_user, ) flask.flash( 'Admins have been asked to un-retire branch: %s' % acl.collection.branchname) except pkgdblib.PkgdbException, err: # pragma: no cover # We should never hit this flask.flash(str(err), 'error') SESSION.rollback() except SQLAlchemyError, err: SESSION.rollback() flask.flash( 'Could not save the request for branch: %s, has ' 'it already been requested?' % acl.collection.branchname, 'error') else: # pragma: no cover flask.flash( 'This package is not orphaned on branch: %s' % acl.collection.branchname)
def package_request_branch(namespace, package, full=True): ''' Gives the possibility to request a new branch for this package. ''' if not bool(full) or str(full) in ['0', 'False']: full = False 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') branches = [ pkg.collection.branchname for pkg in package_acl if pkg.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 collec.branchname not in branches ] form = pkgdb2.forms.BranchForm(collections=branches_possible) if form.validate_on_submit(): for branch in form.branches.data: try: msg = pkgdblib.add_new_branch_request( session=SESSION, namespace=package.namespace, pkg_name=package.name, clt_to=branch, user=flask.g.fas_user) SESSION.commit() flask.flash(msg) except pkgdblib.PkgdbException, err: # pragma: no cover flask.flash(str(err), 'error') SESSION.rollback() except SQLAlchemyError, err: # pragma: no cover APP.logger.exception(err) flask.flash( 'Could not save the request to the database for ' 'branch: %s' % branch, 'error') SESSION.rollback()
def package_take(namespace, package, full=True): ''' Make someone Point of contact of an orphaned package. ''' if not bool(full) or str(full) in ['0', 'False']: full = False 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.branchname for acl in package_acl if acl.collection.status in ['Active', 'Under Development'] and acl.status == 'Orphaned' ] if not collections: flask.flash('No branches orphaned found', 'error') return flask.redirect( flask.url_for('.package_info', namespace=package.namespace, package=package.name)) form = pkgdb2.forms.BranchForm(collections=collections) if form.validate_on_submit(): for branch in form.branches.data: try: pkgdblib.unorphan_package(session=SESSION, namespace=package.namespace, pkg_name=package.name, pkg_branch=branch, pkg_user=flask.g.fas_user.username, user=flask.g.fas_user) SESSION.commit() flask.flash('You have taken the package %s on branch %s' % (package.name, branch)) except pkgdblib.PkgdbBugzillaException, err: # pragma: no cover APP.logger.exception(err) flask.flash(str(err), 'error') SESSION.rollback() except pkgdblib.PkgdbException, err: # pragma: no cover flask.flash(str(err), 'error') SESSION.rollback()
def package_unretire(package, full=True): ''' Asks an admin to unretire the package. ''' if not bool(full) or str(full) in ['0', 'False']: full = False 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.branchname for acl in package_acl if acl.collection.status in ['Active', 'Under Development'] and acl.status == 'Retired' ] form = pkgdb2.forms.BranchForm(collections=collections) if form.validate_on_submit(): for acl in package_acl: if acl.collection.branchname in form.branches.data: if acl.point_of_contact == 'orphan': try: pkgdblib.add_unretire_request( session=SESSION, pkg_name=package.name, pkg_branch=acl.collection.branchname, user=flask.g.fas_user, ) flask.flash( 'Admins have been asked to un-retire branch: %s' % acl.collection.branchname) except pkgdblib.PkgdbException, err: # pragma: no cover # We should never hit this flask.flash(str(err), 'error') SESSION.rollback() except SQLAlchemyError, err: SESSION.rollback() flask.flash( 'Could not save the request for branch: %s, has ' 'it already been requested?' % acl.collection.branchname, 'error') else: # pragma: no cover flask.flash('This package is not orphaned on branch: %s' % acl.collection.branchname)
def package_orphan(namespace, package, full=True): ''' Gives the possibility to orphan or take a package. ''' if not bool(full) or str(full) in ['0', 'False']: full = False 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.branchname for acl in package_acl if acl.collection.status in ['Active', 'Under Development'] and acl.status == 'Approved' and ( is_pkgdb_admin(flask.g.fas_user) or acl.point_of_contact == flask.g.fas_user.username or (acl.point_of_contact.startswith('group::') and is_pkg_admin( SESSION, flask.g.fas_user, namespace, package.name))) ] form = pkgdb2.forms.BranchForm(collections=collections) if form.validate_on_submit(): for branch in form.branches.data: try: pkgdblib.update_pkg_poc(session=SESSION, namespace=namespace, pkg_name=package.name, pkg_branch=branch, pkg_poc='orphan', user=flask.g.fas_user) flask.flash( 'You are no longer point of contact on branch: %s' % branch) except pkgdblib.PkgdbBugzillaException, err: # pragma: no cover APP.logger.exception(err) flask.flash(str(err), 'error') SESSION.rollback() except pkgdblib.PkgdbException, err: # pragma: no cover flask.flash(str(err), 'error') SESSION.rollback()
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 test_api_package_unorphan(self, login_func, mock_func): """ Test the api_package_unorphan function. """ login_func.return_value = None # Redirect as you are not a packager user = FakeFasUser() user.groups = [] with user_set(pkgdb2.APP, user): output = self.app.post('/api/package/unorphan/') self.assertEqual(output.status_code, 302) user = FakeFasUser() with user_set(pkgdb2.APP, user): output = self.app.post('/api/package/unorphan/') self.assertEqual(output.status_code, 500) data = json.loads(output.data) self.assertEqual( data, { "error": "Invalid input submitted", "error_detail": [ "pkgnames: This field is required.", "branches: This field is required.", "poc: This field is required.", ], "output": "notok" } ) mock_func.get_packagers.return_value = ['test'] data = { 'pkgnames': 'guake', 'branches': ['f18', 'master'], 'poc': 'test', } with user_set(pkgdb2.APP, user): output = self.app.post('/api/package/unorphan/', data=data) self.assertEqual(output.status_code, 500) data = json.loads(output.data) self.assertEqual( data, { "error": "No package found by this name", "output": "notok" } ) create_package_acl(self.session) mock_func.log.return_value = '' # Unorphan a not-orphaned package data = { 'pkgnames': 'guake', 'branches': ['f18', 'master'], 'poc': 'test', } with user_set(pkgdb2.APP, user): output = self.app.post('/api/package/unorphan/', data=data) self.assertEqual(output.status_code, 500) data = json.loads(output.data) self.assertEqual( data, { "error": "Package \"guake\" is not orphaned on f18", "output": "notok" } ) # Orphan the package data = { 'pkgnames': 'guake', 'branches': ['f18', 'master'], 'poc': 'test', } with user_set(pkgdb2.APP, user): output = self.app.post('/api/package/orphan/', data=data) self.assertEqual(output.status_code, 200) data = json.loads(output.data) self.assertEqual( data, { "messages": ["", ""], "output": "ok" } ) pkg_acl = pkgdblib.get_acl_package(self.session, 'guake') self.assertEqual(pkg_acl[0].collection.branchname, 'f18') self.assertEqual(pkg_acl[0].package.name, 'guake') self.assertEqual(pkg_acl[0].point_of_contact, 'orphan') self.assertEqual(pkg_acl[0].status, 'Orphaned') self.assertEqual(pkg_acl[1].collection.branchname, 'master') self.assertEqual(pkg_acl[1].package.name, 'guake') self.assertEqual(pkg_acl[1].point_of_contact, 'orphan') self.assertEqual(pkg_acl[1].status, 'Orphaned') # Unorphan the package for someone else data = { 'pkgnames': 'guake', 'branches': ['f18', 'master'], 'poc': 'test', } with user_set(pkgdb2.APP, user): output = self.app.post('/api/package/unorphan/', data=data) self.assertEqual(output.status_code, 500) data = json.loads(output.data) self.assertEqual( data, { "error": "You are not allowed to update ACLs of someone " "else.", "output": "notok" } ) mock_func.get_packagers.return_value = ['pingou'] # Unorphan the package data = { 'pkgnames': 'guake', 'branches': ['f18', 'master'], 'poc': 'pingou', } with user_set(pkgdb2.APP, user): output = self.app.post('/api/package/unorphan/', data=data) self.assertEqual(output.status_code, 200) data = json.loads(output.data) self.assertEqual( data, { "messages": [ "Package guake has been unorphaned on f18 by pingou", "Package guake has been unorphaned on master by pingou" ], "output": "ok" } ) pkg_acl = pkgdblib.get_acl_package(self.session, 'guake') self.assertEqual(pkg_acl[0].collection.branchname, 'f18') self.assertEqual(pkg_acl[0].package.name, 'guake') self.assertEqual(pkg_acl[0].point_of_contact, 'pingou') self.assertEqual(pkg_acl[0].status, 'Approved') self.assertEqual(pkg_acl[1].collection.branchname, 'master') self.assertEqual(pkg_acl[1].package.name, 'guake') self.assertEqual(pkg_acl[1].point_of_contact, 'pingou') self.assertEqual(pkg_acl[1].status, 'Approved')
def test_api_package_orphan(self, login_func, mock_func): """ Test the api_package_orphan function. """ login_func.return_value = None # Redirect as you are not a packager user = FakeFasUser() user.groups = [] with user_set(pkgdb2.APP, user): output = self.app.post('/api/package/orphan/') self.assertEqual(output.status_code, 302) user = FakeFasUser() with user_set(pkgdb2.APP, user): output = self.app.post('/api/package/orphan/') self.assertEqual(output.status_code, 500) data = json.loads(output.data) self.assertEqual( data, { "error": "Invalid input submitted", "error_detail": [ "pkgnames: This field is required.", "branches: This field is required.", ], "output": "notok" } ) data = { 'pkgnames': 'guake', 'branches': ['f18', 'master'], 'poc': 'test', } with user_set(pkgdb2.APP, user): output = self.app.post('/api/package/orphan/', data=data) self.assertEqual(output.status_code, 500) data = json.loads(output.data) self.assertEqual( data, { "error": "No package found by this name", "output": "notok" } ) create_package_acl(self.session) mock_func.log.return_value = '' data = { 'pkgnames': 'guake', 'branches': ['f18', 'master'], 'poc': 'test', } with user_set(pkgdb2.APP, user): output = self.app.post('/api/package/orphan/', data=data) self.assertEqual(output.status_code, 200) data = json.loads(output.data) self.assertEqual( data, { "messages": ["", ""], "output": "ok" } ) pkg_acl = pkgdblib.get_acl_package(self.session, 'guake') self.assertEqual(pkg_acl[0].collection.branchname, 'f18') self.assertEqual(pkg_acl[0].package.name, 'guake') self.assertEqual(pkg_acl[0].point_of_contact, 'orphan') self.assertEqual(pkg_acl[0].status, 'Orphaned') self.assertEqual(pkg_acl[1].collection.branchname, 'master') self.assertEqual(pkg_acl[1].package.name, 'guake') self.assertEqual(pkg_acl[1].point_of_contact, 'orphan') self.assertEqual(pkg_acl[1].status, 'Orphaned')
def api_package_info(pkg_name=None): ''' Package information ------------------- Return information about a specific package. :: /api/package/<pkg_name>/ /api/package/?pattern=<pkg_name> Accept GET queries only :arg pkg_name: The name of the package to retrieve the information of. :kwarg pkg_clt: Restricts the package information to a specific collection (branch). Sample response: :: { "output": "ok", "packages": [ { "status": "Approved", "point_of_contact": "pingou", "package": { "status": "Approved", "upstream_url": null, "description": "Guake is a drop-down terminal for Gnome " "Desktop Environment, so you just need to " "press a key to invoke him,and press again " "to hide." "summary": "Drop-down terminal for GNOME", "creation_date": 1385365548.0, "review_url": null, "name": "guake" }, "collection": { "status": "Under Development", "branchname": "devel", "version": "devel", "name": "Fedora" }, "acls": [ { "status": "Approved", "fas_name": "pingou", "acl": "watchcommits" }, { "status": "Approved", "fas_name": "pingou", "acl": "watchbugzilla" }, { "status": "Approved", "fas_name": "pingou", "acl": "commit" }, { "status": "Approved", "fas_name": "pingou", "acl": "approveacls" }, { "status": "Obsolete", "fas_name": "maxamillion", "acl": "watchcommits" }, { "status": "Obsolete", "fas_name": "maxamillion", "acl": "watchbugzilla" } ], "status_change": 1385366044.0 }, ... ] } ''' httpcode = 200 output = {} pkg_name = flask.request.args.get('pkg_name', pkg_name) pkg_clt = flask.request.args.get('pkg_clt', None) try: packages = pkgdblib.get_acl_package( SESSION, pkg_name=pkg_name, pkg_clt=pkg_clt ) output['output'] = 'ok' output['packages'] = [pkg.to_json() for pkg in packages] except NoResultFound: output['output'] = 'notok' output['error'] = 'Package: %s not found' % pkg_name httpcode = 404 except pkgdblib.PkgdbException, err: SESSION.rollback() output['output'] = 'notok' output['error'] = str(err) httpcode = 500
def api_package_info(pkg_name=None): ''' Package information ------------------- Return information about a specific package. :: /api/package/<pkg_name>/ /api/package/?pattern=<pkg_name> Accept GET queries only :arg pkg_name: The name of the package to retrieve the information of. :kwarg pkg_clt: Restricts the package information to a specific collection (branch). Sample response: :: { "output": "ok", "packages": [ { "status": "Approved", "point_of_contact": "pingou", "package": { "status": "Approved", "upstream_url": null, "description": "Guake is a drop-down terminal for Gnome " "Desktop Environment, so you just need to " "press a key to invoke him,and press again " "to hide." "summary": "Drop-down terminal for GNOME", "creation_date": 1385365548.0, "review_url": null, "name": "guake" }, "collection": { "status": "Under Development", "branchname": "devel", "version": "devel", "name": "Fedora" }, "acls": [ { "status": "Approved", "fas_name": "pingou", "acl": "watchcommits" }, { "status": "Approved", "fas_name": "pingou", "acl": "watchbugzilla" }, { "status": "Approved", "fas_name": "pingou", "acl": "commit" }, { "status": "Approved", "fas_name": "pingou", "acl": "approveacls" }, { "status": "Obsolete", "fas_name": "maxamillion", "acl": "watchcommits" }, { "status": "Obsolete", "fas_name": "maxamillion", "acl": "watchbugzilla" } ], "status_change": 1385366044.0 }, ... ] } ''' httpcode = 200 output = {} pkg_name = flask.request.args.get('pkg_name', pkg_name) pkg_clt = flask.request.args.get('pkg_clt', None) try: packages = pkgdblib.get_acl_package(SESSION, pkg_name=pkg_name, pkg_clt=pkg_clt) output['output'] = 'ok' output['packages'] = [pkg.to_json() for pkg in packages] except NoResultFound: output['output'] = 'notok' output['error'] = 'Package: %s not found' % pkg_name httpcode = 404 except pkgdblib.PkgdbException, err: SESSION.rollback() output['output'] = 'notok' output['error'] = str(err) httpcode = 500
def api_package_info(pkgname=None): ''' Package information ------------------- Return information about a specific package. :: /api/package/<pkg_name>/ /api/package/?pkgname=<pkg_name> Accepts GET queries only :arg pkgname: The name of the package to retrieve the information of. :kwarg branches: Restricts the package information to one or more collection (branches). :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 acls: a boolean to specify whether to include the ACLs in the results. Defaults to True. If True, it will include the ACL of the package in the collection. If False, it will not include the ACL of the package in the collection. Sample response: :: { "output": "ok", "packages": [ { "status": "Approved", "point_of_contact": "pingou", "critpath": False, "package": { "status": "Approved", "upstream_url": null, "description": "Guake is a drop-down terminal for Gnome " "Desktop Environment, so you just need to " "press a key to invoke him,and press again " "to hide." "summary": "Drop-down terminal for GNOME", "creation_date": 1385365548.0, "review_url": null, "name": "guake" }, "collection": { "status": "Under Development", "branchname": "master", "version": "devel", "name": "Fedora" }, "acls": [ { "status": "Approved", "fas_name": "pingou", "acl": "watchcommits" }, { "status": "Approved", "fas_name": "pingou", "acl": "watchbugzilla" }, { "status": "Approved", "fas_name": "pingou", "acl": "commit" }, { "status": "Approved", "fas_name": "pingou", "acl": "approveacls" }, { "status": "Obsolete", "fas_name": "maxamillion", "acl": "watchcommits" }, { "status": "Obsolete", "fas_name": "maxamillion", "acl": "watchbugzilla" }, { "acl": "commit", "fas_name": "group::provenpackager", "status": "Approved" } ], "status_change": 1385366044.0 }, ... ] } ''' httpcode = 200 output = {} pkg_name = flask.request.args.get('pkgname', pkgname) branches = flask.request.args.getlist('branches', None) eol = flask.request.args.get('eol', False) acls = flask.request.args.get('acls', True) if str(acls).lower() in ['0', 'false']: acls = False try: packages = pkgdblib.get_acl_package( SESSION, pkg_name=pkg_name, pkg_clt=branches, eol=eol, ) if not packages: output['output'] = 'notok' output['error'] = 'No package found on these branches: %s' \ % ', '.join(branches) httpcode = 404 else: output['output'] = 'ok' output['packages'] = [ pkg.to_json(not_provenpackager=APP.config.get( 'PKGS_NOT_PROVENPACKAGER'), acls=acls) for pkg in packages ] except NoResultFound: output['output'] = 'notok' output['error'] = 'Package: %s not found' % pkg_name httpcode = 404 jsonout = flask.jsonify(output) jsonout.status_code = httpcode return jsonout
def package_give(namespace, package, full=True): ''' Gives the PoC of a package to someone else. ''' if not bool(full) or str(full) in ['0', 'False']: full = False 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') # Restrict the branch to the one current user is PoC of (unless admin # or group) collect_name = [] for acl in package_acl: if acl.point_of_contact != flask.g.fas_user.username and \ not is_pkgdb_admin(flask.g.fas_user) and \ not acl.point_of_contact.startswith('group::'): pass else: if acl.point_of_contact.startswith('group::'): group = acl.point_of_contact.split('group::')[0] if group not in flask.g.fas_user.groups: pass elif acl.collection.status != 'EOL': collect_name.append(acl.collection.branchname) form = pkgdb2.forms.GivePoCForm(collections=collect_name) acls = ['commit', 'watchbugzilla', 'watchcommits', 'approveacls'] if form.validate_on_submit(): collections = form.branches.data pkg_poc = form.poc.data if pkg_poc.startswith('group::'): acls = ['commit', 'watchbugzilla', 'watchcommits'] try: for pkg_collection in collections: message = pkgdblib.update_pkg_poc( SESSION, namespace=namespace, pkg_name=packagename, pkg_branch=pkg_collection, pkg_poc=pkg_poc, user=flask.g.fas_user, ) flask.flash(message) for acl in acls: pkgdblib.set_acl_package( SESSION, namespace=namespace, pkg_name=packagename, pkg_branch=pkg_collection, pkg_user=pkg_poc, acl=acl, status='Approved', user=flask.g.fas_user ) SESSION.commit() except pkgdblib.exceptions.PkgdbBugzillaException as err: # pragma: no cover APP.logger.exception(err) flask.flash(str(err), 'error') SESSION.rollback() except PkgdbException as err: SESSION.rollback() flask.flash(str(err), 'error') return flask.redirect(flask.url_for( '.package_info', namespace=namespace, package=packagename) ) return flask.render_template( 'package_give.html', full=full, form=form, packagename=packagename, namespace=namespace, )
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 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, )
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') package_acls = [] branch_admin = [] is_poc = False for pkg in package_acl: if pkg.collection.status == 'EOL': # pragma: no cover continue tmp = {} tmp['collection'] = '%s %s' % (pkg.collection.name, pkg.collection.version) tmp['branchname'] = pkg.collection.branchname tmp['point_of_contact'] = pkg.point_of_contact tmp['status'] = pkg.status if hasattr(flask.g, 'fas_user') and flask.g.fas_user and \ pkg.point_of_contact == flask.g.fas_user.username: is_poc = True acls = {} for acl in pkg.acls: tmp2 = {'acl': acl.acl, 'status': acl.status} if acl.fas_name in acls: acls[acl.fas_name].append(tmp2) else: acls[acl.fas_name] = [tmp2] ## This list is a little hacky, but we would have to save ACLs ## in their own table otherwise. planned_acls = set( ['approveacls', 'commit', 'watchbugzilla', 'watchcommits']) for fas_name in acls: seen_acls = set([acl['acl'] for acl in acls[fas_name]]) for aclname in planned_acls - seen_acls: acls[fas_name].append({'acl': aclname, 'status': ''}) tmp['acls'] = acls package_acls.append(tmp) if is_pkg_admin(SESSION, flask.g.fas_user, package.name, pkg.collection.branchname): branch_admin.append(pkg.collection.branchname) package_acls.reverse() if package_acls: package_acls.insert(0, package_acls.pop()) return flask.render_template( 'package.html', package=package, package_acl=package_acls, branch_admin=branch_admin, is_poc=is_poc, )
def package_unretire(namespace, package, full=True): ''' Asks an admin to unretire the package. ''' if not bool(full) or str(full) in ['0', 'False']: full = False 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') # Get the list of retired branches retire_collections = [ acl.collection.branchname for acl in package_acl if acl.collection.status in ['Active', 'Under Development'] and acl.status == 'Retired' ] # Get the list of all the collections active or under development collections = [ collection.branchname for collection in pkgdb2.lib.search_collection( SESSION, '*', 'Under Development') if collection.branchname in retire_collections ] collections.reverse() active_collections = pkgdb2.lib.search_collection(SESSION, '*', 'Active') active_collections.reverse() cnt = 0 # Restrict the Fedora branch to 2 active versions for collection in active_collections: if collection.name.lower() == 'fedora': if cnt >= 2: continue cnt += 1 if collection.branchname not in retire_collections: continue collections.append(collection.branchname) form = pkgdb2.forms.UnretireForm(collections=collections) if form.validate_on_submit(): review_url = form.review_url.data review_url = review_url.strip() if review_url else None checks_ok = True for br in form.branches.data: if br == 'master' and not review_url: checks_ok = False flask.flash( 'You must provide a review URL to un-retire master', 'error') break elif br.startswith( 'e') and 'master' in collections and not review_url: checks_ok = False flask.flash( 'You must provide a review URL to un-retire an EPEL ' 'branch if master is also retired', 'error') break if not checks_ok: return flask.redirect( flask.url_for('.package_info', namespace=package.namespace, package=package.name)) for acl in package_acl: if acl.collection.branchname in form.branches.data: if acl.point_of_contact == 'orphan': try: pkgdblib.add_unretire_request( session=SESSION, namespace=namespace, pkg_name=package.name, pkg_branch=acl.collection.branchname, review_url=form.review_url.data, user=flask.g.fas_user, ) flask.flash( 'Admins have been asked to un-retire branch: %s' % acl.collection.branchname) except pkgdblib.PkgdbException, err: # pragma: no cover # We should never hit this flask.flash(str(err), 'error') SESSION.rollback() except SQLAlchemyError, err: SESSION.rollback() flask.flash( 'Could not save the request for branch: %s, has ' 'it already been requested?' % acl.collection.branchname, 'error') else: # pragma: no cover flask.flash('This package is not orphaned on branch: %s' % acl.collection.branchname)
def package_give(package, full=True): ''' Gives the PoC of a package to someone else. ''' if not bool(full) or str(full) in ['0', 'False']: full = False 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') # Restrict the branch to the one current user is PoC of (unless admin # or group) collect_name = [] for acl in package_acl: if acl.point_of_contact != flask.g.fas_user.username and \ not is_pkgdb_admin(flask.g.fas_user) and \ not acl.point_of_contact.startswith('group::'): pass else: if acl.point_of_contact.startswith('group::'): group = acl.point_of_contact.split('group::')[0] if group not in flask.g.fas_user.groups: pass elif acl.collection.status != 'EOL': collect_name.append(acl.collection.branchname) form = pkgdb2.forms.GivePoCForm(collections=collect_name) acls = ['commit', 'watchbugzilla', 'watchcommits', 'approveacls'] if form.validate_on_submit(): collections = form.branches.data pkg_poc = form.poc.data if pkg_poc.startswith('group::'): acls = ['commit', 'watchbugzilla', 'watchcommits'] try: for pkg_collection in collections: message = pkgdblib.update_pkg_poc( SESSION, pkg_name=packagename, pkg_branch=pkg_collection, pkg_poc=pkg_poc, user=flask.g.fas_user, ) flask.flash(message) for acl in acls: pkgdblib.set_acl_package(SESSION, pkg_name=packagename, pkg_branch=pkg_collection, pkg_user=pkg_poc, acl=acl, status='Approved', user=flask.g.fas_user) SESSION.commit() except pkgdblib.PkgdbBugzillaException, err: # pragma: no cover APP.logger.exception(err) flask.flash(str(err), 'error') SESSION.rollback() except pkgdblib.PkgdbException, err: SESSION.rollback() flask.flash(str(err), 'error')
def package_retire(namespace, package, full=True): ''' Gives the possibility to orphan or take a package. ''' if not bool(full) or str(full) in ['0', 'False']: full = False 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') if not is_pkgdb_admin(flask.g.fas_user): flask.flash( 'Only Admins are allowed to retire package here, ' 'you should use `fedpkg retire`.', 'errors') return flask.redirect(flask.url_for( '.package_info', namespace=package.namespace, package=package.name) ) collections = [ acl.collection.branchname for acl in package_acl if acl.collection.status in ['Active', 'Under Development'] and acl.status == 'Orphaned' ] form = pkgdb2.forms.BranchForm(collections=collections) if form.validate_on_submit(): for acl in package_acl: if acl.collection.branchname in form.branches.data: if acl.point_of_contact == 'orphan': try: pkgdblib.update_pkg_status( session=SESSION, namespace=namespace, pkg_name=package.name, pkg_branch=acl.collection.branchname, status='Retired', user=flask.g.fas_user ) flask.flash( 'This package has been retired on branch: %s' % acl.collection.branchname) except PkgdbException as err: # pragma: no cover # We should never hit this flask.flash(str(err), 'error') SESSION.rollback() APP.logger.exception(err) else: # pragma: no cover flask.flash( 'This package has not been orphaned on ' 'branch: %s' % acl.collection.branchname) try: SESSION.commit() # Keep it in, but normally we shouldn't hit this except PkgdbException as err: # pragma: no cover # We should never hit this SESSION.rollback() APP.logger.exception(err) flask.flash(str(err), 'error') return flask.redirect(flask.url_for( '.package_info', namespace=package.namespace, package=package.name) ) return flask.render_template( 'branch_selection.html', full=full, package=package, form=form, action='retire', )
def package_request_branch(namespace, package, full=True): ''' Gives the possibility to request a new branch for this package. ''' if not bool(full) or str(full) in ['0', 'False']: full = False 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') branches = [ pkg.collection.branchname for pkg in package_acl if pkg.collection.status != 'EOL' ] collections = pkgdb2.lib.search_collection(SESSION, '*', 'Under Development') collections.extend(pkgdb2.lib.search_collection(SESSION, '*', 'Active')) # List the possible branches that this package does not already have. branches_possible = [ collec.branchname for collec in collections if collec.branchname not in branches ] # Further limit that list to only the branches allowed for this namespace. namespace_policy = APP.config.get('PKGDB2_NAMESPACE_POLICY') policy = namespace_policy.get(pkg.package.namespace) if policy: branches_possible = [b for b in branches_possible if b in policy] form = pkgdb2.forms.BranchForm(collections=branches_possible) if form.validate_on_submit(): for branch in form.branches.data: try: msg = pkgdblib.add_new_branch_request( session=SESSION, namespace=package.namespace, pkg_name=package.name, clt_to=branch, user=flask.g.fas_user) SESSION.commit() flask.flash(msg) except PkgdbException as err: # pragma: no cover flask.flash(str(err), 'error') SESSION.rollback() except SQLAlchemyError as err: # pragma: no cover APP.logger.exception(err) flask.flash( 'Could not save the request to the database for ' 'branch: %s' % branch, 'error') SESSION.rollback() return flask.redirect( flask.url_for('.package_info', namespace=package.namespace, package=package.name)) return flask.render_template( 'request_branch.html', full=full, package=package, form=form, action='request_branch', )
def package_unretire(namespace, package, full=True): ''' Asks an admin to unretire the package. ''' if not bool(full) or str(full) in ['0', 'False']: full = False 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') # Get the list of retired branches retire_collections = [ acl.collection.branchname for acl in package_acl if acl.collection.status in ['Active', 'Under Development'] and acl.status == 'Retired' ] # Get the list of all the collections active or under development collections = [ collection.branchname for collection in pkgdb2.lib.search_collection(SESSION, '*', 'Under Development') if collection.branchname in retire_collections ] collections.reverse() active_collections = pkgdb2.lib.search_collection(SESSION, '*', 'Active') active_collections.reverse() cnt = 0 # Restrict the Fedora branch to 2 active versions for collection in active_collections: if collection.name.lower() == 'fedora': if cnt >= 2: continue cnt += 1 if collection.branchname not in retire_collections: continue collections.append(collection.branchname) form = pkgdb2.forms.UnretireForm(collections=collections) if form.validate_on_submit(): review_url = form.review_url.data review_url = review_url.strip() if review_url else None checks_ok = True # Check the review URL bz = APP.config.get('PKGDB2_BUGZILLA_URL') review_url = pkgdblib.check_bz_url(bz, review_url) for br in form.branches.data: if br.startswith('e') \ and 'master' in collections \ and not review_url: checks_ok = False flask.flash( 'You must provide a valid review URL to un-retire an ' 'EPEL branch if master is also retired', 'error') break if not checks_ok: return flask.redirect(flask.url_for( '.package_info', namespace=package.namespace, package=package.name) ) for acl in package_acl: if acl.collection.branchname in form.branches.data: if acl.point_of_contact == 'orphan': try: pkgdblib.add_unretire_request( session=SESSION, namespace=namespace, pkg_name=package.name, pkg_branch=acl.collection.branchname, review_url=review_url, user=flask.g.fas_user, ) flask.flash( 'Admins have been asked to un-retire branch: %s' % acl.collection.branchname) except PkgdbException as err: # pragma: no cover # We should never hit this flask.flash(str(err), 'error') SESSION.rollback() except SQLAlchemyError as err: APP.logger.exception(err) SESSION.rollback() flask.flash( 'Could not save the request for branch: %s, has ' 'it already been requested?' % acl.collection.branchname, 'error') else: # pragma: no cover flask.flash( 'This package is not orphaned on branch: %s' % acl.collection.branchname) try: SESSION.commit() # Keep it in, but normally we shouldn't hit this except PkgdbException as err: # pragma: no cover # We should never hit this SESSION.rollback() APP.logger.exception(err) flask.flash(str(err), 'error') return flask.redirect(flask.url_for( '.package_info', namespace=package.namespace, package=package.name) ) return flask.render_template( 'request_unretire.html', full=full, package=package, form=form, action='unretire', )
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 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_package_info(pkgname=None): ''' Package information ------------------- Return information about a specific package. :: /api/package/<pkg_name>/ /api/package/?pkgname=<pkg_name> Accept GET queries only :arg pkgname: The name of the package to retrieve the information of. :kwarg branches: Restricts the package information to one or more collection (branches). :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 acls: a boolean to specify whether to include the ACLs in the results. Defaults to True. If True, it will include the ACL of the package in the collection. If False, it will not include the ACL of the package in the collection. Sample response: :: { "output": "ok", "packages": [ { "status": "Approved", "point_of_contact": "pingou", "critpath": False, "package": { "status": "Approved", "upstream_url": null, "description": "Guake is a drop-down terminal for Gnome " "Desktop Environment, so you just need to " "press a key to invoke him,and press again " "to hide." "summary": "Drop-down terminal for GNOME", "creation_date": 1385365548.0, "review_url": null, "name": "guake" }, "collection": { "status": "Under Development", "branchname": "master", "version": "devel", "name": "Fedora" }, "acls": [ { "status": "Approved", "fas_name": "pingou", "acl": "watchcommits" }, { "status": "Approved", "fas_name": "pingou", "acl": "watchbugzilla" }, { "status": "Approved", "fas_name": "pingou", "acl": "commit" }, { "status": "Approved", "fas_name": "pingou", "acl": "approveacls" }, { "status": "Obsolete", "fas_name": "maxamillion", "acl": "watchcommits" }, { "status": "Obsolete", "fas_name": "maxamillion", "acl": "watchbugzilla" }, { "acl": "commit", "fas_name": "group::provenpackager", "status": "Approved" } ], "status_change": 1385366044.0 }, ... ] } ''' httpcode = 200 output = {} pkg_name = flask.request.args.get('pkgname', pkgname) branches = flask.request.args.getlist('branches', None) eol = flask.request.args.get('eol', False) acls = flask.request.args.get('acls', True) if str(acls).lower() in ['0', 'false']: acls = False try: packages = pkgdblib.get_acl_package( SESSION, pkg_name=pkg_name, pkg_clt=branches, eol=eol, ) if not packages: output['output'] = 'notok' output['error'] = 'No package found on these branches: %s' \ % ', '.join(branches) httpcode = 404 else: output['output'] = 'ok' output['packages'] = [ pkg.to_json(not_provenpackager=APP.config.get( 'PKGS_NOT_PROVENPACKAGER'), acls=acls) for pkg in packages] except NoResultFound: output['output'] = 'notok' output['error'] = 'Package: %s not found' % pkg_name httpcode = 404 jsonout = flask.jsonify(output) jsonout.status_code = httpcode return jsonout
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') package_acls = [] branch_admin = [] is_poc = False for pkg in package_acl: if pkg.collection.status == 'EOL': # pragma: no cover continue tmp = {} tmp['collection'] = '%s %s' % (pkg.collection.name, pkg.collection.version) tmp['branchname'] = pkg.collection.branchname tmp['point_of_contact'] = pkg.point_of_contact tmp['status'] = pkg.status if hasattr(flask.g, 'fas_user') and flask.g.fas_user and \ pkg.point_of_contact == flask.g.fas_user.username: is_poc = True acls = {} for acl in pkg.acls: tmp2 = {'acl': acl.acl, 'status': acl.status} if acl.fas_name in acls: acls[acl.fas_name].append(tmp2) else: acls[acl.fas_name] = [tmp2] ## This list is a little hacky, but we would have to save ACLs ## in their own table otherwise. planned_acls = set(['approveacls', 'commit', 'watchbugzilla', 'watchcommits']) for fas_name in acls: seen_acls = set([acl['acl'] for acl in acls[fas_name]]) for aclname in planned_acls - seen_acls: acls[fas_name].append({'acl': aclname, 'status': ''}) tmp['acls'] = acls package_acls.append(tmp) if is_pkg_admin(SESSION, flask.g.fas_user, package.name, pkg.collection.branchname): branch_admin.append(pkg.collection.branchname) package_acls.reverse() if package_acls: package_acls.insert(0, package_acls.pop()) return flask.render_template( 'package.html', package=package, package_acl=package_acls, branch_admin=branch_admin, is_poc=is_poc, )