Flesh out some of the organization methods and fix the models.
This commit is contained in:
parent
ecc4ad6e0f
commit
4c0f987af3
5 changed files with 181 additions and 64 deletions
|
@ -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),
|
||||
)
|
||||
|
||||
|
|
212
data/model.py
212
data/model.py
|
@ -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):
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
||||
|
|
13
initdb.py
13
initdb.py
|
@ -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.
Reference in a new issue