Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Guest projects #498

Merged
merged 14 commits into from
Jul 13, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
- Redis host/port env vars fixed:
- `REDIS_PORT_6379_ADDR` to `REDIS_PORT_6379_TCP_ADDR`
- `REDIS_PORT_6379_PORT` to `REDIS_PORT_6379_TCP_PORT`
- Public projects visible by guests #498

### v0.0.10
- Allow override of repo name in `dockci.yaml` #397
Expand Down
30 changes: 30 additions & 0 deletions alembic/versions/4b558aa4806_public_projects.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
"""public projects

Revision ID: 4b558aa4806
Revises: 289417c9d06
Create Date: 2016-07-08 18:05:57.498826

"""

# revision identifiers, used by Alembic.
revision = '4b558aa4806'
down_revision = '289417c9d06'
branch_labels = None
depends_on = None

from alembic import op
import sqlalchemy as sa


def upgrade():
### commands auto generated by Alembic - please adjust! ###
op.add_column('project', sa.Column('public', sa.Boolean(), server_default=sa.text('false'), nullable=False))
op.create_index(op.f('ix_project_public'), 'project', ['public'], unique=False)
### end Alembic commands ###


def downgrade():
### commands auto generated by Alembic - please adjust! ###
op.drop_index(op.f('ix_project_public'), table_name='project')
op.drop_column('project', 'public')
### end Alembic commands ###
16 changes: 14 additions & 2 deletions dockci/api/job.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@
import sqlalchemy
import uuid

import flask_restful
import redis
import redis_lock

from flask import abort, request, url_for
from flask_restful import fields, inputs, marshal_with, Resource
from flask_security import login_required
from flask_security import current_user, login_required

from . import fields as fields_
from .base import BaseDetailResource, BaseRequestParser
Expand Down Expand Up @@ -128,7 +129,10 @@ def get_validate_job(project_slug, job_slug):
job_id = Job.id_from_slug(job_slug)
job = Job.query.get_or_404(job_id)
if job.project.slug != project_slug:
abort(404)
flask_restful.abort(404)

if not (job.project.public or current_user.is_authenticated()):
flask_restful.abort(404)

return job

Expand Down Expand Up @@ -187,6 +191,10 @@ class JobList(BaseDetailResource):
def get(self, project_slug):
""" List all jobs for a project """
project = Project.query.filter_by(slug=project_slug).first_or_404()

if not (project.public or current_user.is_authenticated()):
flask_restful.abort(404)

base_query = filter_jobs_by_request(project)
return {
'items': base_query.paginate().items,
Expand All @@ -210,6 +218,10 @@ class JobCommitsList(Resource):
def get(self, project_slug):
""" List all distinct job commits for a project """
project = Project.query.filter_by(slug=project_slug).first_or_404()

if not (project.public or current_user.is_authenticated()):
flask_restful.abort(404)

base_query = filter_jobs_by_request(project).filter(
Job.commit.op('SIMILAR TO')(r'[0-9a-fA-F]+')
)
Expand Down
17 changes: 16 additions & 1 deletion dockci/api/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ def docker_repo_field(value, name):
'github_repo_id': fields.String(),
'github_hook_id': fields.String(),
'gitlab_repo_id': fields.String(),
'public': fields.Boolean(),
'shield_text': fields.String(),
'shield_color': fields.String(),
'target_registry': RewriteUrl(
Expand Down Expand Up @@ -136,6 +137,10 @@ def docker_repo_field(value, name):
type=RegexInput(),
),
'github_secret': dict(help="Shared secret to validate GitHub hooks"),
'public': dict(
help="Whether or not to allow read-only guest access",
type=inputs.boolean,
),
}

UTILITY_ARG = dict(
Expand Down Expand Up @@ -228,6 +233,9 @@ def get(self):

query = Project.query

if not current_user.is_authenticated():
query = query.filter_by(public=True)

if opts['order'] == 'recent':
query = (
query.
Expand Down Expand Up @@ -266,7 +274,10 @@ class ProjectDetail(BaseDetailResource):
@marshal_with(DETAIL_FIELDS)
def get(self, project_slug):
""" Get project details """
return Project.query.filter_by(slug=project_slug).first_or_404()
project = Project.query.filter_by(slug=project_slug).first_or_404()
if not (project.public or current_user.is_authenticated()):
flask_restful.abort(404)
return project

@login_required
@marshal_with(DETAIL_FIELDS)
Expand Down Expand Up @@ -326,6 +337,10 @@ class ProjectBranchList(Resource):
def get(self, project_slug):
""" List of all branches in a project """
project = Project.query.filter_by(slug=project_slug).first_or_404()

if not (project.public or current_user.is_authenticated()):
flask_restful.abort(404)

return [
dict(name=job.git_branch)
for job
Expand Down
6 changes: 6 additions & 0 deletions dockci/models/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,13 @@ class Project(DB.Model, RepoFsMixin): # pylint:disable=no-init
repo = DB.Column(DB.String(255), nullable=False)
name = DB.Column(DB.String(255), nullable=False)
branch_pattern = DB.Column(RegexType(), nullable=True)

utility = DB.Column(DB.Boolean(), nullable=False, index=True)
public = DB.Column(DB.Boolean(),
default=False,
server_default=sqlalchemy.sql.expression.false(),
nullable=False,
index=True)

# TODO repo ID from repo
github_repo_id = DB.Column(DB.String(255))
Expand Down
9 changes: 9 additions & 0 deletions dockci/static/js/components/project_edit.html
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,15 @@
<input required class="form-control" id="inputName" name="name" placeholder="Name" data-bind="value:project().name">
</div>
</div>
<div class="form-group">
<label for="inputPublic" class="col-sm-2 control-label">Public</label>
<div class="col-sm-10">
<div class="checkbox"><label>
<input type="checkbox" id="inputPublic" name="public" data-bind="checked:project().public">
Visible without login
</label></div>
</div>
</div>
<div class="form-group">
<label for="inputTargetRegistry" class="col-sm-2 control-label">Target registry</label>
<div class="col-sm-10">
Expand Down
4 changes: 4 additions & 0 deletions dockci/static/js/models/project.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ define(['jquery', 'knockout', '../util'], function ($, ko, util) {
this.display_repo = ko.observable()
this.branch_pattern = ko.observable()
this.utility = ko.observable()
this.public = ko.observable()

this.forcedType = ko.observable()

Expand Down Expand Up @@ -85,6 +86,7 @@ define(['jquery', 'knockout', '../util'], function ($, ko, util) {
'github_secret': this.github_secret() || undefined,
'gitlab_private_token': this.gitlab_private_token() || undefined,
'target_registry': this.target_registry_base_name() || null,
'public': this.public(),
}
if(isNew) {
return $.extend(baseParams, {
Expand Down Expand Up @@ -119,6 +121,7 @@ define(['jquery', 'knockout', '../util'], function ($, ko, util) {
, 'repo': null
, 'display_repo': ''
, 'branch_pattern': ''
, 'public': false
, 'utility': false
, 'gitlab_base_uri': ''
, 'gitlab_repo_id': ''
Expand All @@ -130,6 +133,7 @@ define(['jquery', 'knockout', '../util'], function ($, ko, util) {
this._repo(data['repo'])
this.display_repo(data['display_repo'])
this.branch_pattern(data['branch_pattern'])
this.public(data['public'])
this.utility(data['utility'])
this.gitlab_base_uri(data['gitlab_base_uri'])
this.gitlab_repo_id(data['gitlab_repo_id'])
Expand Down
10 changes: 8 additions & 2 deletions dockci/views/job.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@ def job_view(project_slug, job_slug):
"""
View to display a job
"""
Project.query.filter_by(slug=project_slug).first_or_404() # ensure exist
project = Project.query.filter_by(slug=project_slug).first_or_404()
if not (project.public or current_user.is_authenticated()):
abort(404)

job = Job.query.get_or_404(Job.id_from_slug(job_slug))

return render_template('job.html', job=job)
Expand Down Expand Up @@ -150,7 +153,10 @@ def job_new_github(project, job):

def check_output(project_slug, job_slug, filename):
""" Ensure the job exists, and that the path is not dangerous """
Project.query.filter_by(slug=project_slug).first_or_404() # ensure exist
project = Project.query.filter_by(slug=project_slug).first_or_404()
if not (project.public or current_user.is_authenticated()):
abort(404)

job = Job.query.get_or_404(Job.id_from_slug(job_slug))

job_output_path = job.job_output_path()
Expand Down
9 changes: 8 additions & 1 deletion dockci/views/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
Views related to project management
"""

from flask import redirect, render_template, request
from flask import abort, redirect, render_template, request
from flask_security import current_user

from dockci.api.job import filter_jobs_by_request
from dockci.models.project import Project
Expand All @@ -20,6 +21,9 @@ def project_shield_view(slug, extension):
""" View to give shields for each project """
project = Project.query.filter_by(slug=slug).first_or_404()

if not (project.public or current_user.is_authenticated()):
abort(404)

try:
query = '?style=%s' % request.args['style']
except KeyError:
Expand All @@ -44,6 +48,9 @@ def project_view(slug):
"""
project = Project.query.filter_by(slug=slug).first_or_404()

if not (project.public or current_user.is_authenticated()):
abort(404)

page_size = int(request.args.get('page_size', 20))
page = int(request.args.get('page', 1))

Expand Down
6 changes: 2 additions & 4 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,7 @@ def base_db_conn():
APP.config['SQLALCHEMY_DATABASE_URI'] = DB.engine.url
app_init()

try:
yield conn
finally:
conn.execute('DROP DATABASE %s' % db_name)
yield conn


@pytest.yield_fixture
Expand Down Expand Up @@ -140,6 +137,7 @@ def project(db, randid):
name=randid,
repo='test',
utility=False,
public=True
), delete=True) as model:
yield model

Expand Down
23 changes: 7 additions & 16 deletions tests/db/api/test_user_api_db.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,30 +20,22 @@ def test_add_to_empty(self):
assert [role.name for role in user.roles] == ['admin']

@pytest.mark.usefixtures('db')
def test_add_multiple(self):
def test_add_multiple(self, role):
""" Add multiple roles to a user with no roles """
role = Role(name='test')
DB.session.add(role)
DB.session.commit()

user = User()
rest_set_roles(user, ['admin', 'test'])
assert [role.name for role in user.roles] == ['admin', 'test']
rest_set_roles(user, ['admin', role.name])
assert [role.name for role in user.roles] == ['admin', role.name]

@pytest.mark.usefixtures('db')
def test_set_with_existing(self):
def test_set_with_existing(self, role, user):
""" Set roles on a user with an existing role """
role = Role(name='test')
user = SECURITY_STATE.datastore.create_user(
email='[email protected]',
)
user.roles.append(Role.query.get(1))
user.roles.append(role)
DB.session.add(role)
DB.session.add(user)
DB.session.commit()

rest_set_roles(user, ['test'])
assert [role.name for role in user.roles] == ['test']
rest_set_roles(user, [role.name])
assert [role.name for role in user.roles] == [role.name]

@pytest.mark.usefixtures('db')
def test_add_fake(self):
Expand Down Expand Up @@ -110,7 +102,6 @@ def test_no_admin_update_roles(self, client, user, role):
'roles': [role.name],
})

print(response.data)
assert response.status_code == 401

DB.session.refresh(user)
Expand Down
11 changes: 10 additions & 1 deletion tests/db/models/test_project_db.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import pytest

from dockci.models.job import Job
from dockci.models.job import Job, JobStageTmp
from dockci.models.project import Project
from dockci.server import DB

Expand All @@ -12,6 +12,7 @@ def create_project(slug, **kwargs):
slug=slug,
utility=False,
repo='test',
public=True,
)
final_kwargs.update(kwargs)
return Project(**final_kwargs)
Expand All @@ -30,6 +31,14 @@ def create_job(**kwargs):
class TestProjectsSummary(object):
""" Ensure ``Project.get_status_summary`` behaves as expected """

def setup_method(self, _):
JobStageTmp.query.delete()
Job.query.delete()
def teardown_method(self, _):
JobStageTmp.query.delete()
Job.query.delete()


@pytest.mark.parametrize('models,p_filters,exp_s,exp_f,exp_b,exp_i', [
(
(
Expand Down
Loading