Skip to content

Commit

Permalink
Updates; remove rename branch code
Browse files Browse the repository at this point in the history
  • Loading branch information
jeffwilcox committed Aug 15, 2023
1 parent 682553a commit e165cb1
Show file tree
Hide file tree
Showing 55 changed files with 3,104 additions and 3,264 deletions.
7 changes: 7 additions & 0 deletions .cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
".git/",
".environment/**",
"**/jitStaticConfiguration.json",
"**/*Accounts.json",
"**/sentiment/**",
"**/thirdparty/**",
"**/vendor/**",
Expand All @@ -23,6 +24,8 @@
"enableGlobDot": true,
"useGitignore": true,
"words": [
"1es",
"1escopilot",
"aadgraph",
"aadid",
"aadname",
Expand Down Expand Up @@ -149,6 +152,7 @@
"copilotagreement",
"copilotrequest",
"Copybara",
"corpnet",
"corporatealias",
"corporatecount",
"corporatedev",
Expand All @@ -174,6 +178,7 @@
"DATETIME",
"dbaeumer",
"dcount",
"deadcode",
"decisionmaker",
"Decisionmaker",
"Decisionmakers",
Expand Down Expand Up @@ -583,6 +588,7 @@
"pmownerid",
"popd",
"portaldescription",
"portaldev",
"portalppe",
"portalprod",
"portalwestus",
Expand Down Expand Up @@ -788,6 +794,7 @@
"unadopted",
"unarchived",
"Unauthoritative",
"Uncommited",
"unconfigured",
"Unconfigured",
"unconfirmedorganizationname",
Expand Down
1 change: 1 addition & 0 deletions .gitignore
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
Expand Down
3 changes: 2 additions & 1 deletion .markdownlint-cli2.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
"MD024": {
"allow_different_nesting": true
},
"MD026": false
"MD026": false,
"MD033": false // no inline HTML: we use inline HTML for expandable details sections
},
"ignores": ["**/node_modules/**"]
}
3 changes: 2 additions & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,8 @@
"console": "integratedTerminal",
"env": {
"NODE_ENV": "localhost",
"DEBUG": "startup"
"DEBUG": "startup",
"EXIT_IMMEDIATELY": "1"
}
},
{
Expand Down
74 changes: 74 additions & 0 deletions api/client/context/administration/app.ts
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;
59 changes: 59 additions & 0 deletions api/client/context/administration/appInstallation.ts
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;
128 changes: 128 additions & 0 deletions api/client/context/administration/apps.ts
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;
3 changes: 3 additions & 0 deletions api/client/context/administration/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import getCompanySpecificDeployment from '../../../../middleware/companySpecific
import { ErrorHelper, getProviders } from '../../../../transitional';

import routeIndividualOrganization from './organization';
import routeApps from './apps';

const router: Router = Router();

Expand Down Expand Up @@ -49,6 +50,8 @@ router.use((req: IRequestWithAdministration, res: Response, next: NextFunction)
return req.isSystemAdministrator ? next() : next(jsonError('Not authorized', 403));
});

router.use('/apps', routeApps);

router.use(
'/organization/:orgName',
asyncHandler(async (req: ReposAppRequest, res: Response, next: NextFunction) => {
Expand Down
Loading

0 comments on commit e165cb1

Please sign in to comment.