Fix some stuff with logins and permissions, add tags to the mode.
This commit is contained in:
parent
744c73509b
commit
08446ef59e
10 changed files with 94 additions and 34 deletions
25
auth/auth.py
25
auth/auth.py
|
@ -3,38 +3,17 @@ import logging
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
from flask import request, make_response, _request_ctx_stack, abort
|
from flask import request, make_response, _request_ctx_stack, abort
|
||||||
from flask.ext.principal import identity_changed, Identity
|
from flask.ext.principal import identity_changed, Identity
|
||||||
from flask.ext.login import UserMixin
|
|
||||||
from base64 import b64decode
|
from base64 import b64decode
|
||||||
|
|
||||||
from data import model
|
from data import model
|
||||||
from app import app, login_manager
|
from app import app
|
||||||
|
|
||||||
from util import parse_namespace_repository
|
from util.names import parse_namespace_repository
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class _LoginWrappedDBUser(UserMixin):
|
|
||||||
def __init__(self, db_user):
|
|
||||||
self.db_user = db_user
|
|
||||||
|
|
||||||
def is_active(self):
|
|
||||||
return self.db_user.verified
|
|
||||||
|
|
||||||
def get_id(self):
|
|
||||||
return unicode(self.db_user.username)
|
|
||||||
|
|
||||||
|
|
||||||
@login_manager.user_loader
|
|
||||||
def load_user(username):
|
|
||||||
db_user = model.get_user(username)
|
|
||||||
if db_user:
|
|
||||||
return _LoginWrappedDBUser(db_user)
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def get_authenticated_user():
|
def get_authenticated_user():
|
||||||
return getattr(_request_ctx_stack.top, 'authenticated_user', None)
|
return getattr(_request_ctx_stack.top, 'authenticated_user', None)
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ import logging
|
||||||
|
|
||||||
from flask.ext.principal import identity_loaded, UserNeed, Permission
|
from flask.ext.principal import identity_loaded, UserNeed, Permission
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
from functools import partial
|
||||||
|
|
||||||
from data import model
|
from data import model
|
||||||
from app import app
|
from app import app
|
||||||
|
@ -11,7 +12,8 @@ from auth import get_authenticated_user, get_validated_token
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
_RepositoryNeed = namedtuple('repository', ['namespace', 'name', 'role'])
|
_ResourceNeed = namedtuple('resource', ['type', 'namespace', 'name', 'role'])
|
||||||
|
_RepositoryNeed = partial(_ResourceNeed, 'repository')
|
||||||
|
|
||||||
|
|
||||||
class ModifyRepositoryPermission(Permission):
|
class ModifyRepositoryPermission(Permission):
|
||||||
|
@ -38,6 +40,7 @@ class UserPermission(Permission):
|
||||||
|
|
||||||
@identity_loaded.connect_via(app)
|
@identity_loaded.connect_via(app)
|
||||||
def on_identity_loaded(sender, identity):
|
def on_identity_loaded(sender, identity):
|
||||||
|
logger.debug('Identity loaded: %s' % identity)
|
||||||
# We have verified an identity, load in all of the permissions
|
# We have verified an identity, load in all of the permissions
|
||||||
if get_authenticated_user():
|
if get_authenticated_user():
|
||||||
identity.provides.add(UserNeed(get_authenticated_user().username))
|
identity.provides.add(UserNeed(get_authenticated_user().username))
|
||||||
|
|
|
@ -18,7 +18,9 @@ class User(BaseModel):
|
||||||
username = CharField(unique=True)
|
username = CharField(unique=True)
|
||||||
password_hash = CharField()
|
password_hash = CharField()
|
||||||
email = CharField(unique=True)
|
email = CharField(unique=True)
|
||||||
verified = BooleanField(default=False)
|
|
||||||
|
# TODO move this to False and require email verification
|
||||||
|
verified = BooleanField(default=True)
|
||||||
|
|
||||||
|
|
||||||
class Visibility(BaseModel):
|
class Visibility(BaseModel):
|
||||||
|
@ -68,6 +70,12 @@ class Image(BaseModel):
|
||||||
checksum = CharField(null=True)
|
checksum = CharField(null=True)
|
||||||
|
|
||||||
|
|
||||||
|
class RepositoryTag(BaseModel):
|
||||||
|
name = CharField()
|
||||||
|
image = ForeignKeyField(Image)
|
||||||
|
repository = ForeignKeyField(Repository)
|
||||||
|
|
||||||
|
|
||||||
class RepositoryImage(BaseModel):
|
class RepositoryImage(BaseModel):
|
||||||
repository = ForeignKeyField(Repository)
|
repository = ForeignKeyField(Repository)
|
||||||
image = ForeignKeyField(Image)
|
image = ForeignKeyField(Image)
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
import bcrypt
|
import bcrypt
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from database import (User, Repository, Image, RepositoryImage, AccessToken,
|
from database import *
|
||||||
RepositoryPermission, Visibility, Role)
|
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
@ -111,6 +110,52 @@ def get_repository_images(namespace_name, repository_name):
|
||||||
Repository.namespace == namespace_name)
|
Repository.namespace == namespace_name)
|
||||||
|
|
||||||
|
|
||||||
|
def list_repository_tags(namespace_name, repository_name):
|
||||||
|
select = RepositoryTag.select(RepositoryTag, Image)
|
||||||
|
with_repo = select.join(Repository)
|
||||||
|
with_image = with_repo.switch(RepositoryTag).join(Image)
|
||||||
|
return joined.where(Repository.name == repository_name and
|
||||||
|
Repository.namespace == namespace_name)
|
||||||
|
|
||||||
|
|
||||||
|
def get_tag_image(namespace_name, repository_name, tag_name):
|
||||||
|
joined = Image.select().join(RepositoryTag).join(Repository)
|
||||||
|
return joined.where(Repository.name == repository_name and
|
||||||
|
Repository.namespace == namespace_name and
|
||||||
|
RepositoryTag.name == tag_name)
|
||||||
|
|
||||||
|
|
||||||
|
def create_or_update_tag(namespace_name, repository_name, tag_name,
|
||||||
|
tag_image_id):
|
||||||
|
repo = Repository.get(Repository.name == name and
|
||||||
|
Repository.namespace == namespace)
|
||||||
|
image = Image.get(Image.image_id == tag_image_id)
|
||||||
|
|
||||||
|
try:
|
||||||
|
tag = RepositoryTag.get(RepositoryTag.repository == repo and
|
||||||
|
RepositoryTag.tag_name == tag_name)
|
||||||
|
tag.image = image
|
||||||
|
tag.save()
|
||||||
|
except RepositoryTag.DoesNotExist:
|
||||||
|
tag = RepositoryTag.create(repository=repo, image=image, name=tag_name)
|
||||||
|
|
||||||
|
return tag
|
||||||
|
|
||||||
|
|
||||||
|
def delete_tag(namespace_name, repository_name, tag_name):
|
||||||
|
repo = Repository.get(Repository.name == name and
|
||||||
|
Repository.namespace == namespace)
|
||||||
|
tag = RepositoryTag.get(RepositoryTag.repository == repo and
|
||||||
|
RepositoryTag.tag_name == tag_name)
|
||||||
|
tag.delete_instance()
|
||||||
|
|
||||||
|
|
||||||
|
def delete_all_repository_tags(namespace_name, repository_name):
|
||||||
|
repo = Repository.get(Repository.name == name and
|
||||||
|
Repository.namespace == namespace)
|
||||||
|
RepositoryTag.delete().where(RepositoryTag.repository == repo)
|
||||||
|
|
||||||
|
|
||||||
def create_access_token(repository, user):
|
def create_access_token(repository, user):
|
||||||
new_token = AccessToken.create(user=user, repository=repository)
|
new_token = AccessToken.create(user=user, repository=repository)
|
||||||
return new_token
|
return new_token
|
||||||
|
|
|
@ -6,7 +6,7 @@ from functools import wraps
|
||||||
|
|
||||||
from data import model
|
from data import model
|
||||||
from app import app
|
from app import app
|
||||||
from util import parse_repository_name
|
from util.names import parse_repository_name
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
@ -33,7 +33,7 @@ def list_repos_api():
|
||||||
'role': repo_perm.role.name,
|
'role': repo_perm.role.name,
|
||||||
}
|
}
|
||||||
|
|
||||||
repos = [repo_view(repo)
|
repos = [repo_view(repo)
|
||||||
for repo in model.get_user_repositories(current_user.db_user)]
|
for repo in model.get_user_repositories(current_user.db_user)]
|
||||||
response = {
|
response = {
|
||||||
'repositories': repos
|
'repositories': repos
|
||||||
|
|
|
@ -10,12 +10,11 @@ from data import model
|
||||||
from app import app
|
from app import app
|
||||||
from auth.auth import (process_auth, get_authenticated_user,
|
from auth.auth import (process_auth, get_authenticated_user,
|
||||||
get_validated_token)
|
get_validated_token)
|
||||||
from util import parse_namespace_repository, parse_repository_name
|
from util.names import parse_namespace_repository, parse_repository_name
|
||||||
from auth.permissions import (ModifyRepositoryPermission,
|
from auth.permissions import (ModifyRepositoryPermission,
|
||||||
ReadRepositoryPermission, UserPermission)
|
ReadRepositoryPermission, UserPermission)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,33 @@
|
||||||
from flask import abort, send_file, redirect, request
|
import logging
|
||||||
|
|
||||||
|
from flask import abort, send_file, redirect, request, url_for
|
||||||
|
from flask.ext.login import login_user, UserMixin
|
||||||
|
|
||||||
from data import model
|
from data import model
|
||||||
from app import app
|
from app import app, login_manager
|
||||||
|
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class _LoginWrappedDBUser(UserMixin):
|
||||||
|
def __init__(self, db_user):
|
||||||
|
self.db_user = db_user
|
||||||
|
|
||||||
|
def is_active(self):
|
||||||
|
return self.db_user.verified
|
||||||
|
|
||||||
|
def get_id(self):
|
||||||
|
return unicode(self.db_user.username)
|
||||||
|
|
||||||
|
|
||||||
|
@login_manager.user_loader
|
||||||
|
def load_user(username):
|
||||||
|
db_user = model.get_user(username)
|
||||||
|
if db_user:
|
||||||
|
return _LoginWrappedDBUser(db_user)
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
@app.route('/', methods=['GET'])
|
@app.route('/', methods=['GET'])
|
||||||
|
@ -27,4 +53,4 @@ def signin():
|
||||||
|
|
||||||
@app.route('/signin', methods=['GET'])
|
@app.route('/signin', methods=['GET'])
|
||||||
def render_signin_page():
|
def render_signin_page():
|
||||||
return send_file('templates/signin.html')
|
return send_file('templates/signin.html')
|
||||||
|
|
BIN
test.db
BIN
test.db
Binary file not shown.
0
util/__init__.py
Normal file
0
util/__init__.py
Normal file
Reference in a new issue