check-communicable.ts 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. import { WebClient } from '@slack/web-api';
  2. import axios, { AxiosError } from 'axios';
  3. import { ConnectionStatus } from '../interfaces/connection-status';
  4. import { markdownSectionBlock } from './block-kit-builder';
  5. import { requiredScopes } from './required-scopes';
  6. import { generateWebClient } from './webclient-factory';
  7. /**
  8. * Check whether the HTTP server responds or not.
  9. *
  10. * @param serverUri Server URI to connect
  11. * @returns AxiosError when error is occured
  12. */
  13. export const connectToHttpServer = async(serverUri: string): Promise<void|AxiosError> => {
  14. try {
  15. await axios.get(serverUri, { maxRedirects: 0, timeout: 3000 });
  16. }
  17. catch (err) {
  18. return err as AxiosError;
  19. }
  20. };
  21. /**
  22. * Check whether the Slack API server responds or not.
  23. *
  24. * @returns AxiosError when error is occured
  25. */
  26. export const connectToSlackApiServer = async(): Promise<void|AxiosError> => {
  27. return connectToHttpServer('https://slack.com/api/');
  28. };
  29. /**
  30. * Test Slack API
  31. * @param client
  32. */
  33. const testSlackApiServer = async(client: WebClient): Promise<any> => {
  34. const result = await client.api.test();
  35. if (!result.ok) {
  36. throw new Error(result.error);
  37. }
  38. return result;
  39. };
  40. const checkSlackScopes = (resultTestSlackApiServer: any) => {
  41. const slackScopes = resultTestSlackApiServer.response_metadata.scopes;
  42. const isPassedScopeCheck = requiredScopes.every(e => slackScopes.includes(e));
  43. if (!isPassedScopeCheck) {
  44. throw new Error(`The scopes you registered are not appropriate. Required scopes are ${requiredScopes}`);
  45. }
  46. };
  47. /**
  48. * Retrieve Slack workspace name
  49. * @param client
  50. */
  51. const retrieveWorkspaceName = async(client: WebClient): Promise<string> => {
  52. const result = await client.team.info();
  53. if (!result.ok) {
  54. throw new Error(result.error);
  55. }
  56. return (result as any).team?.name;
  57. };
  58. /**
  59. * @param token bot OAuth token
  60. * @returns
  61. */
  62. export const getConnectionStatus = async(token:string): Promise<ConnectionStatus> => {
  63. const client = generateWebClient(token);
  64. const status: ConnectionStatus = {};
  65. try {
  66. // try to connect
  67. const resultTestSlackApiServer = await testSlackApiServer(client);
  68. // check scope
  69. await checkSlackScopes(resultTestSlackApiServer);
  70. // retrieve workspace name
  71. status.workspaceName = await retrieveWorkspaceName(client);
  72. }
  73. catch (err) {
  74. status.error = err;
  75. }
  76. return status;
  77. };
  78. /**
  79. * Get token string to ConnectionStatus map
  80. * @param keys Array of bot OAuth token or specific key
  81. * @param botTokenResolver function to convert from key to token
  82. * @returns
  83. */
  84. export const getConnectionStatuses = async(keys: string[], botTokenResolver?: (key: string) => string): Promise<{[key: string]: ConnectionStatus}> => {
  85. const map = keys
  86. .reduce<Promise<Map<string, ConnectionStatus>>>(
  87. async(acc, key) => {
  88. let token = key;
  89. if (botTokenResolver != null) {
  90. token = botTokenResolver(key);
  91. }
  92. const status: ConnectionStatus = await getConnectionStatus(token);
  93. (await acc).set(key, status);
  94. return acc;
  95. },
  96. // define initial accumulator
  97. Promise.resolve(new Map<string, ConnectionStatus>()),
  98. );
  99. // convert to object
  100. return Object.fromEntries(await map);
  101. };
  102. export const sendSuccessMessage = async(token:string, channel:string, appSiteUrl:string): Promise<void> => {
  103. const client = generateWebClient(token);
  104. await client.chat.postMessage({
  105. channel,
  106. text: 'Success',
  107. blocks: [
  108. markdownSectionBlock(`:tada: Successfully tested with ${appSiteUrl}.`),
  109. markdownSectionBlock('Now your GROWI and Slack integration is ready to use :+1:'),
  110. ],
  111. });
  112. };