async def _check_reposet( request: AthenianWebRequest, sdb_conn: Optional[databases.core.Connection], account: int, body: List[str], ) -> List[str]: service = None repos = set() for repo in body: for key, prefix in PREFIXES.items(): if repo.startswith(prefix): if service is None: service = key elif service != key: raise ResponseError( BadRequestError(detail="mixed services: %s, %s" % (service, key), )) repos.add(repo[len(prefix):]) if service is None: raise ResponseError( BadRequestError( detail= "repository prefixes do not match to any supported service", )) checker = await access_classes[service](account, sdb_conn, request.mdb, request.cache).load() denied = await checker.check(repos) if denied: raise ResponseError( ForbiddenError( detail="the following repositories are access denied for %s: %s" % (service, denied), )) return sorted(set(body))
async def create_reposet(request: AthenianWebRequest, body: dict) -> web.Response: """Create a repository set. :param body: List of repositories to group. """ body = RepositorySetCreateRequest.from_dict(body) user = request.uid account = body.account async with request.sdb.connection() as sdb_conn: try: adm = await get_user_account_status(user, account, sdb_conn, request.cache) except ResponseError as e: return e.response if not adm: return ResponseError( ForbiddenError( detail="User %s is not an admin of the account %d" % (user, account))).response try: items = await _check_reposet(request, sdb_conn, body.account, body.items) except ResponseError as e: return e.response rs = RepositorySet(owner=account, items=items).create_defaults() rid = await sdb_conn.execute( insert(RepositorySet).values(rs.explode())) return response(CreatedIdentifier(rid))
async def update_reposet(request: AthenianWebRequest, id: int, body: List[str]) -> web.Response: """Update a repository set. :param id: Numeric identifier of the repository set to update. :type id: int :param body: New list of repositories in the group. """ async with request.sdb.connection() as sdb_conn: try: rs, is_admin = await fetch_reposet(id, [RepositorySet], request.uid, sdb_conn, request.cache) except ResponseError as e: return e.response if not is_admin: return ResponseError( ForbiddenError(detail="User %s may not modify reposet %d" % (request.uid, id))).response try: body = await _check_reposet(request, sdb_conn, id, body) except ResponseError as e: return e.response rs.items = body rs.refresh() await sdb_conn.execute( update(RepositorySet).where(RepositorySet.id == id).values( rs.explode())) return web.json_response(body, status=200)
async def _resolve_repos( filt: Union[FilterContribsOrReposRequest, FilterPullRequestsRequest], uid: str, native_uid: str, sdb_conn: Union[databases.core.Connection, databases.Database], mdb_conn: Union[databases.core.Connection, databases.Database], cache: Optional[aiomcache.Client], ) -> List[str]: status = await sdb_conn.fetch_one( select([UserAccount.is_admin]).where( and_(UserAccount.user_id == uid, UserAccount.account_id == filt.account))) if status is None: raise ResponseError( ForbiddenError(detail="User %s is forbidden to access account %d" % (uid, filt.account))) check_access = True if not filt.in_: rss = await load_account_reposets(filt.account, native_uid, [RepositorySet.id], sdb_conn, mdb_conn, cache) filt.in_ = ["{%d}" % rss[0][RepositorySet.id.key]] check_access = False repos = set( chain.from_iterable(await asyncio.gather(*[ resolve_reposet(r, ".in[%d]" % i, uid, filt.account, sdb_conn, cache) for i, r in enumerate(filt.in_) ]))) prefix = "github.com/" repos = [r[r.startswith(prefix) and len(prefix):] for r in repos] if check_access: checker = await access_classes["github"](filt.account, sdb_conn, mdb_conn, cache).load() denied = await checker.check(set(repos)) if denied: raise ResponseError( ForbiddenError( detail= "the following repositories are access denied for %s: %s" % ("github.com/", denied), )) return repos
async def delete_reposet(request: AthenianWebRequest, id: int) -> web.Response: """Delete a repository set. :param id: Numeric identifier of the repository set to delete. :type id: int """ try: _, is_admin = await fetch_reposet(id, [], request.uid, request.sdb, request.cache) except ResponseError as e: return e.response if not is_admin: return ResponseError( ForbiddenError(detail="User %s may not modify reposet %d" % (request.uid, id))).response await request.sdb.execute( delete(RepositorySet).where(RepositorySet.id == id)) return web.Response(status=200)
async def get_account(request: AthenianWebRequest, id: int) -> web.Response: """Return details about the current account.""" user_id = request.uid users = await request.sdb.fetch_all( select([UserAccount]).where(UserAccount.account_id == id)) for user in users: if user[UserAccount.user_id.key] == user_id: break else: return ResponseError( ForbiddenError( detail="User %s is not allowed to access account %d" % (user_id, id))).response admins = [] regulars = [] for user in users: role = admins if user[UserAccount.is_admin.key] else regulars role.append(user[UserAccount.user_id.key]) users = await request.auth.get_users(regulars + admins) account = Account(regulars=[users[k] for k in regulars if k in users], admins=[users[k] for k in admins if k in users]) return response(account)
async def resolve_reposet( repo: str, pointer: str, uid: str, account: int, db: Union[databases.core.Connection, databases.Database], cache: Optional[aiomcache.Client], ) -> List[str]: """ Dereference the repository sets. If `repo` is a regular repository, return `[repo]`. Otherwise, return the list of \ repositories by the parsed ID from the database. """ if not repo.startswith("{"): return [repo] if not repo.endswith("}"): raise ResponseError( InvalidRequestError( detail="repository set format is invalid: %s" % repo, pointer=pointer, )) try: set_id = int(repo[1:-1]) except ValueError: raise ResponseError( InvalidRequestError( detail="repository set identifier is invalid: %s" % repo, pointer=pointer, )) rs, _ = await fetch_reposet(set_id, [RepositorySet.items], uid, db, cache) if rs.owner != account: raise ResponseError( ForbiddenError( detail= "User %s is not allowed to reference reposet %d in this query" % (uid, set_id))) return rs.items
async def become_user(request: AthenianWebRequest, id: str = "") -> web.Response: """God mode ability to turn into any user. The current user must be marked internally as \ a super admin.""" user_id = getattr(request, "god_id", None) if user_id is None: return ResponseError( ForbiddenError(detail="User %s is not allowed to mutate" % user_id)).response async with request.sdb.connection() as conn: if id and (await conn.fetch_one( select([UserAccount]).where(UserAccount.user_id == id) )) is None: return ResponseError( NotFoundError(detail="User %s does not exist" % id)).response god = await conn.fetch_one(select([God]).where(God.user_id == user_id)) god = God(**god).refresh() god.mapped_id = id or None await conn.execute( update(God).where(God.user_id == user_id).values(god.explode())) user = await (await request.auth.get_user(id or user_id)).load_accounts(request.sdb) return response(user)