mirror of
https://github.com/matrix-org/matrix-hookshot.git
synced 2025-03-10 21:19:13 +00:00
Add APIs for checking the state of GitHub
This commit is contained in:
parent
fb6fdd548d
commit
4eb48afa21
@ -133,7 +133,7 @@ export class Bridge {
|
||||
}
|
||||
if (this.config.github) {
|
||||
routers.push({
|
||||
route: "/v1/jira",
|
||||
route: "/v1/github",
|
||||
router: new GitHubProvisionerRouter(this.config.github, this.tokenStore).getRouter(),
|
||||
});
|
||||
}
|
||||
|
@ -1,8 +1,30 @@
|
||||
import { Router, Request, Response } from "express";
|
||||
import { Router, Request, Response, NextFunction } from "express";
|
||||
import { BridgeConfigGitHub } from "../Config/Config";
|
||||
import { ApiError, ErrCode } from "../provisioning/api";
|
||||
import { UserTokenStore } from "../UserTokenStore";
|
||||
import { generateGitHubOAuthUrl } from "./AdminCommands";
|
||||
import LogWrapper from "../LogWrapper";
|
||||
|
||||
const log = new LogWrapper("GitHubProvisionerRouter");
|
||||
interface GitHubAccountStatus {
|
||||
loggedIn: boolean;
|
||||
organisations?: {
|
||||
name: string;
|
||||
avatarUrl: string;
|
||||
}[]
|
||||
}
|
||||
interface GitHubRepoItem {
|
||||
name: string;
|
||||
owner: string;
|
||||
fullName: string;
|
||||
description: string|null;
|
||||
avatarUrl: string;
|
||||
}
|
||||
|
||||
interface GitHubRepoResponse {
|
||||
page: number;
|
||||
repositories: GitHubRepoItem[];
|
||||
}
|
||||
|
||||
export class GitHubProvisionerRouter {
|
||||
constructor(private readonly config: BridgeConfigGitHub, private readonly tokenStore: UserTokenStore) { }
|
||||
@ -10,6 +32,9 @@ export class GitHubProvisionerRouter {
|
||||
public getRouter() {
|
||||
const router = Router();
|
||||
router.get("/oauth", this.onOAuth.bind(this));
|
||||
router.get("/account", this.onGetAccount.bind(this));
|
||||
router.get("/orgs/:orgName/repositories", this.onGetOrgRepositories.bind(this));
|
||||
router.get("/repositories", this.onGetRepositories.bind(this));
|
||||
return router;
|
||||
}
|
||||
|
||||
@ -21,4 +46,96 @@ export class GitHubProvisionerRouter {
|
||||
url: generateGitHubOAuthUrl(this.config.oauth.client_id, this.config.oauth.redirect_uri, this.tokenStore.createStateForOAuth(req.query.userId))
|
||||
});
|
||||
}
|
||||
|
||||
private async onGetAccount(req: Request<undefined, undefined, undefined, {userId: string, page: string, perPage: string}>, res: Response<GitHubAccountStatus>, next: NextFunction) {
|
||||
const octokit = await this.tokenStore.getOctokitForUser(req.query.userId);
|
||||
if (!octokit) {
|
||||
return res.send({
|
||||
loggedIn: false,
|
||||
});
|
||||
}
|
||||
const organisations = [];
|
||||
const page = req.query.page ? parseInt(req.query.page) : 1;
|
||||
const perPage = req.query.perPage ? parseInt(req.query.perPage) : 10;
|
||||
try {
|
||||
const orgRes = await octokit.orgs.listForAuthenticatedUser({page, per_page: perPage});
|
||||
for (const org of orgRes.data) {
|
||||
organisations.push({
|
||||
name: org.login,
|
||||
avatarUrl: org.avatar_url,
|
||||
});
|
||||
}
|
||||
} catch (ex) {
|
||||
log.warn(`Failed to fetch orgs for GitHub user ${req.query.userId}`, ex);
|
||||
return next( new ApiError("Could not fetch orgs for GitHub user", ErrCode.Unknown));
|
||||
}
|
||||
return res.send({
|
||||
loggedIn: true,
|
||||
organisations,
|
||||
})
|
||||
}
|
||||
|
||||
private async onGetOrgRepositories(req: Request<{orgName: string}, undefined, undefined, {userId: string, page: string, perPage: string}>, res: Response<GitHubRepoResponse>, next: NextFunction) {
|
||||
const octokit = await this.tokenStore.getOctokitForUser(req.query.userId);
|
||||
if (!octokit) {
|
||||
// TODO: Better error?
|
||||
return next(new ApiError("Not logged in", ErrCode.ForbiddenUser));
|
||||
}
|
||||
|
||||
const repositories = [];
|
||||
const page = req.query.page ? parseInt(req.query.page) : 1;
|
||||
const perPage = req.query.perPage ? parseInt(req.query.perPage) : 10;
|
||||
try {
|
||||
const orgRes = await octokit.repos.listForOrg({org: req.params.orgName, page, per_page: perPage});
|
||||
for (const repo of orgRes.data) {
|
||||
repositories.push({
|
||||
name: repo.name,
|
||||
owner: repo.owner.login,
|
||||
fullName: repo.full_name,
|
||||
description: repo.description,
|
||||
avatarUrl: repo.owner.avatar_url,
|
||||
});
|
||||
}
|
||||
|
||||
return res.send({
|
||||
page,
|
||||
repositories,
|
||||
});
|
||||
} catch (ex) {
|
||||
log.warn(`Failed to fetch accessible repos for ${req.params.orgName} / ${req.query.userId}`, ex);
|
||||
return next(new ApiError("Could not fetch accessible repos for GitHub org", ErrCode.Unknown));
|
||||
}
|
||||
}
|
||||
|
||||
private async onGetRepositories(req: Request<undefined, undefined, undefined, {userId: string, page: string, perPage: string}>, res: Response<GitHubRepoResponse>, next: NextFunction) {
|
||||
const octokit = await this.tokenStore.getOctokitForUser(req.query.userId);
|
||||
if (!octokit) {
|
||||
// TODO: Better error?
|
||||
return next(new ApiError("Not logged in", ErrCode.ForbiddenUser));
|
||||
}
|
||||
|
||||
const repositories = [];
|
||||
const page = req.query.page ? parseInt(req.query.page) : 1;
|
||||
const perPage = req.query.perPage ? parseInt(req.query.perPage) : 10;
|
||||
try {
|
||||
const orgRes = await octokit.repos.listForAuthenticatedUser({page, per_page: perPage, type: "member"});
|
||||
for (const repo of orgRes.data) {
|
||||
repositories.push({
|
||||
name: repo.name,
|
||||
owner: repo.owner.login,
|
||||
fullName: repo.full_name,
|
||||
description: repo.description,
|
||||
avatarUrl: repo.owner.avatar_url,
|
||||
});
|
||||
}
|
||||
|
||||
return res.send({
|
||||
page,
|
||||
repositories,
|
||||
});
|
||||
} catch (ex) {
|
||||
log.warn(`Failed to fetch accessible repos for ${req.query.userId}`, ex);
|
||||
return next(new ApiError("Could not fetch accessible repos for GitHub user", ErrCode.Unknown));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -178,6 +178,69 @@ the bridge will be granted access.
|
||||
}]
|
||||
```
|
||||
|
||||
### GET /github/v1/account?userId={userId}
|
||||
|
||||
Request the status of the users account. This will return a `loggedIn` value to determine if the
|
||||
bridge has a GitHub identity stored for the user, and any organisations they have access to.
|
||||
|
||||
### Response
|
||||
|
||||
```json5
|
||||
{
|
||||
"loggedIn": true,
|
||||
"organisations": {
|
||||
"name": "half-shot",
|
||||
"avatarUrl": "https://avatars.githubusercontent.com/u/8418310?v=4"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### GET /github/v1/orgs/{orgName}/repositories?userId={userId}&page={page}&perPage={perPage}
|
||||
|
||||
Request a list of all repositories a user is a member of in the given org. The `owner` and `name` value of a repository can be given to create a new GitHub connection.
|
||||
|
||||
This request is paginated, and `page` sets the page (defaults to `1`) while `perPage` (defaults to `10`) sets the number of entries per page.
|
||||
|
||||
This request can be retried until the number of entries is less than the value of `perPage`.
|
||||
|
||||
### Response
|
||||
|
||||
```json5
|
||||
{
|
||||
"loggedIn": true,
|
||||
"repositories": {
|
||||
"name": "matrix-hookshot",
|
||||
"owner": "half-shot",
|
||||
"fullName": "half-shot/matrix-hookshot",
|
||||
"avatarUrl": "https://avatars.githubusercontent.com/u/8418310?v=4",
|
||||
"description": "A bridge between Matrix and multiple project management services, such as GitHub, GitLab and JIRA. "
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### GET /github/v1/repositories?userId={userId}&page={page}&perPage={perPage}
|
||||
|
||||
Request a list of all repositories a user is a member of (including those not belonging to an org). The `owner` and `name` value of a repository can be given to create a new GitHub connection.
|
||||
|
||||
This request is paginated, and `page` sets the page (defaults to `1`) while `perPage` (defaults to `10`) sets the number of entries per page.
|
||||
|
||||
This request can be retried until the number of entries is less than the value of `perPage`.
|
||||
|
||||
### Response
|
||||
|
||||
```json5
|
||||
{
|
||||
"loggedIn": true,
|
||||
"repositories": {
|
||||
"name": "matrix-hookshot",
|
||||
"owner": "half-shot",
|
||||
"fullName": "half-shot/matrix-hookshot",
|
||||
"avatarUrl": "https://avatars.githubusercontent.com/u/8418310?v=4",
|
||||
"description": "A bridge between Matrix and multiple project management services, such as GitHub, GitLab and JIRA. "
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## JIRA
|
||||
|
||||
|
||||
@ -229,3 +292,4 @@ a new JIRA connection.
|
||||
"id": "10015"
|
||||
}
|
||||
}
|
||||
```
|
Loading…
x
Reference in New Issue
Block a user