Initial interfaces and support for team syncing worker
This commit is contained in:
parent
94b07e6de9
commit
eeadeb9383
12 changed files with 282 additions and 15 deletions
|
@ -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
|
||||
|
|
Reference in a new issue