Exemple #1
0
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)
Exemple #2
0
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))
Exemple #3
0
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))
Exemple #4
0
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))
Exemple #5
0
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)
Exemple #6
0
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'))
Exemple #7
0
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'))
Exemple #8
0
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))
Exemple #9
0
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)
Exemple #10
0
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)
Exemple #11
0
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)
Exemple #12
0
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))
Exemple #13
0
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))
Exemple #14
0
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)