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):
name = CharField()
name = CharField(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):
user = ForeignKeyField(User, index=True)
@ -97,13 +104,15 @@ class Role(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)
role = ForeignKeyField(Role)
class Meta:
database = db
indexes = (
(('team', 'repository'), True),
(('user', 'repository'), True),
)
@ -116,7 +125,6 @@ class TeamPermission(BaseModel):
class Meta:
database = db
indexes = (
# A team may only have one permission level in an org
(('team', 'organization'), True),
)

View file

@ -22,6 +22,14 @@ class InvalidUsernameException(DataModelException):
pass
class InvalidOrganizationException(DataModelException):
pass
class InvalidTeamException(DataModelException):
pass
class InvalidPasswordException(DataModelException):
pass
@ -73,6 +81,58 @@ def create_user(username, password, email):
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):
new_user = create_user(username, None, email)
new_user.verified = True
@ -166,35 +226,27 @@ def verify_user(username, password):
# We weren't able to authorize the user
return None
class dotdict(dict):
def __getattr__(self, name):
return self[name]
def get_user_organizations(username):
# TODO: return the orgs that the user is apart of.
return [dotdict({
'username': 'testorg',
'email': 'testorg@quay.io'
})]
UserAlias = User.alias()
all_teams = User.select().join(Team).join(TeamMember)
with_user = all_teams.join(UserAlias, on=(UserAlias.id == TeamMember.user))
return with_user.where(User.organization == True,
UserAlias.username == username)
def lookup_organization(name, username=None):
if name == 'testorg':
return dotdict({
'username': 'testorg',
'email': 'testorg@quay.io'
})
def get_organization(name):
try:
return User.get(username=name, organization=True)
except User.DoesNotExist:
raise InvalidOrganizationException('Organization does not exist: %s' %
name)
return None
def get_user_teams(username, organization):
# TODO: return the teams that the user is apart of.
return [dotdict({
'id': 1234,
'name': 'Owners'
})]
def get_user_teams_within_org(username, organization):
joined = Team.select().join(TeamMember).join(User)
return joined.where(Team.organization == organization,
User.username == username)
def get_visible_repositories(username=None, include_public=True, limit=None,
@ -328,8 +380,10 @@ def create_repository(namespace, name, owner, visibility='private'):
repo = Repository.create(namespace=namespace, name=name,
visibility=private)
admin = Role.get(name='admin')
permission = RepositoryPermission.create(user=owner, repository=repo,
role=admin)
if owner and not owner.organization:
permission = RepositoryPermission.create(user=owner, repository=repo,
role=admin)
return repo
@ -451,59 +505,101 @@ def delete_all_repository_tags(namespace_name, repository_name):
RepositoryTag.delete().where(RepositoryTag.repository == repo)
def user_permission_repo_query(username, namespace_name, repository_name):
selected = RepositoryPermission.select(User, Repository, Role,
def __entity_permission_repo_query(entity_id, entity_table,
entity_id_property, namespace_name,
repository_name):
""" This method works for both users and teams. """
selected = RepositoryPermission.select(entity_table, Repository, Role,
RepositoryPermission)
with_user = selected.join(User)
with_user = selected.join(entity_table)
with_role = with_user.switch(RepositoryPermission).join(Role)
with_repo = with_role.switch(RepositoryPermission).join(Repository)
return with_repo.where(Repository.name == repository_name,
Repository.namespace == namespace_name,
User.username == username)
entity_id_property == entity_id)
def get_user_reponame_permission(username, namespace_name, repository_name):
fetched = list(user_permission_repo_query(username, namespace_name,
repository_name))
fetched = list(__entity_permission_repo_query(username, User, User.username,
namespace_name,
repository_name))
if not fetched:
raise DataModelException('User does not have permission for repo.')
return fetched[0]
def get_team_reponame_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.')
return fetched[0]
def delete_user_permission(username, namespace_name, repository_name):
if username == namespace_name:
raise DataModelException('Namespace owner must always be admin.')
fetched = list(__entity_permission_repo_query(username, User, User.username,
namespace_name,
repository_name))
if not fetched:
raise DataModelException('User does not have permission for repo.')
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.')
user = User.get(User.username == username)
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
return __set_entity_repo_permission(username, User, User.username, 'user',
namespace_name, repository_name,
role_name)
def delete_user_permission(username, namespace_name, repository_name):
if username == namespace_name:
raise DataModelException('Namespace owner must always be admin.')
fetched = list(user_permission_repo_query(username, namespace_name,
repository_name))
if not fetched:
raise DataModelException('User does not have permission for repo.')
fetched[0].delete_instance()
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):

View file

@ -208,11 +208,11 @@ def get_organization(orgname):
abort(404)
user = current_user.db_user()
organization = model.lookup_organization(orgname, username = user.username)
if not organization:
org = model.get_organization(orgname)
if not org:
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))

View file

@ -148,6 +148,19 @@ if __name__ == '__main__':
'Empty repository which is building.',
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')
tag = 'ci.devtable.com:5000/%s/%s' % (building.namespace, building.name)
build = model.create_repository_build(building, token, '123-45-6789', tag)

Binary file not shown.