Initial interfaces and support for team syncing worker

This commit is contained in:
Joseph Schorr 2017-02-21 21:07:48 -05:00
parent 94b07e6de9
commit eeadeb9383
12 changed files with 282 additions and 15 deletions

View file

@ -1,9 +1,11 @@
import json
import uuid
from datetime import datetime
from peewee import fn
from data.database import (Team, TeamMember, TeamRole, User, TeamMemberInvite, RepositoryPermission,
TeamSync, LoginService)
TeamSync, LoginService, FederatedLogin, db_random_func, db_transaction)
from data.model import (DataModelException, InvalidTeamException, UserAlreadyInTeam,
InvalidTeamMemberException, _basequery)
from data.text import prefix_search
@ -192,7 +194,7 @@ def get_matching_teams(team_prefix, organization):
return query.limit(10)
def get_teams_within_org(organization):
def get_teams_within_org(organization, has_external_auth=False):
""" Returns a AttrDict of team info (id, name, description), its role under the org,
the number of repositories on which it has permission, and the number of members.
"""
@ -209,6 +211,8 @@ def get_teams_within_org(organization):
'repo_count': 0,
'member_count': 0,
'is_synced': False,
}
teams = {team.id: _team_view(team) for team in query}
@ -236,6 +240,12 @@ def get_teams_within_org(organization):
for member_tuple in members_tuples:
teams[member_tuple[0]]['member_count'] = member_tuple[1]
# Add syncing information.
if has_external_auth:
sync_query = TeamSync.select(TeamSync.team).where(TeamSync.team << teams.keys())
for team_sync in sync_query:
teams[team_sync.team_id]['is_synced'] = True
return [AttrDict(team_info) for team_info in teams.values()]
@ -374,16 +384,72 @@ def confirm_team_invite(code, user_obj):
inviter = found.inviter
return (team, inviter)
def list_federated_team_members(team, login_service_name):
""" Returns a dict of all federated IDs for all team members in the team whose users are
bound to the login service withn the given name. The dictionary is from federated service
identifier (username) to their Quay User table ID.
"""
login_service = LoginService.get(name=login_service_name)
query = (FederatedLogin
.select(FederatedLogin.service_ident, User.id)
.join(User)
.join(TeamMember)
.join(Team)
.where(Team.id == team, User.robot == False, FederatedLogin.service == login_service))
return dict(query.tuples())
def list_team_users(team):
""" Returns an iterator of all the *users* found in a team. Does not include robots. """
return (User
.select()
.join(TeamMember)
.join(Team)
.where(Team.id == team, User.robot == False))
def set_team_syncing(team, login_service_name, config):
""" Sets the given team to sync to the given service using the given config. """
login_service = LoginService.get(name=login_service_name)
TeamSync.create(team=team, transaction_id='', service=login_service, config=json.dumps(config))
def remove_team_syncing(orgname, teamname):
""" Removes syncing on the team matching the given organization name and team name. """
existing = get_team_sync_information(orgname, teamname)
if existing:
existing.delete_instance()
def get_stale_team(stale_timespan):
""" Returns a team that is setup to sync to an external group, and who has not been synced in
now - stale_timespan. Returns None if none found.
"""
stale_at = datetime.now() - stale_timespan
try:
candidates = (TeamSync
.select(TeamSync.id)
.where((TeamSync.last_updated <= stale_at) | (TeamSync.last_updated >> None))
.limit(500)
.alias('candidates'))
found = (TeamSync
.select(candidates.c.id)
.from_(candidates)
.order_by(db_random_func())
.get())
if found is None:
return
return TeamSync.select(TeamSync, Team).join(Team).where(TeamSync.id == found.id).get()
except TeamSync.DoesNotExist:
return None
def get_team_sync_information(orgname, teamname):
""" Returns the team syncing information for the team with the given name under the organization
with the given name or None if none.
@ -400,3 +466,28 @@ def get_team_sync_information(orgname, teamname):
return query.get()
except TeamSync.DoesNotExist:
return None
def update_sync_status(team_sync_info):
""" Attempts to update the transaction ID and last updated time on a TeamSync object. If the
transaction ID on the entry in the DB does not match that found on the object, this method
returns False, which indicates another caller updated it first.
"""
new_transaction_id = str(uuid.uuid4())
query = (TeamSync
.update(transaction_id=new_transaction_id, last_updated=datetime.now())
.where(TeamSync.id == team_sync_info.id,
TeamSync.transaction_id == team_sync_info.transaction_id))
return query.execute() == 1
def delete_members_not_present(team, member_id_set):
""" Deletes all members of the given team that are not found in the member ID set. """
with db_transaction():
user_ids = set([u.id for u in list_team_users(team)])
to_delete = list(user_ids - member_id_set)
if to_delete:
query = TeamMember.delete().where(TeamMember.team == team, TeamMember.user << to_delete)
return query.execute()
return 0