in api/createRepo.ts [409:571]
async function sendEmail(req: IReposAppRequestWithCreateResponse, logic: ICustomizedNewRepositoryLogic, createContext: INewRepositoryContext, mailProvider: IMailProvider, apiKeyRow, correlationId: string, repoCreateResults, approvalRequest: RepositoryMetadataEntity, msProperties, existingRepoId: any, repository: Repository, createdUserLink: ICorporateLink): Promise<void> {
const { config, insights, viewServices } = getProviders(req);
const deployment = getCompanySpecificDeployment();
const emailTemplate = deployment?.views?.email?.repository?.new || defaultMailView;
const excludeNotificationsValue = config.notifications?.reposNotificationExcludeForUsers;
const operations = repository.organization.operations;
let excludeNotifications = [];
if (excludeNotificationsValue) {
excludeNotifications = excludeNotificationsValue.split(',');
}
if (approvalRequest.createdByCorporateUsername && excludeNotifications && excludeNotifications.includes(approvalRequest.createdByCorporateUsername.toLowerCase())) {
return;
}
const emails = (msProperties?.notify && (msProperties.notify as string).split(',')) || [];
getAdditionalNotificationEmails(repository).filter(email => email).map(email => {
if (!emails.includes(email)) {
emails.push(email);
}
});
let targetType = repoCreateResults.fork ? 'Fork' : 'Repo';
if (!repoCreateResults.fork && approvalRequest.transferSource) {
targetType = 'Transfer';
}
let managerInfo: ICachedEmployeeInformation = null;
if (operations.hasCapability(CoreCapability.Hiearchy) && approvalRequest.createdByCorporateId) {
try {
const opsHierarchy = operationsWithCapability<IOperationsHierarchy>(operations, CoreCapability.Hiearchy);
managerInfo = await opsHierarchy.getCachedEmployeeManagementInformation(approvalRequest.createdByCorporateId);
} catch (ignoreError) {
console.dir(ignoreError);
}
}
let headline = `${targetType} ready`;
const serviceShortName = apiKeyRow && apiKeyRow.service ? apiKeyRow.service : undefined;
let subject = serviceShortName ? `${approvalRequest.repositoryName} ${targetType.toLowerCase()} created by ${serviceShortName}` : `${approvalRequest.repositoryName} ${targetType.toLowerCase()} created`;
if (existingRepoId) {
subject = `${approvalRequest.repositoryName} ${targetType.toLowerCase()} ready`;
}
const displayHostname = req.hostname;
const approvalScheme = displayHostname === 'localhost' && config.webServer.allowHttp === true ? 'http' : 'https';
const reposSiteBaseUrl = `${approvalScheme}://${displayHostname}/`;
if (repository) {
try {
await repository.getDetails();
} catch (getDetailsErrorIgnored) {
console.dir(getDetailsErrorIgnored);
}
}
let additionalViewProperties: ICustomizedNewRepoProperties = null;
try {
if (createContext && logic) {
additionalViewProperties = await logic.getNewMailViewProperties(createContext, repository);
}
} catch (err) {
insights?.trackException({ exception: err });
console.warn(err);
}
const mail = {
to: [...emails, ...additionalViewProperties?.to],
cc: additionalViewProperties?.cc,
bcc: additionalViewProperties?.bcc,
subject,
correlationId,
content: undefined,
};
if (managerInfo && managerInfo.managerMail) {
let shouldSend = true;
if (createContext && logic) {
shouldSend = logic.shouldNotifyManager(createContext, approvalRequest.createdByCorporateId);
}
if (shouldSend) {
if (mail.cc) {
mail.cc.push(managerInfo.managerMail);
} else {
mail.cc = [managerInfo.managerMail];
}
}
}
const skuName = operations.hasCapability(CoreCapability.GitHubRestApi) ? operationsWithCapability<IOperationsGitHubRestLibrary>(operations, CoreCapability.GitHubRestApi).githubSkuName : 'GitHub';
const app = config.brand?.companyName ? `${config.brand.companyName} ${skuName}` : skuName;
const contentOptions = Object.assign(additionalViewProperties?.viewProperties || {} /* allow a custom provider to override */, {
reason: `You are receiving this e-mail because the new repository request included the e-mail notification address(es) ${msProperties.notify}, or, you are the manager of the person who created the repo.`,
headline,
notification: 'information',
app,
correlationId,
approvalRequest, // old name
repositoryMetadataEntity: approvalRequest,
repository,
organization: repository ? repository.organization : null,
createdUserLink,
existingRepoId,
results: repoCreateResults,
version: config.logging.version,
managerInfo,
reposSiteUrl: reposSiteBaseUrl,
liveReposSiteUrl: config.urls ? config.urls.repos : null,
api: serviceShortName, // when used by the client single-page app, this is not considered an API call
service: serviceShortName,
serviceOwner: apiKeyRow ? apiKeyRow.owner : undefined,
serviceDescription: apiKeyRow ? apiKeyRow.description : undefined,
viewServices,
isNotBootstrap: true,
});
try {
mail.content = await RenderHtmlMail(config.typescript.appDirectory, emailTemplate, contentOptions);
} catch (renderError) {
req.insights.trackException({
exception: renderError,
properties: {
content: contentOptions,
eventName: 'ApiRepoCreateMailRenderFailure',
},
});
throw renderError;
}
const customData = {
content: contentOptions,
receipt: null,
eventName: undefined,
};
const additionalMail = { ...mail };
try {
insights?.trackEvent({
name: 'ApiRepoSendMail', properties: {
to: JSON.stringify(mail.to || ''),
cc: JSON.stringify(mail.to || ''),
bcc: JSON.stringify(mail.to || ''),
}
});
customData.receipt = await mailProvider.sendMail(mail);
insights?.trackEvent({ name: 'ApiRepoCreateMailSuccess', properties: customData });
req.repoCreateResponse.notified = emails;
} catch (mailError) {
customData.eventName = 'ApiRepoCreateMailFailure';
insights?.trackException({ exception: mailError, properties: customData });
}
// send to operations, too
delete additionalMail.cc;
let notifyMailAddress: string = null;
const skipAdditionalSend = config?.notifications?.skipDedicatedNewRepoMail;
if (operations.hasCapability(CoreCapability.Notifications)) {
const opsNotifications = operationsWithCapability<IOperationsNotifications>(operations, CoreCapability.Notifications);
notifyMailAddress = opsNotifications.getRepositoriesNotificationMailAddress();
}
const operationsMails = notifyMailAddress ? [notifyMailAddress] : [];
if (!skipAdditionalSend && operationsMails && operationsMails.length) {
additionalMail.to = operationsMails;
contentOptions.reason = `You are receiving this e-mail as the operations contact address(es) ${operationsMails.join(', ')}. A repo has been created or classified.`;
try {
additionalMail.content = await RenderHtmlMail(config.typescript.appDirectory, emailTemplate, contentOptions);
} catch (renderError) {
console.dir(renderError);
return;
}
try {
await mailProvider.sendMail(additionalMail);
} catch (ignoredError) {
console.dir(ignoredError);
return;
}
}
}