diff --git a/api.py b/api.py new file mode 100644 index 000000000..92d0b9f46 --- /dev/null +++ b/api.py @@ -0,0 +1,57 @@ +import logging + +from flask import request, make_response, jsonify, abort +from flask.ext.login import login_required, current_user +from functools import wraps + +import model + +from app import app +from util import parse_repository_name + + +logger = logging.getLogger(__name__) + + +@app.route('/api/') +def welcome(): + return make_response('welcome', 200) + + +@app.route('/api/repository/', methods=['POST']) +@login_required +def create_repo_api(): + pass + + +@app.route('/api/repository/', methods=['GET']) +@login_required +def list_repos_api(): + def repo_view(repo_perm): + return { + 'namespace': repo_perm.repository.namespace, + 'name': repo_perm.repository.name, + 'role': repo_perm.role.name, + } + + repos = [repo_view(repo) + for repo in model.get_user_repositories(current_user)] + response = { + 'repositories': repos + } + + return jsonify(response) + + +@app.route('/api/repository/', methods=['PUT']) +@login_required +@parse_repository_name +def update_repo_api(namespace, repository): + pass + + +@app.route('/api/repository/', methods=['GET']) +@login_required +@parse_repository_name +def get_repo_api(namespace, repository): + pass diff --git a/app.py b/app.py index 29f43d9bc..c8bbd5379 100644 --- a/app.py +++ b/app.py @@ -1,10 +1,55 @@ -from flask import Flask, make_response, jsonify +import logging + +from flask import (Flask, make_response, request, abort, render_template, + redirect, url_for) from flask.ext.principal import Principal +from flask.ext.login import login_user, LoginManager + +import model app = Flask(__name__) +logger = logging.getLogger(__name__) Principal(app, use_sessions=False) +app.secret_key = '1cb18882-6d12-440d-a4cc-b7430fb5f884' + +login_manager = LoginManager() +login_manager.init_app(app) +login_manager.login_view = 'signin' + + +@login_manager.user_loader +def load_user(username): + return model.get_user(username) + + +@app.route('/', methods=['GET']) +def index(): + return render_template('index.html') + + +@app.route('/signin', methods=['POST']) +def signin(): + username = request.form['username'] + password = request.form['password'] + + #TODO Allow email login + verified = model.verify_user(username, password) + if verified: + logger.debug('Successfully signed in as: %s' % username) + + login_user(verified) + return redirect(request.args.get('next') or url_for('index')) + + abort(403) + + +@app.route('/signin', methods=['GET']) +def render_signin_page(): + return render_template('signin.html') + + @app.route('/_ping') @app.route('/v1/_ping') def ping(): diff --git a/database.py b/database.py index 99e9ae6fa..542b2b7d6 100644 --- a/database.py +++ b/database.py @@ -20,6 +20,18 @@ class User(BaseModel): email = CharField(unique=True) verified = BooleanField(default=False) + def is_active(self): + return self.verified + + def is_authenticated(self): + return True + + def is_anonymous(self): + return False + + def get_id(self): + return unicode(self.username) + class Visibility(BaseModel): name = CharField() diff --git a/index.py b/index.py index 540c3a33b..adbdf6544 100644 --- a/index.py +++ b/index.py @@ -8,26 +8,19 @@ from functools import wraps from app import app from auth import process_auth, get_authenticated_user, get_validated_token -from util import parse_namespace_repository +from util import parse_namespace_repository, parse_repository_name from permissions import (ModifyRepositoryPermission, ReadRepositoryPermission, UserPermission) import model + logger = logging.getLogger(__name__) REGISTRY_SERVER = 'localhost:5003' -def parse_repository_name(f): - @wraps(f) - def wrapper(repository, *args, **kwargs): - (namespace, repository) = parse_namespace_repository(repository) - return f(namespace, repository, *args, **kwargs) - return wrapper - - def generate_headers(access): def add_headers(f): @wraps(f) diff --git a/model.py b/model.py index b5532ce98..3015ddba5 100644 --- a/model.py +++ b/model.py @@ -15,6 +15,13 @@ def create_user(username, password, email): return new_user +def get_user(username): + try: + return User.get(User.username == username) + except User.DoesNotExist: + return None + + def verify_user(username, password): try: fetched = User.get(User.username == username) @@ -61,6 +68,14 @@ def get_repository(namespace, name): return None +def get_user_repositories(user): + select = RepositoryPermission.select(RepositoryPermission, Repository, Role) + with_user = select.join(User).where(User.username == user.username) + with_role = with_user.switch(RepositoryPermission).join(Role) + with_repo = with_role.switch(RepositoryPermission).join(Repository) + return with_repo + + def create_repository(namespace, name, owner): private = Visibility.get(name='private') repo = Repository.create(namespace=namespace, name=name, diff --git a/requirements.txt b/requirements.txt index 253d526d4..9b80bab6d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,5 @@ peewee flask py-bcrypt -Flask-Principal \ No newline at end of file +Flask-Principal +Flask-Login \ No newline at end of file diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 000000000..41c4e9033 --- /dev/null +++ b/templates/index.html @@ -0,0 +1,15 @@ + + + Quay - Private Docker Repository + + + + + + + + + +

Hello World

+ + \ No newline at end of file diff --git a/templates/signin.html b/templates/signin.html new file mode 100644 index 000000000..79d704d24 --- /dev/null +++ b/templates/signin.html @@ -0,0 +1,12 @@ + + + Quay Sign In + + +
+ Username:
+ Password:
+ +
+ + \ No newline at end of file diff --git a/util.py b/util.py index 7575b7726..25616a346 100644 --- a/util.py +++ b/util.py @@ -1,5 +1,7 @@ import urllib +from functools import wraps + def parse_namespace_repository(repository): parts = repository.rstrip('/').split('/', 1) @@ -10,3 +12,11 @@ def parse_namespace_repository(repository): (namespace, repository) = parts repository = urllib.quote_plus(repository) return (namespace, repository) + + +def parse_repository_name(f): + @wraps(f) + def wrapper(repository, *args, **kwargs): + (namespace, repository) = parse_namespace_repository(repository) + return f(namespace, repository, *args, **kwargs) + return wrapper diff --git a/wsgi.py b/wsgi.py index 66f29524d..411075378 100644 --- a/wsgi.py +++ b/wsgi.py @@ -3,6 +3,7 @@ import logging from app import app import index +import api if __name__ == '__main__': FORMAT = '%(asctime)-15s - %(levelname)s - %(pathname)s - ' + \