Flesh out some of the organization methods and fix the models.

This commit is contained in:
yackob03 2013-11-01 19:34:17 -04:00
parent ecc4ad6e0f
commit 4c0f987af3
5 changed files with 181 additions and 64 deletions

View file

@ -38,9 +38,16 @@ class User(BaseModel):
class Team(BaseModel): class Team(BaseModel):
name = CharField() name = CharField(index=True)
organization = ForeignKeyField(User, index=True) organization = ForeignKeyField(User, index=True)
class Meta:
database = db
indexes = (
# A team name must be unique within an organization
(('name', 'organization'), True),
)
class TeamMember(BaseModel): class TeamMember(BaseModel):
user = ForeignKeyField(User, index=True) user = ForeignKeyField(User, index=True)
@ -97,13 +104,15 @@ class Role(BaseModel):
class RepositoryPermission(BaseModel): class RepositoryPermission(BaseModel):
user = ForeignKeyField(User, index=True) team = ForeignKeyField(Team, index=True, null=True)
user = ForeignKeyField(User, index=True, null=True)
repository = ForeignKeyField(Repository, index=True) repository = ForeignKeyField(Repository, index=True)
role = ForeignKeyField(Role) role = ForeignKeyField(Role)
class Meta: class Meta:
database = db database = db
indexes = ( indexes = (
(('team', 'repository'), True),
(('user', 'repository'), True), (('user', 'repository'), True),
) )
@ -116,7 +125,6 @@ class TeamPermission(BaseModel):
class Meta: class Meta:
database = db database = db
indexes = ( indexes = (
# A team may only have one permission level in an org
(('team', 'organization'), True), (('team', 'organization'), True),
) )

View file

@ -22,6 +22,14 @@ class InvalidUsernameException(DataModelException):
pass pass
class InvalidOrganizationException(DataModelException):
pass
class InvalidTeamException(DataModelException):
pass
class InvalidPasswordException(DataModelException): class InvalidPasswordException(DataModelException):
pass pass
@ -73,6 +81,58 @@ def create_user(username, password, email):
raise DataModelException(ex.message) raise DataModelException(ex.message)
def create_organization(name, email, creating_user):
try:
# Create the org
new_org = create_user(name, None, email)
new_org.organization = True
new_org.save()
# Create a team for the owners
owners_team = create_team('Owners', new_org)
# Add the user who created the org to the owners
add_user_to_team(creating_user, owners_team)
# Give the owners team admin access to the namespace
set_team_org_permission(owners_team, new_org, 'admin')
return new_org
except InvalidUsernameException:
raise InvalidOrganizationException('Invalid organization name: %s' % name)
def create_team(name, org):
if not validate_username(name):
raise InvalidTeamException('Invalid team name: %s' % name)
if not org.organization:
raise InvalidOrganizationException('User with name %s is not an org.' %
org.username)
return Team.create(name=name, organization=org)
def add_user_to_team(user, team):
return TeamMember.create(user=user, team=team)
def set_team_org_permission(team, org, role_name):
new_role = Role.get(Role.name == role_name)
# Fetch any existing permission for this user on the repo
try:
perm = TeamPermission.get(TeamPermission.team == team,
TeamPermission.organization == org)
perm.role = new_role
perm.save()
return perm
except TeamPermission.DoesNotExist:
new_perm = TeamPermission.create(team=team, organization=org,
role=new_role)
return new_perm
def create_federated_user(username, email, service_name, service_id): def create_federated_user(username, email, service_name, service_id):
new_user = create_user(username, None, email) new_user = create_user(username, None, email)
new_user.verified = True new_user.verified = True
@ -166,35 +226,27 @@ def verify_user(username, password):
# We weren't able to authorize the user # We weren't able to authorize the user
return None return None
class dotdict(dict):
def __getattr__(self, name):
return self[name]
def get_user_organizations(username): def get_user_organizations(username):
# TODO: return the orgs that the user is apart of. UserAlias = User.alias()
return [dotdict({ all_teams = User.select().join(Team).join(TeamMember)
'username': 'testorg', with_user = all_teams.join(UserAlias, on=(UserAlias.id == TeamMember.user))
'email': 'testorg@quay.io' return with_user.where(User.organization == True,
})] UserAlias.username == username)
def lookup_organization(name, username=None): def get_organization(name):
if name == 'testorg': try:
return dotdict({ return User.get(username=name, organization=True)
'username': 'testorg', except User.DoesNotExist:
'email': 'testorg@quay.io' raise InvalidOrganizationException('Organization does not exist: %s' %
}) name)
return None
def get_user_teams(username, organization): def get_user_teams_within_org(username, organization):
# TODO: return the teams that the user is apart of. joined = Team.select().join(TeamMember).join(User)
return [dotdict({ return joined.where(Team.organization == organization,
'id': 1234, User.username == username)
'name': 'Owners'
})]
def get_visible_repositories(username=None, include_public=True, limit=None, def get_visible_repositories(username=None, include_public=True, limit=None,
@ -328,6 +380,8 @@ def create_repository(namespace, name, owner, visibility='private'):
repo = Repository.create(namespace=namespace, name=name, repo = Repository.create(namespace=namespace, name=name,
visibility=private) visibility=private)
admin = Role.get(name='admin') admin = Role.get(name='admin')
if owner and not owner.organization:
permission = RepositoryPermission.create(user=owner, repository=repo, permission = RepositoryPermission.create(user=owner, repository=repo,
role=admin) role=admin)
return repo return repo
@ -451,19 +505,23 @@ def delete_all_repository_tags(namespace_name, repository_name):
RepositoryTag.delete().where(RepositoryTag.repository == repo) RepositoryTag.delete().where(RepositoryTag.repository == repo)
def user_permission_repo_query(username, namespace_name, repository_name): def __entity_permission_repo_query(entity_id, entity_table,
selected = RepositoryPermission.select(User, Repository, Role, entity_id_property, namespace_name,
repository_name):
""" This method works for both users and teams. """
selected = RepositoryPermission.select(entity_table, Repository, Role,
RepositoryPermission) RepositoryPermission)
with_user = selected.join(User) with_user = selected.join(entity_table)
with_role = with_user.switch(RepositoryPermission).join(Role) with_role = with_user.switch(RepositoryPermission).join(Role)
with_repo = with_role.switch(RepositoryPermission).join(Repository) with_repo = with_role.switch(RepositoryPermission).join(Repository)
return with_repo.where(Repository.name == repository_name, return with_repo.where(Repository.name == repository_name,
Repository.namespace == namespace_name, Repository.namespace == namespace_name,
User.username == username) entity_id_property == entity_id)
def get_user_reponame_permission(username, namespace_name, repository_name): def get_user_reponame_permission(username, namespace_name, repository_name):
fetched = list(user_permission_repo_query(username, namespace_name, fetched = list(__entity_permission_repo_query(username, User, User.username,
namespace_name,
repository_name)) repository_name))
if not fetched: if not fetched:
raise DataModelException('User does not have permission for repo.') raise DataModelException('User does not have permission for repo.')
@ -471,34 +529,22 @@ def get_user_reponame_permission(username, namespace_name, repository_name):
return fetched[0] return fetched[0]
def set_user_repo_permission(username, namespace_name, repository_name, def get_team_reponame_permission(team_name, namespace_name, repository_name):
role_name): fetched = list(__entity_permission_repo_query(team_name, Team, Team.name,
if username == namespace_name: namespace_name,
raise DataModelException('Namespace owner must always be admin.') repository_name))
if not fetched:
raise DataModelException('Team does not have permission for repo.')
user = User.get(User.username == username) return fetched[0]
repo = Repository.get(Repository.name == repository_name,
Repository.namespace == namespace_name)
new_role = Role.get(Role.name == role_name)
# Fetch any existing permission for this user on the repo
try:
perm = RepositoryPermission.get(RepositoryPermission.user == user,
RepositoryPermission.repository == repo)
perm.role = new_role
perm.save()
return perm
except RepositoryPermission.DoesNotExist:
new_perm = RepositoryPermission.create(repository=repo, user=user,
role=new_role)
return new_perm
def delete_user_permission(username, namespace_name, repository_name): def delete_user_permission(username, namespace_name, repository_name):
if username == namespace_name: if username == namespace_name:
raise DataModelException('Namespace owner must always be admin.') raise DataModelException('Namespace owner must always be admin.')
fetched = list(user_permission_repo_query(username, namespace_name, fetched = list(__entity_permission_repo_query(username, User, User.username,
namespace_name,
repository_name)) repository_name))
if not fetched: if not fetched:
raise DataModelException('User does not have permission for repo.') raise DataModelException('User does not have permission for repo.')
@ -506,6 +552,56 @@ def delete_user_permission(username, namespace_name, repository_name):
fetched[0].delete_instance() fetched[0].delete_instance()
def delete_team_permission(team_name, namespace_name, repository_name):
fetched = list(__entity_permission_repo_query(team_name, Team, Team.name,
namespace_name,
repository_name))
if not fetched:
raise DataModelException('Team does not have permission for repo.')
fetched[0].delete_instance()
def __set_entity_repo_permission(entity_id, entity_table, entity_id_property,
permission_entity_property, namespace_name,
repository_name, role_name):
entity = entity_table.get(entity_id_property == entity_id)
repo = Repository.get(Repository.name == repository_name,
Repository.namespace == namespace_name)
new_role = Role.get(Role.name == role_name)
# Fetch any existing permission for this user on the repo
try:
entity_attr = getattr(RepositoryPermission, permission_entity_property)
perm = RepositoryPermission.get(entity_attr == entity,
RepositoryPermission.repository == repo)
perm.role = new_role
perm.save()
return perm
except RepositoryPermission.DoesNotExist:
set_entity_kwargs = {permission_entity_property: entity}
new_perm = RepositoryPermission.create(repository=repo, role=new_role,
**set_entity_kwargs)
return new_perm
def set_user_repo_permission(username, namespace_name, repository_name,
role_name):
if username == namespace_name:
raise DataModelException('Namespace owner must always be admin.')
return __set_entity_repo_permission(username, User, User.username, 'user',
namespace_name, repository_name,
role_name)
def set_team_repo_permission(team_name, namespace_name, repository_name,
role_name):
return __set_entity_repo_permission(team_name, Team, Team.name, 'team',
namespace_name, repository_name,
role_name)
def purge_repository(namespace_name, repository_name): def purge_repository(namespace_name, repository_name):
fetched = Repository.get(Repository.name == repository_name, fetched = Repository.get(Repository.name == repository_name,
Repository.namespace == namespace_name) Repository.namespace == namespace_name)

View file

@ -208,11 +208,11 @@ def get_organization(orgname):
abort(404) abort(404)
user = current_user.db_user() user = current_user.db_user()
organization = model.lookup_organization(orgname, username = user.username) org = model.get_organization(orgname)
if not organization: if not org:
abort(404) abort(404)
teams = model.get_user_teams(user.username, organization) teams = model.get_user_teams_within_org(user.username, org)
return jsonify(org_view(organization, teams)) return jsonify(org_view(organization, teams))

View file

@ -148,6 +148,19 @@ if __name__ == '__main__':
'Empty repository which is building.', 'Empty repository which is building.',
False, [], (0, [], None)) False, [], (0, [], None))
org = model.create_organization('devtableorg', 'quay@devtable.com',
new_user_1)
org_repo = __generate_repository(org, 'orgrepo',
'Repository owned by an org.', False,
[], (4, [], ['latest', 'prod']))
reader_team = model.create_team('Readers', org)
model.set_team_repo_permission(reader_team.name, org_repo.namespace,
org_repo.name, 'read')
model.add_user_to_team(new_user_2, reader_team)
token = model.create_access_token(building, 'write') token = model.create_access_token(building, 'write')
tag = 'ci.devtable.com:5000/%s/%s' % (building.namespace, building.name) tag = 'ci.devtable.com:5000/%s/%s' % (building.namespace, building.name)
build = model.create_repository_build(building, token, '123-45-6789', tag) build = model.create_repository_build(building, token, '123-45-6789', tag)

Binary file not shown.