Sfoglia il codice sorgente

Merge pull request #4058 from weseek/feat/6450-6451-save-commands

6450 6451 save commands
itizawa 4 anni fa
parent
commit
3b8e727a7f

+ 12 - 6
packages/slackbot-proxy/src/controllers/growi-to-slack.ts

@@ -3,6 +3,7 @@ import {
 } from '@tsed/common';
 import axios from 'axios';
 import createError from 'http-errors';
+import { addHours } from 'date-fns';
 
 import { WebAPICallResult } from '@slack/web-api';
 
@@ -26,9 +27,6 @@ import { SectionBlockPayloadDelegator } from '~/services/growi-uri-injector/Sect
 
 const logger = loggerFactory('slackbot-proxy:controllers:growi-to-slack');
 
-// temporarily save for selection to growi
-const temporarySinglePostCommands = ['create'];
-
 @Controller('/g2s')
 export class GrowiToSlackCtrl {
 
@@ -94,7 +92,7 @@ export class GrowiToSlackCtrl {
     return res.send({ connectionStatuses });
   }
 
-  @Get('/relation-test')
+  @Post('/relation-test')
   @UseBefore(verifyGrowiToSlackRequest)
   async postRelation(@Req() req: GrowiReq, @Res() res: Res): Promise<void|string|Res|WebAPICallResult> {
     const { tokenGtoPs } = req;
@@ -170,6 +168,9 @@ export class GrowiToSlackCtrl {
 
     logger.debug('relation test is success', order);
 
+    // temporary cache for 48 hours
+    const expiredAtCommands = addHours(new Date(), 48);
+
     // Transaction is not considered because it is used infrequently,
     const response = await this.relationRepository.createQueryBuilder('relation')
       .insert()
@@ -178,10 +179,15 @@ export class GrowiToSlackCtrl {
         tokenGtoP: order.tokenGtoP,
         tokenPtoG: order.tokenPtoG,
         growiUri: order.growiUrl,
-        siglePostCommands: temporarySinglePostCommands,
+        supportedCommandsForBroadcastUse: req.body.supportedCommandsForBroadcastUse,
+        supportedCommandsForSingleUse: req.body.supportedCommandsForSingleUse,
+        expiredAtCommands,
       })
       // https://github.com/typeorm/typeorm/issues/1090#issuecomment-634391487
-      .orUpdate({ conflict_target: ['installation', 'growiUri'], overwrite: ['tokenGtoP', 'tokenPtoG', 'siglePostCommands'] })
+      .orUpdate({
+        conflict_target: ['installation', 'growiUri'],
+        overwrite: ['tokenGtoP', 'tokenPtoG', 'supportedCommandsForBroadcastUse', 'supportedCommandsForSingleUse'],
+      })
       .execute();
 
     // Find the generated relation

+ 15 - 8
packages/slackbot-proxy/src/controllers/slack.ts

@@ -21,6 +21,7 @@ import { ExtractGrowiUriFromReq } from '~/middlewares/slack-to-growi/extract-gro
 import { InstallerService } from '~/services/InstallerService';
 import { SelectGrowiService } from '~/services/SelectGrowiService';
 import { RegisterService } from '~/services/RegisterService';
+import { RelationsService } from '~/services/RelationsService';
 import { UnregisterService } from '~/services/UnregisterService';
 import { InvalidUrlError } from '../models/errors';
 import loggerFactory from '~/utils/logger';
@@ -50,6 +51,9 @@ export class SlackCtrl {
   @Inject()
   registerService: RegisterService;
 
+  @Inject()
+  relationsService: RelationsService;
+
   @Inject()
   unregisterService: UnregisterService;
 
@@ -159,21 +163,24 @@ export class SlackCtrl {
     // See https://api.slack.com/apis/connections/events-api#the-events-api__responding-to-events
     res.send();
 
-    body.growiUris = [];
-    relations.forEach((relation) => {
-      if (relation.siglePostCommands.includes(growiCommand.growiCommandType)) {
-        body.growiUris.push(relation.growiUri);
-      }
-    });
+    body.growiUrisForSingleUse = relations.filter((relation) => {
+      // TODO GW-6845 retrieve commands if it has expired
+      return this.relationsService.isSupportedGrowiCommandForSingleUse(relation, growiCommand.growiCommandType);
+    }).map(relation => relation.growiUri);
 
-    if (body.growiUris != null && body.growiUris.length > 0) {
+    if (body.growiUrisForSingleUse.length > 0) {
       return this.selectGrowiService.process(growiCommand, authorizeResult, body);
     }
 
+    const relationsForBroadcastUse = relations.filter((relation) => {
+      // TODO GW-6845 retrieve commands if it has expired
+      return this.relationsService.isSupportedGrowiCommandForBroadcastUse(relation, growiCommand.growiCommandType);
+    });
+
     /*
      * forward to GROWI server
      */
-    this.sendCommand(growiCommand, relations, body);
+    this.sendCommand(growiCommand, relationsForBroadcastUse, body);
   }
 
   @Post('/interactions')

+ 12 - 1
packages/slackbot-proxy/src/entities/relation.ts

@@ -31,6 +31,17 @@ export class Relation {
   growiUri: string;
 
   @Column('simple-array')
-  siglePostCommands: string[];
+  supportedCommandsForBroadcastUse: string[];
+
+  @Column('simple-array')
+  supportedCommandsForSingleUse: string[];
+
+  @CreateDateColumn()
+  expiredAtCommands: Date;
+
+  isExpiredCommands():boolean {
+    const now = Date.now();
+    return this.expiredAtCommands.getTime() < now;
+  }
 
 }

+ 15 - 0
packages/slackbot-proxy/src/services/RelationsService.ts

@@ -0,0 +1,15 @@
+import { Service } from '@tsed/di';
+import { Relation } from '~/entities/relation';
+
+@Service()
+export class RelationsService {
+
+  isSupportedGrowiCommandForSingleUse(relation:Relation, growiCommandType:string):boolean {
+    return !relation.isExpiredCommands() && relation.supportedCommandsForSingleUse.includes(growiCommandType);
+  }
+
+  isSupportedGrowiCommandForBroadcastUse(relation:Relation, growiCommandType:string):boolean {
+    return !relation.isExpiredCommands() && relation.supportedCommandsForBroadcastUse.includes(growiCommandType);
+  }
+
+}

+ 2 - 2
packages/slackbot-proxy/src/services/SelectGrowiService.ts

@@ -21,7 +21,7 @@ export class SelectGrowiService implements GrowiCommandProcessor {
   @Inject()
   relationRepository: RelationRepository;
 
-  async process(growiCommand: GrowiCommand, authorizeResult: AuthorizeResult, body: {[key:string]:string } & {growiUris:string[]}): Promise<void> {
+  async process(growiCommand: GrowiCommand, authorizeResult: AuthorizeResult, body: {[key:string]:string } & {growiUrisForSingleUse:string[]}): Promise<void> {
     const { botToken } = authorizeResult;
 
     if (botToken == null) {
@@ -60,7 +60,7 @@ export class SelectGrowiService implements GrowiCommandProcessor {
             element: {
               type: 'static_select',
               action_id: 'growi_app',
-              options: body.growiUris.map((growiUri) => {
+              options: body.growiUrisForSingleUse.map((growiUri) => {
                 return ({
                   text: {
                     type: 'plain_text',

+ 2 - 0
src/server/models/slack-app-integration.js

@@ -4,6 +4,8 @@ const mongoose = require('mongoose');
 const schema = new mongoose.Schema({
   tokenGtoP: { type: String, required: true, unique: true },
   tokenPtoG: { type: String, required: true, unique: true },
+  supportedCommandsForBroadcastUse: { type: [String], default: [] },
+  supportedCommandsForSingleUse: { type: [String], default: [] },
 });
 
 class SlackAppIntegration {

+ 14 - 8
src/server/routes/apiv3/slack-integration-settings.js

@@ -105,17 +105,17 @@ module.exports = (crowi) => {
     return result.data;
   }
 
-  async function postRelationTest(token) {
+  async function postRelationTest(token, supportedCommandsForBroadcastUse, supportedCommandsForSingleUse) {
     const proxyUri = crowi.configManager.getConfig('crowi', 'slackbot:proxyServerUri');
     if (proxyUri == null) {
       throw new Error('Proxy URL is not registered');
     }
 
-    const result = await axios.get(urljoin(proxyUri, '/g2s/relation-test'), {
-      headers: {
-        'x-growi-gtop-tokens': token,
-      },
-    });
+    const headers = {
+      'x-growi-gtop-tokens': token,
+    };
+
+    const result = await axios.post(urljoin(proxyUri, '/g2s/relation-test'), { supportedCommandsForBroadcastUse, supportedCommandsForSingleUse }, { headers });
 
     return result.data;
   }
@@ -400,9 +400,13 @@ module.exports = (crowi) => {
     }
 
     const { tokenGtoP, tokenPtoG } = await SlackAppIntegration.generateUniqueAccessTokens();
+    const supportedCommandsForBroadcastUse = ['search'];
+    const supportedCommandsForSingleUse = ['create'];
 
     try {
-      const slackAppTokens = await SlackAppIntegration.create({ tokenGtoP, tokenPtoG });
+      const slackAppTokens = await SlackAppIntegration.create({
+        tokenGtoP, tokenPtoG, supportedCommandsForBroadcastUse, supportedCommandsForSingleUse,
+      });
       return res.apiv3(slackAppTokens, 200);
     }
     catch (error) {
@@ -522,7 +526,9 @@ module.exports = (crowi) => {
         const msg = 'Could not find SlackAppIntegration by id';
         return res.apiv3Err(new ErrorV3(msg, 'find-slackAppIntegration-failed'), 400);
       }
-      const result = await postRelationTest(slackAppIntegration.tokenGtoP);
+      const result = await postRelationTest(
+        slackAppIntegration.tokenGtoP, slackAppIntegration.supportedCommandsForBroadcastUse, slackAppIntegration.supportedCommandsForSingleUse,
+      );
       slackBotToken = result.slackBotToken;
       if (slackBotToken == null) {
         const msg = 'Could not find slackBotToken by relation';