check-communicable.ts 3.4 KB

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