-
Notifications
You must be signed in to change notification settings - Fork 124
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
682553a
commit e165cb1
Showing
55 changed files
with
3,104 additions
and
3,264 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
dist/ | ||
node_modules/ | ||
.DS_Store | ||
reports/ | ||
|
||
# Potential local development environment scripts | ||
app.yaml | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
// | ||
// Copyright (c) Microsoft. | ||
// Licensed under the MIT license. See LICENSE file in the project root for full license information. | ||
// | ||
|
||
import { NextFunction, Response, Router } from 'express'; | ||
import asyncHandler from 'express-async-handler'; | ||
|
||
import { ReposAppRequest } from '../../../../interfaces'; | ||
import { CreateError, getProviders } from '../../../../transitional'; | ||
|
||
import routeIndividualApp from './app'; | ||
import GitHubApplication from '../../../../business/application'; | ||
import { OrganizationSetting } from '../../../../entities/organizationSettings/organizationSetting'; | ||
import { sortByCaseInsensitive } from '../../../../utils'; | ||
import routeApplicationInstallation from './appInstallation'; | ||
import { ApiRequestWithGitHubApplication, RequestWithInstallation } from './types'; | ||
|
||
const router: Router = Router(); | ||
|
||
router.get( | ||
'/', | ||
asyncHandler(async function (req: ApiRequestWithGitHubApplication, res: Response, next: NextFunction) { | ||
const { gitHubApplication } = req; | ||
const installationIdString = req.query.installation_id; | ||
const setupAction = req.query.setup_action; | ||
// if (installationIdString && setupAction) { | ||
// return res.redirect( | ||
// `./${githubApplication.id}/installations/${installationIdString}?setup_action=${setupAction}` | ||
// ); | ||
// } | ||
// const individualContext = req.individualContext; | ||
const allInstalls = await gitHubApplication.getInstallations({ maxAgeSeconds: 5 }); | ||
const { valid, invalid } = GitHubApplication.filterInstallations(allInstalls); | ||
return res.json({ | ||
state: { | ||
installations: { | ||
valid, | ||
invalid, | ||
}, | ||
app: gitHubApplication.asClientJson(), | ||
}, | ||
}) as unknown as void; | ||
}) | ||
); | ||
|
||
router.use( | ||
'/installations/:installationId', | ||
asyncHandler(async function (req: RequestWithInstallation, res, next) { | ||
// const installationIdString = req.query.installation_id; | ||
// const setupAction = req.query.setup_action; | ||
const { gitHubApplication } = req; | ||
const { installationId: installationIdAsString } = req.params; | ||
const installationId = Number(installationIdAsString); | ||
const installation = await gitHubApplication.getInstallation(installationId); | ||
if (!installation) { | ||
return next( | ||
CreateError.NotFound( | ||
`The GitHub app installation ${installationIdAsString} could not be found for app ${gitHubApplication.id}` | ||
) | ||
); | ||
} | ||
req.installation = installation; | ||
return next(); | ||
}) | ||
); | ||
|
||
router.use('/installations/:installationId', routeApplicationInstallation); | ||
|
||
router.use('*', (req, res: Response, next: NextFunction) => { | ||
return next(CreateError.NotFound('no API or function available: context/administration/apps/...')); | ||
}); | ||
|
||
export default router; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
// | ||
// Copyright (c) Microsoft. | ||
// Licensed under the MIT license. See LICENSE file in the project root for full license information. | ||
// | ||
|
||
import { NextFunction, Response, Router } from 'express'; | ||
import asyncHandler from 'express-async-handler'; | ||
|
||
import { CreateError, getProviders } from '../../../../transitional'; | ||
import { OrganizationSetting } from '../../../../entities/organizationSettings/organizationSetting'; | ||
import { AdministrativeGitHubAppInstallationResponse, RequestWithInstallation } from './types'; | ||
|
||
const router: Router = Router(); | ||
|
||
router.use( | ||
asyncHandler(async function (req: RequestWithInstallation, res: Response, next: NextFunction) { | ||
const { operations, organizationSettingsProvider } = getProviders(req); | ||
|
||
const { installation } = req; | ||
const organizationId = installation.account.id; | ||
const organizationName = installation.account.login; | ||
let settings: OrganizationSetting = null; | ||
try { | ||
settings = await organizationSettingsProvider.getOrganizationSetting(organizationId.toString()); | ||
} catch (notFound) { | ||
/* ignored */ | ||
} | ||
req.organizationDynamicSettings = settings; | ||
|
||
const staticSettings = operations.getOrganizationSettings(organizationName); | ||
req.organizationStaticSettings = staticSettings; | ||
|
||
return next(); | ||
}) | ||
); | ||
|
||
router.get( | ||
'/', | ||
asyncHandler(async (req: RequestWithInstallation, res: Response, next: NextFunction) => { | ||
const { gitHubApplication, installation, organizationDynamicSettings, organizationStaticSettings } = req; | ||
const response: AdministrativeGitHubAppInstallationResponse = { | ||
app: gitHubApplication.asClientJson(), | ||
// installation, | ||
installationId: installation.id, | ||
dynamicSettings: organizationDynamicSettings, | ||
}; | ||
return res.json(response) as unknown as void; | ||
}) | ||
); | ||
|
||
router.use('*', (req, res: Response, next: NextFunction) => { | ||
return next( | ||
CreateError.NotFound( | ||
'no API or function available: context/administration/apps/:appId/installations/:installationId' | ||
) | ||
); | ||
}); | ||
|
||
export default router; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
// | ||
// Copyright (c) Microsoft. | ||
// Licensed under the MIT license. See LICENSE file in the project root for full license information. | ||
// | ||
|
||
import { NextFunction, Response, Router } from 'express'; | ||
import asyncHandler from 'express-async-handler'; | ||
|
||
import { ReposAppRequest } from '../../../../interfaces'; | ||
import { CreateError, getProviders } from '../../../../transitional'; | ||
|
||
import routeIndividualApp from './app'; | ||
import GitHubApplication from '../../../../business/application'; | ||
import { sortByCaseInsensitive } from '../../../../utils'; | ||
import { | ||
ApiRequestWithGitHubApplication, | ||
ManagedOrganizationAppConfigurationsByOrgView, | ||
ManagedOrganizationStatus, | ||
} from './types'; | ||
|
||
const router: Router = Router(); | ||
|
||
router.get( | ||
'/', | ||
asyncHandler(async (req: ReposAppRequest, res: Response) => { | ||
const { operations, organizationSettingsProvider } = getProviders(req); | ||
const apps = operations.getApplications(); | ||
const byOrg = new Map<string, ManagedOrganizationAppConfigurationsByOrgView>(); | ||
function getOrg(name: string) { | ||
let o = byOrg.get(name); | ||
if (!o) { | ||
o = { | ||
organizationName: name, | ||
id: undefined, | ||
status: ManagedOrganizationStatus.NotAdopted, | ||
appInstallations: new Map(), | ||
dynamicSettings: null, | ||
configuredInstallations: [], | ||
}; | ||
for (const app of apps) { | ||
o.appInstallations.set(app.id, null); | ||
} | ||
byOrg.set(name, o); | ||
} | ||
return o; | ||
} | ||
for (const app of apps) { | ||
const appInstalls = await app.getInstallations({ maxAgeSeconds: 5 }); | ||
const { valid: validInstallations } = GitHubApplication.filterInstallations(appInstalls); | ||
for (const valid of validInstallations) { | ||
const organizationName = valid.account.login; | ||
const o = getOrg(organizationName.toLowerCase()); | ||
o.appInstallations.set(app.id, { | ||
app, | ||
installationId: valid.id, | ||
}); | ||
o.id = Number(valid.target_id); | ||
if (!o.dynamicSettings && valid.target_type === 'Organization') { | ||
try { | ||
o.dynamicSettings = await organizationSettingsProvider.getOrganizationSetting( | ||
valid.target_id.toString() | ||
); | ||
} catch (ignore) { | ||
/* ignored */ | ||
} | ||
if (o.dynamicSettings) { | ||
o.configuredInstallations = o.dynamicSettings.installations.map( | ||
(install) => install.installationId | ||
); | ||
o.status = ManagedOrganizationStatus.Adopted; | ||
} | ||
if (o.dynamicSettings && o.dynamicSettings.active === true) { | ||
o.status = ManagedOrganizationStatus.Active; | ||
} | ||
} | ||
} | ||
} | ||
for (const organization of operations.organizations.values()) { | ||
const anOrg = getOrg(organization.name.toLowerCase()); | ||
anOrg.id = organization.id; | ||
} | ||
const orgNames = Array.from(byOrg.keys()).sort(sortByCaseInsensitive); | ||
return res.json({ | ||
apps: apps.map((app) => app.asClientJson()), | ||
orgNames, | ||
orgs: Array.from(byOrg.values()).map((data) => { | ||
return { | ||
name: data.organizationName, | ||
status: data.status, | ||
id: data.id, | ||
configuredInstallations: data.configuredInstallations, | ||
hasDynamicSettings: !!data.dynamicSettings, | ||
appInstallations: Array.from(data.appInstallations.keys()) | ||
.filter((a) => a) | ||
.map((appIdKey) => { | ||
const install = data.appInstallations.get(appIdKey); | ||
return { | ||
installationId: install?.installationId, | ||
appId: install?.app?.id, | ||
}; | ||
}), | ||
}; | ||
}), | ||
}) as unknown as void; | ||
}) | ||
); | ||
|
||
router.use( | ||
'/:appId', | ||
asyncHandler(async function (req: ApiRequestWithGitHubApplication, res: Response, next: NextFunction) { | ||
const { operations } = getProviders(req); | ||
const appId = Number(req.params.appId); | ||
const app = operations.getApplicationById(appId); | ||
if (app) { | ||
req.gitHubApplication = app; | ||
return next(); | ||
} | ||
return next(CreateError.NotFound('no app available with that ID')); | ||
}) | ||
); | ||
|
||
router.use('/:appId', routeIndividualApp); | ||
|
||
router.use('*', (req, res: Response, next: NextFunction) => { | ||
return next(CreateError.NotFound('no API or function available: context/administration/apps')); | ||
}); | ||
|
||
export default router; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.