def edit_package(name): package = db.query(Package).filter_by(name=name).first_or_404() form = request.form try: for key, prev_val in form.items(): if key.startswith('group-prev-'): group = db.query(PackageGroup).get_or_404( int(key[len('group-prev-'):])) new_val = form.get('group-{}'.format(group.id)) if bool(new_val) != (prev_val == 'true'): if not group.editable: abort(403) if new_val: rel = PackageGroupRelation(package_name=package.name, group_id=group.id) db.add(rel) else: db.query(PackageGroupRelation)\ .filter_by(group_id=group.id, package_name=package.name)\ .delete(synchronize_session=False) if 'manual_priority' in form: new_priority = int(form['manual_priority']) package.manual_priority = new_priority if 'arch_override' in form: package.arch_override = form['arch_override'].strip() or None flash("Package modified") except (KeyError, ValueError): abort(400) db.commit() return redirect(url_for('package_detail', name=package.name))
def edit_package(name): package = db.query(Package).filter_by(name=name).first_or_404() form = request.form try: for key, prev_val in form.items(): if key.startswith('group-prev-'): group = db.query(PackageGroup).get_or_404(int(key[len('group-prev-'):])) new_val = form.get('group-{}'.format(group.id)) if bool(new_val) != (prev_val == 'true'): if not group.editable: abort(403) if new_val: rel = PackageGroupRelation(package_name=package.name, group_id=group.id) db.add(rel) else: db.query(PackageGroupRelation)\ .filter_by(group_id=group.id, package_name=package.name)\ .delete(synchronize_session=False) if 'manual_priority' in form: new_priority = int(form['manual_priority']) package.manual_priority = new_priority if 'arch_override' in form: package.arch_override = form['arch_override'].strip() or None flash("Package modified") except (KeyError, ValueError): abort(400) db.commit() return redirect(url_for('package_detail', name=package.name))
def process_group_form(group=None): if request.method == 'GET': if group: obj = dict(name=group.name, owners=[u.name for u in group.owners], packages=[p.name for p in group.packages]) form = GroupForm(**obj) else: form = GroupForm(owners=[g.user.name]) return render_template('edit-group.html', group=group, form=form) form = GroupForm() # check permissions if group and not group.editable: flash("You don't have permission to edit this group") return redirect( url_for('group_detail', name=group.name, namespace=group.namespace)) # check form validity if not form.validate_or_flash(): return render_template('edit-group.html', group=group, form=form) names = set(form.packages.data) users = [ get_or_create(db, User, name=name) for name in set(form.owners.data) ] db.commit() user_ids = [u.id for u in users] packages = db.query(Package).filter(Package.name.in_(names)) found_names = {p.name for p in packages} if len(found_names) != len(names): flash("Packages don't exist: " + ', '.join(names - found_names)) return render_template('edit-group.html', group=group, form=form) created = not group if created: group = PackageGroup(namespace=g.user.name) db.add(group) group.name = form.name.data try: db.flush() except IntegrityError: db.rollback() flash("Group already exists") return render_template('edit-group.html', group=group, form=form) if not created: db.query(PackageGroupRelation)\ .filter_by(group_id=group.id).delete() db.query(GroupACL)\ .filter_by(group_id=group.id).delete() rels = [dict(group_id=group.id, package_name=name) for name in found_names] acls = [dict(group_id=group.id, user_id=user_id) for user_id in user_ids] db.execute(PackageGroupRelation.__table__.insert(), rels) db.execute(GroupACL.__table__.insert(), acls) db.commit() flash("Group created" if created else "Group modified") return redirect( url_for('group_detail', name=group.name, namespace=group.namespace))
def get_global_notices(): notices = [n.content for n in db.query(AdminNotice.content).filter_by(key="global_notice")] if g.current_collection and g.current_collection.latest_repo_resolved is False: problems = db.query(BuildrootProblem)\ .filter_by(collection_id=g.current_collection.id).all() notices.append("Base buildroot for {} is not installable. " "Dependency problems:<br/>".format(g.current_collection) + '<br/>'.join((p.problem for p in problems))) notices = map(Markup, notices) return notices
def package_detail(name): collection = g.current_collection or g.default_collection packages = { p.collection_id: p for p in db.query(Package).filter_by(name=name) } package = None all_packages = [] for coll in g.collections: p = packages.get(coll.id) if p: all_packages.append((coll, p)) if coll is collection: package = p if not package: abort(404) package.global_groups = db.query(PackageGroup)\ .join(PackageGroupRelation)\ .filter(PackageGroupRelation.package_name == package.name)\ .filter(PackageGroup.namespace == None)\ .all() package.user_groups = [] package.available_groups = [] if g.user: user_groups = \ db.query(PackageGroup, func.bool_or(PackageGroupRelation.package_name == package.name))\ .outerjoin(PackageGroupRelation)\ .join(GroupACL)\ .filter(GroupACL.user_id == g.user.id)\ .order_by(PackageGroup.namespace.nullsfirst(), PackageGroup.name)\ .group_by(PackageGroup.id)\ .distinct().all() package.user_groups = [ group for group, checked in user_groups if checked and group.namespace ] package.available_groups = [ group for group, checked in user_groups if not checked ] page = db.query(Build)\ .filter_by(package_id=package.id)\ .options(subqueryload(Build.dependency_changes), subqueryload(Build.build_arch_tasks))\ .order_by(Build.id.desc())\ .paginate(builds_per_page) return render_template("package-detail.html", package=package, page=page, builds=page.items, all_packages=all_packages)
def process_group_form(group=None): if request.method == 'GET': if group: obj = dict(name=group.name, owners=[u.name for u in group.owners], packages=[p.name for p in group.packages]) form = GroupForm(**obj) else: form = GroupForm(owners=[g.user.name]) return render_template('edit-group.html', group=group, form=form) form = GroupForm() # check permissions if group and not group.editable: flash("You don't have permission to edit this group") return redirect(url_for('group_detail', name=group.name, namespace=group.namespace)) # check form validity if not form.validate_or_flash(): return render_template('edit-group.html', group=group, form=form) names = set(form.packages.data) users = [get_or_create(db, User, name=name) for name in set(form.owners.data)] db.commit() user_ids = [u.id for u in users] packages = db.query(Package).filter(Package.name.in_(names)) found_names = {p.name for p in packages} if len(found_names) != len(names): flash("Packages don't exist: " + ', '.join(names - found_names)) return render_template('edit-group.html', group=group, form=form) created = not group if created: group = PackageGroup(namespace=g.user.name) db.add(group) group.name = form.name.data try: db.flush() except IntegrityError: db.rollback() flash("Group already exists") return render_template('edit-group.html', group=group, form=form) if not created: db.query(PackageGroupRelation)\ .filter_by(group_id=group.id).delete() db.query(GroupACL)\ .filter_by(group_id=group.id).delete() rels = [dict(group_id=group.id, package_name=name) for name in found_names] acls = [dict(group_id=group.id, user_id=user_id) for user_id in user_ids] db.execute(PackageGroupRelation.__table__.insert(), rels) db.execute(GroupACL.__table__.insert(), acls) db.commit() flash("Group created" if created else "Group modified") return redirect(url_for('group_detail', name=group.name, namespace=group.namespace))
def get_global_notices(): notices = [ n.content for n in db.query(AdminNotice.content).filter_by(key="global_notice") ] if g.current_collection and g.current_collection.latest_repo_resolved is False: problems = db.query(BuildrootProblem)\ .filter_by(collection_id=g.current_collection.id).all() notices.append( "Base buildroot for {} is not installable. " "Dependency problems:<br/>".format(g.current_collection) + '<br/>'.join((p.problem for p in problems))) notices = map(Markup, notices) return notices
def collection_package_view(template, query_fn=None, **template_args): collection = g.current_collection or g.default_collection package_query = db.query(Package).filter(Package.collection_id == collection.id) if query_fn: package_query = query_fn(package_query) untracked = request.args.get('untracked') == '1' order_name = request.args.get('order_by', 'running,state,name') # pylint: disable=E1101 order_map = {'name': [Package.name], 'state': [Package.resolved, Reversed(Build.state)], 'running': [Package.last_complete_build_id == Package.last_build_id], 'task_id': [Build.task_id], 'started': [Build.started], 'current_priority': [NullsLastOrder(Package.current_priority)]} order_names, order = get_order(order_map, order_name) if not untracked: package_query = package_query.filter(Package.tracked == True) pkgs = package_query.filter(Package.blocked == False)\ .outerjoin(Package.last_build)\ .options(contains_eager(Package.last_build))\ .order_by(*order) page = pkgs.paginate(packages_per_page) populate_package_groups(page.items) return render_template(template, packages=page.items, page=page, order=order_names, collection=collection, **template_args)
def collection_package_view(template, query_fn=None, **template_args): collection = g.current_collection or g.default_collection package_query = db.query(Package).filter( Package.collection_id == collection.id) if query_fn: package_query = query_fn(package_query) untracked = request.args.get('untracked') == '1' order_name = request.args.get('order_by', 'running,state,name') # pylint: disable=E1101 order_map = { 'name': [Package.name], 'state': [Package.resolved, Reversed(Build.state)], 'running': [Package.last_complete_build_id == Package.last_build_id], 'task_id': [Build.task_id], 'started': [Build.started], 'current_priority': [NullsLastOrder(Package.current_priority)] } order_names, order = get_order(order_map, order_name) if not untracked: package_query = package_query.filter(Package.tracked == True) pkgs = package_query.filter(Package.blocked == False)\ .outerjoin(Package.last_build)\ .options(contains_eager(Package.last_build))\ .order_by(*order) page = pkgs.paginate(packages_per_page) populate_package_groups(page.items) return render_template(template, packages=page.items, page=page, order=order_names, collection=collection, **template_args)
def build_detail(build_id): # pylint: disable=E1101 build = db.query(Build)\ .options(joinedload(Build.package), subqueryload(Build.dependency_changes), subqueryload(Build.build_arch_tasks))\ .filter_by(id=build_id).first_or_404() return render_template("build-detail.html", build=build, cancel_form=EmptyForm())
def group_detail(name=None, namespace=None): group = db.query(PackageGroup)\ .filter_by(name=name, namespace=namespace).first_or_404() def query_fn(query): return query.outerjoin(PackageGroupRelation, PackageGroupRelation.package_name == Package.name)\ .filter(PackageGroupRelation.group_id == group.id) return package_view("group-detail.html", query_fn=query_fn, group=group)
def package_detail(name): collection = g.current_collection or g.default_collection packages = {p.collection_id: p for p in db.query(Package).filter_by(name=name)} package = None all_packages = [] for coll in g.collections: p = packages.get(coll.id) if p: all_packages.append((coll, p)) if coll is collection: package = p if not package: abort(404) package.global_groups = db.query(PackageGroup)\ .join(PackageGroupRelation)\ .filter(PackageGroupRelation.package_name == package.name)\ .filter(PackageGroup.namespace == None)\ .all() package.user_groups = [] package.available_groups = [] if g.user: user_groups = \ db.query(PackageGroup, func.bool_or(PackageGroupRelation.package_name == package.name))\ .outerjoin(PackageGroupRelation)\ .join(GroupACL)\ .filter(GroupACL.user_id == g.user.id)\ .order_by(PackageGroup.namespace.nullsfirst(), PackageGroup.name)\ .group_by(PackageGroup.id)\ .distinct().all() package.user_groups = [group for group, checked in user_groups if checked and group.namespace] package.available_groups = [group for group, checked in user_groups if not checked] page = db.query(Build)\ .filter_by(package_id=package.id)\ .options(subqueryload(Build.dependency_changes), subqueryload(Build.build_arch_tasks))\ .order_by(Build.id.desc())\ .paginate(builds_per_page) return render_template("package-detail.html", package=package, page=page, builds=page.items, all_packages=all_packages)
def add_packages(): form = AddPackagesForm() if request.method == 'POST': if not form.validate_or_flash(): return render_template("add-packages.html", form=form) names = set(form.packages.data) existing = db.query(Package).filter(Package.name.in_(names)).all() nonexistent = names - {p.name for p in existing} if nonexistent: flash("Packages don't exist: " + ','.join(nonexistent)) return render_template("add-packages.html", form=form) if form.collection.data == '_all': coll_ids = [c.id for c in g.collections] else: coll_ids = [ c.id for c in g.collections if c.name == form.collection.data ] if not coll_ids: abort(404) db.query(Package).filter(Package.name.in_(names))\ .filter(Package.collection_id.in_(coll_ids))\ .update({'tracked': True}) if form.group.data: name, _, namespace = reversed(form.group.data.partition('/')) group = db.query(PackageGroup)\ .filter_by(namespace=namespace or None, name=name)\ .first() or abort(400) if not group.editable: abort(400) rels = [ dict(group_id=group.id, package_name=name) for name in names ] if rels: db.execute(PackageGroupRelation.__table__.insert(), rels) added = ' '.join(names) log.info("%s added %s", g.user.name, added) flash("Packages added: {}".format(added)) db.commit() return redirect(request.form.get('next') or url_for('frontpage')) return render_template("add-packages.html", form=form)
def delete_group(name, namespace=None): group = db.query(PackageGroup)\ .options(joinedload(PackageGroup.packages))\ .filter_by(name=name, namespace=namespace).first_or_404() if request.method == 'POST': if EmptyForm().validate_or_flash() and group.editable: db.delete(group) db.commit() return redirect(url_for('groups_overview')) return render_template('edit-group.html', group=group) return redirect(url_for('groups_overview'))
def unified_package_view(template, query_fn=None, **template_args): untracked = request.args.get('untracked') == '1' order_name = request.args.get('order_by', 'running,failing,name') # pylint: disable=E1101 subq = db.query(Package.name, func.array_agg(func.row(Package.collection_id, Package.tracked, Package.resolved, Package.last_complete_build_state)) .label("states"), func.bool_or(Package.resolved).label("resolved"), func.bool_or(Package.last_complete_build_state == Build.FAILED) .label("failing"), func.bool_or(Package.last_complete_build_id != Package.last_build_id) .label("has_running_build"))\ .filter(Package.blocked == False)\ .group_by(Package.name) if not untracked: subq = subq.filter(Package.tracked == True) if query_fn: subq = query_fn(subq) subq = subq.subquery() order_map = { 'name': [subq.c.name], 'failing': [subq.c.resolved, Reversed(subq.c.failing)], 'running': [NullsLastOrder(subq.c.has_running_build)], } order_names, order = get_order(order_map, order_name) package_query = db.query(subq.c.name, subq.c.states, subq.c.has_running_build) page = package_query.order_by(*order).paginate(packages_per_page) page.items = map(UnifiedPackage, page.items) populate_package_groups(page.items) return render_template(template, packages=page.items, page=page, order=order_names, collection=None, **template_args)
def create_or_login(response): flask.session["openid"] = response.identity_url username = openid_to_username(response.identity_url) user = db.query(User).filter_by(name=username).first() if not user: user = User(name=username) db.add(user) user.email = response.email user.timezone = response.timezone db.commit() flask.g.user = user return flask.redirect(openid.get_next_url())
def cancel_build(build_id): if not g.user.admin: abort(403) build = db.query(Build).filter_by(id=build_id).first_or_404() if EmptyForm().validate_or_flash(): if build.state != Build.RUNNING: flash("Only running builds can be canceled.") elif build.cancel_requested: flash("Build already has pending cancelation request.") else: flash("Cancelation request sent.") build.cancel_requested = True db.commit() return redirect(url_for('package_detail', name=build.package.name))
def add_packages(): form = AddPackagesForm() if request.method == 'POST': if not form.validate_or_flash(): return render_template("add-packages.html", form=form) names = set(form.packages.data) existing = db.query(Package).filter(Package.name.in_(names)).all() nonexistent = names - {p.name for p in existing} if nonexistent: flash("Packages don't exist: " + ','.join(nonexistent)) return render_template("add-packages.html", form=form) if form.collection.data == '_all': coll_ids = [c.id for c in g.collections] else: coll_ids = [c.id for c in g.collections if c.name == form.collection.data] if not coll_ids: abort(404) db.query(Package).filter(Package.name.in_(names))\ .filter(Package.collection_id.in_(coll_ids))\ .update({'tracked': True}) if form.group.data: name, _, namespace = reversed(form.group.data.partition('/')) group = db.query(PackageGroup)\ .filter_by(namespace=namespace or None, name=name)\ .first() or abort(400) if not group.editable: abort(400) rels = [dict(group_id=group.id, package_name=name) for name in names] if rels: db.execute(PackageGroupRelation.__table__.insert(), rels) added = ' '.join(names) log.info("%s added %s", g.user.name, added) flash("Packages added: {}".format(added)) db.commit() return redirect(request.form.get('next') or url_for('frontpage')) return render_template("add-packages.html", form=form)
def get_collections(): collection_name = request.args.get('collection') g.collections = db.query(Collection)\ .order_by(Collection.order, Collection.name.desc())\ .all() if not g.collections: abort(500, "No collections setup") g.default_collection = g.collections[0] if collection_name: for collection in g.collections: if collection.name == collection_name: g.current_collection = collection break else: abort(404, "Collection not found") else: g.current_collection = None
def bugreport(name): package = db.query(Package)\ .filter(Package.name == name)\ .filter(Package.blocked == False)\ .filter(Package.last_complete_build_id != None)\ .options(joinedload(Package.last_complete_build))\ .first() or abort(404) variables = package.srpm_nvra or abort(404) variables['package'] = package variables['collection'] = package.collection variables['url'] = request.url_root + url_for('package_detail', name=package.name) template = get_config('bugreport.template') bug = {key: template[key].format(**variables) for key in template.keys()} bug['comment'] = dedent(bug['comment']).strip() query = urllib.urlencode(bug) bugreport_url = get_config('bugreport.url').format(query=query) return redirect(bugreport_url)
def populate_package_groups(packages): name_map = {} for package in packages: package.visible_groups = [] name_map[package.name] = package filter_expr = PackageGroup.namespace == None if g.user: filter_expr |= GroupACL.user_id == g.user.id query = db.query(PackageGroupRelation)\ .options(contains_eager(PackageGroupRelation.group))\ .filter(PackageGroupRelation.package_name.in_(name_map.keys()))\ .join(PackageGroup)\ .filter(filter_expr)\ .order_by(PackageGroup.namespace, PackageGroup.name) if g.user: query = query.outerjoin(GroupACL) for r in query: name_map[r.package_name].visible_groups.append(r.group)
def login(): if bypass_login: identity = "none" user_name = bypass_login else: identity = request.environ.get('REMOTE_USER') or abort(501) user_name = re.match(user_re, identity).group(1) user = db.query(m.User).filter_by(name=user_name).first() if not user: user = m.User(name=user_name, admin=bool(bypass_login)) db.add(user) db.commit() flash('New user "{}" was registered.'.format(user_name)) session['user'] = user_name flash('Logged in as user "{}" with identity "{}".' .format(user_name, identity)) if user.admin: flash('You have admin privileges.') next_url = request.values.get("next", url_for('frontpage')) return redirect(next_url)
def login(): if bypass_login: identity = "none" user_name = bypass_login else: identity = request.environ.get('REMOTE_USER') or abort(501) user_name = re.match(user_re, identity).group(1) user = db.query(m.User).filter_by(name=user_name).first() if not user: user = m.User(name=user_name, admin=bool(bypass_login)) db.add(user) db.commit() flash('New user "{}" was registered.'.format(user_name)) session['user'] = user_name flash('Logged in as user "{}" with identity "{}".'.format( user_name, identity)) if user.admin: flash('You have admin privileges.') next_url = request.values.get("next", url_for('frontpage')) return redirect(next_url)
def groups_overview(): groups = db.query(PackageGroup)\ .options(undefer(PackageGroup.package_count))\ .filter_by(namespace=None)\ .order_by(PackageGroup.name).all() return render_template("groups.html", groups=groups)
def edit_group(name, namespace=None): group = db.query(PackageGroup)\ .options(joinedload(PackageGroup.packages))\ .filter_by(name=name, namespace=namespace).first_or_404() return process_group_form(group=group)
def can_edit_group(group): return g.user and (g.user.admin or db.query(exists() .where((GroupACL.user_id == g.user.id) & (GroupACL.group_id == group.id))) .scalar())
def lookup_current_user(): g.user = None user_name = session.get('user', None) if user_name: g.user = db.query(m.User).filter_by(name=user_name).one()
def lookup_current_user(): flask.g.user = None if "openid" in flask.session: username = openid_to_username(flask.session["openid"]) flask.g.user = db.query(User).filter_by(name=username).first()
def can_edit_group(group): return g.user and (g.user.admin or db.query( exists().where((GroupACL.user_id == g.user.id) & (GroupACL.group_id == group.id))).scalar())