def login(): """ Acknowledge the logged in user by adding it's name to session. The login itself must have had already happened in httpd. Adds the user to the database on first login. """ if bypass_login: identity = "none" user_name = bypass_login else: identity = request.environ.get(user_env) 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_info('New user "{}" was registered.'.format(user_name)) session['user'] = user_name flash_ack('Logged in as user "{}" with identity "{}".' .format(user_name, identity)) if user.admin: flash_info('You have admin privileges.') next_url = request.values.get("next", url_for('frontpage')) return redirect(next_url)
def new_rebuild_request(): if get_config('copr.require_admin') and not g.user.admin: abort(403) form = RebuildRequestForm() if form.validate_or_flash(): collection = g.collections_by_name.get(form.collection.data) if not collection: abort(404, "Collection not found") repo_source = form.copr_name.data if '/' not in repo_source: repo_source = g.user.name + '/' + repo_source repo_source = 'copr:' + repo_source rebuild_request = CoprRebuildRequest( collection_id=collection.id, user_id=g.user.id, repo_source=repo_source, description=form.description.data or None, schedule_count=form.schedule_count.data, ) db.add(rebuild_request) db.commit() flash_ack('Rebuild request created') return redirect( url_for('rebuild_request_detail', request_id=rebuild_request.id)) return redirect(url_for('list_rebuild_requests', username=g.user.name))
def edit_rebuild(): form = EditRebuildForm() if not form.validate_on_submit(): abort(400) rebuild = db.query(CoprRebuild)\ .filter_by(request_id=form.request_id.data, package_id=form.package_id.data)\ .first_or_404() if not rebuild.request.editable: abort(403) if form.action.data == 'move-top': db.query(CoprRebuild)\ .filter(CoprRebuild.request_id == rebuild.request_id)\ .filter(CoprRebuild.state == None)\ .filter(CoprRebuild.order < rebuild.order)\ .update({'order': CoprRebuild.order + 1}) rebuild.order = db.query(func.min(CoprRebuild.order) - 1)\ .filter(CoprRebuild.request_id == rebuild.request_id)\ .filter(CoprRebuild.state == None)\ .scalar() # Moving to top should ensure the package will be scheduled rebuild.request.schedule_count += 1 rebuild.request.state = 'in progress' elif form.action.data == 'remove': db.query(CoprRebuild)\ .filter(CoprRebuild.request_id == rebuild.request_id)\ .filter(CoprRebuild.order > rebuild.order)\ .update({'order': CoprRebuild.order - 1}) db.delete(rebuild) db.commit() return redirect( url_for('rebuild_request_detail', request_id=rebuild.request_id))
def process_group_form(group=None): """ Validate and process submitted group form. :param group: :return: """ if request.method == 'GET': # construct new form if group: # edit form obj = dict(name=group.name, owners=[u.name for u in group.owners], packages=[p.name for p in group.packages]) form = forms.GroupForm(**obj) else: # creation form form = forms.GroupForm(owners=[g.user.name]) return render_template('edit-group.html', group=group, form=form) form = forms.GroupForm() # check permissions if group and not group.editable: flash_nak("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) # existing group being edited or None - to be sent into template existing_group = group if not group: group = PackageGroup(namespace=g.user.name) db.add(group) group.name = form.name.data try: db.flush() except IntegrityError: db.rollback() flash_nak("Group already exists") return render_template('edit-group.html', group=existing_group, form=form) try: data.set_group_content(session, group, form.packages.data) data.set_group_maintainers(session, group, form.owners.data) except data.PackagesDontExist as e: db.rollback() flash_nak(str(e)) return render_template('edit-group.html', group=existing_group, form=form) db.commit() flash_ack("Group created" if not existing_group else "Group modified") return redirect( url_for('group_detail', name=group.name, namespace=group.namespace))
def edit_package(name): """ Edit package attributes or groups. Everyone can edit attributes, group membership requires permissions. """ form = forms.EditPackageForm() collection = g.collections_by_id.get(form.collection_id.data) or abort(400) if not form.validate_or_flash(): return package_detail(name=name, form=form, collection=collection) package = db.query(Package)\ .filter_by(name=name, collection_id=collection.id)\ .first_or_404() # Interpret group checkboxes for key, prev_val in request.form.items(): if key.startswith('group-prev-'): group = db.query(PackageGroup).get_or_404(int(key[len('group-prev-'):])) new_val = request.form.get('group-{}'.format(group.id)) if bool(new_val) != (prev_val == 'true'): if not group.editable: abort(403) if new_val: data.set_group_content(session, group, [package.name], append=True) else: data.set_group_content(session, group, [package.name], delete=True) # Using set_package_attribute to generate audit log events if form.tracked.data is not None: data.set_package_attribute( session, package, 'tracked', form.tracked.data, ) if form.manual_priority.data is not None: data.set_package_attribute( session, package, 'manual_priority', form.manual_priority.data, ) if form.arch_override.data is not None: data.set_package_attribute( session, package, 'arch_override', ' '.join(form.arch_override.data) or None, ) if form.skip_resolution.data is not None: data.set_package_attribute( session, package, 'skip_resolution', form.skip_resolution.data, ) if package.skip_resolution: package.resolved = None db.query(UnappliedChange).filter_by(package_id=package.id).delete() flash_ack("Package modified") db.commit() return redirect(url_for('package_detail', name=package.name) + "?collection=" + collection.name)
def delete_group(name, namespace=None): group = db.query(PackageGroup)\ .options(joinedload(PackageGroup.packages))\ .filter_by(name=name, namespace=namespace).first_or_404() # Validate CSRF and permissions if not forms.EmptyForm().validate_or_flash() or not group.editable: abort(401) data.delete_group(session, group) db.commit() flash_ack("Group was deleted") return redirect(url_for('groups_overview'))
def process_group_form(group=None): """ Validate and process submitted group form. :param group: :return: """ if request.method == 'GET': # construct new form if group: # edit form obj = dict(name=group.name, owners=[u.name for u in group.owners], packages=[p.name for p in group.packages]) form = forms.GroupForm(**obj) else: # creation form form = forms.GroupForm(owners=[g.user.name]) return render_template('edit-group.html', group=group, form=form) form = forms.GroupForm() # check permissions if group and not group.editable: flash_nak("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) # existing group being edited or None - to be sent into template existing_group = group if not group: group = PackageGroup(namespace=g.user.name) db.add(group) group.name = form.name.data try: db.flush() except IntegrityError: db.rollback() flash_nak("Group already exists") return render_template('edit-group.html', group=existing_group, form=form) try: data.set_group_content(session, group, form.packages.data) data.set_group_maintainers(session, group, form.owners.data) except data.PackagesDontExist as e: db.rollback() flash_nak(str(e)) return render_template('edit-group.html', group=existing_group, form=form) db.commit() flash_ack("Group created" if not existing_group else "Group modified") return redirect(url_for('group_detail', name=group.name, namespace=group.namespace))
def add_packages(): """ Mark multiple packages as tracked. Optionally add them to a group. """ form = forms.AddPackagesForm() if request.method == 'POST': if not form.validate_or_flash(): return render_template("add-packages.html", form=form) names = set(form.packages.data) try: collection = [ c for c in g.collections if c.name == form.collection.data ][0] except IndexError: abort(404) try: added = data.track_packages(session, collection, names) except data.PackagesDontExist as e: db.rollback() flash_nak(str(e)) # frontend doesn't have Koji access, so it needs to rely on backend's polling flash_nak( dedent(""" If a package has been just created, it is possible that it hasn't been propagated to our database yet. In that case, please, try again later. """)) return render_template("add-packages.html", form=form) if form.group.data: namespace, name = PackageGroup.parse_name(form.group.data) group = db.query(PackageGroup)\ .filter_by(namespace=namespace, name=name)\ .first_or_404() if not group.editable: abort(400) data.set_group_content(session, group, names, append=True) flash_ack("Packages added: {}".format(','.join(p.name for p in added))) db.commit() return redirect(request.form.get('next') or url_for('frontpage')) return render_template("add-packages.html", form=form)
def login(): if bypass_login: identity = "none" user_name = bypass_login else: identity = request.environ.get(user_env) 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_info('New user "{}" was registered.'.format(user_name)) session['user'] = user_name flash_ack('Logged in as user "{}" with identity "{}".' .format(user_name, identity)) if user.admin: flash_info('You have admin privileges.') next_url = request.values.get("next", url_for('frontpage')) return redirect(next_url)
def add_packages(): """ Mark multiple packages as tracked. Optionally add them to a group. """ form = forms.AddPackagesForm() if request.method == 'POST': if not form.validate_or_flash(): return render_template("add-packages.html", form=form) names = set(form.packages.data) try: collection = [c for c in g.collections if c.name == form.collection.data][0] except IndexError: abort(404) try: added = data.track_packages(session, collection, names) except data.PackagesDontExist as e: db.rollback() flash_nak(str(e)) # frontend doesn't have Koji access, so it needs to rely on backend's polling flash_nak(dedent(""" If a package has been just created, it is possible that it hasn't been propagated to our database yet. In that case, please, try again later. """)) return render_template("add-packages.html", form=form) if form.group.data: namespace, name = PackageGroup.parse_name(form.group.data) group = db.query(PackageGroup)\ .filter_by(namespace=namespace, name=name)\ .first_or_404() if not group.editable: abort(400) data.set_group_content(session, group, names, append=True) flash_ack("Packages added: {}".format(','.join(p.name for p in added))) db.commit() return redirect(request.form.get('next') or url_for('frontpage')) return render_template("add-packages.html", form=form)
def cancel_build(build_id): """ Requests cancellation of a build by marking the build in the DB. Doesn't do the cancellation itself, as frontend doens't have access to Koji. Backend polls for the atttribute. """ if not g.user.admin: abort(403) build = db.query(Build).filter_by(id=build_id).first_or_404() if forms.EmptyForm().validate_or_flash(): if build.state != Build.RUNNING: flash_nak("Only running builds can be canceled.") elif build.cancel_requested: flash_nak("Build already has pending cancelation request.") else: flash_ack("Cancelation request sent.") session.log_user_action( "Build (id={build.id}, task_id={build.task_id}) cancelation requested" .format(build=build)) build.cancel_requested = True db.commit() return redirect(url_for('package_detail', name=build.package.name))
def cancel_build(build_id): """ Requests cancellation of a build by marking the build in the DB. Doesn't do the cancellation itself, as frontend doens't have access to Koji. Backend polls for the atttribute. """ if not g.user.admin: abort(403) build = db.query(Build).filter_by(id=build_id).first_or_404() if forms.EmptyForm().validate_or_flash(): if build.state != Build.RUNNING: flash_nak("Only running builds can be canceled.") elif build.cancel_requested: flash_nak("Build already has pending cancelation request.") else: flash_ack("Cancelation request sent.") session.log_user_action( "Build (id={build.id}, task_id={build.task_id}) cancelation requested" .format(build=build) ) build.cancel_requested = True db.commit() return redirect(url_for('package_detail', name=build.package.name))
def edit_package(name): """ Edit package attributes or groups. Everyone can edit attributes, group membership requires permissions. """ form = forms.EditPackageForm() collection = g.collections_by_id.get(form.collection_id.data) or abort(400) if not form.validate_or_flash(): return package_detail(name=name, form=form, collection=collection) package = db.query(Package)\ .filter_by(name=name, collection_id=collection.id)\ .first_or_404() # Interpret group checkboxes for key, prev_val in request.form.items(): if key.startswith('group-prev-'): group = db.query(PackageGroup).get_or_404( int(key[len('group-prev-'):])) new_val = request.form.get('group-{}'.format(group.id)) if bool(new_val) != (prev_val == 'true'): if not group.editable: abort(403) if new_val: data.set_group_content(session, group, [package.name], append=True) else: data.set_group_content(session, group, [package.name], delete=True) # Using set_package_attribute to generate audit log events if form.tracked.data is not None: data.set_package_attribute( session, package, 'tracked', form.tracked.data, ) if form.manual_priority.data is not None: data.set_package_attribute( session, package, 'manual_priority', form.manual_priority.data, ) if form.arch_override.data is not None: data.set_package_attribute( session, package, 'arch_override', ' '.join(form.arch_override.data) or None, ) if form.skip_resolution.data is not None: data.set_package_attribute( session, package, 'skip_resolution', form.skip_resolution.data, ) if package.skip_resolution: package.resolved = None db.query(UnappliedChange).filter_by(package_id=package.id).delete() flash_ack("Package modified") db.commit() return redirect( url_for('package_detail', name=package.name) + "?collection=" + collection.name)