Sequence dialog example
This commit is contained in:
		
							parent
							
								
									1e04cb169e
								
							
						
					
					
						commit
						3371759544
					
				
							
								
								
									
										3
									
								
								.gitignore → dialog-sequence/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore → dialog-sequence/.gitignore
									
									
									
									
										vendored
									
									
								
							@ -11,3 +11,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#!.yarn/cache
 | 
					#!.yarn/cache
 | 
				
			||||||
.pnp.*
 | 
					.pnp.*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					node_modules
 | 
				
			||||||
 | 
					.idea
 | 
				
			||||||
							
								
								
									
										33
									
								
								dialog-sequence/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								dialog-sequence/README.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,33 @@
 | 
				
			|||||||
 | 
					# Loop Dialog Sequence Example
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Пример приложения для последовательного открытия модальных окон с формой.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Запуск и установка
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					В файле index.js меняем переменные:
 | 
				
			||||||
 | 
					- SERVER_URL - адрес вашего сервера Loop
 | 
				
			||||||
 | 
					- LOOP_URL - адрес приложения 
 | 
				
			||||||
 | 
					- PORT - по желанию
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Устанавливаем зависимости `yarn` или `npm install`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Запускаем командой `yarn start` или `npm start`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Переходим в Loop и устанавливаем приложение через слеш команду в любом канале:
 | 
				
			||||||
 | 
					`/apps install http _SERVER_URL_/manifest.json`
 | 
				
			||||||
 | 
					в появившемся окне ставим галочку, что мы все понимаем и подтверждаем.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					После установки должна появиться новая кнопка на правой панели или в верхней панели канала.
 | 
				
			||||||
 | 
					- Переходим в Loop и создаем тестовый канал
 | 
				
			||||||
 | 
					- Приглашаем бота ru.loop.dialog-sequence-example в команду
 | 
				
			||||||
 | 
					- Добавляем бота ru.loop.dialog-sequence-example в тестовый канал
 | 
				
			||||||
 | 
					- Нажимаем на новую кнопку "Открыть форму" (с иконкой Мистфикса)
 | 
				
			||||||
 | 
					- Заполняем форму и нажимаем отправить
 | 
				
			||||||
 | 
					- Если все хорошо, в канал придет сообщение от бота и откроется следующая форма
 | 
				
			||||||
 | 
					- Enjoy
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### Важные замечания по работе с apps framework
 | 
				
			||||||
 | 
					- Все ответы должны быть с кодом 200 (не 201 и тд.)
 | 
				
			||||||
 | 
					- Для получения данных о канале требуется разрешение act_as_user, если его убрать то контекст канала приходить не будет
 | 
				
			||||||
 | 
					- Все иконки описываются без указания пути, Loop всегда будет их искать по пути `_SERVER_URL_/static/`
 | 
				
			||||||
 | 
					- Без основной иконки (указанной в манифесте) приложение не установится
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								dialog-sequence/icon.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								dialog-sequence/icon.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 3.1 MiB  | 
							
								
								
									
										178
									
								
								dialog-sequence/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										178
									
								
								dialog-sequence/index.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,178 @@
 | 
				
			|||||||
 | 
					const express = require('express');
 | 
				
			||||||
 | 
					const bodyParser = require('body-parser');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const app = express();
 | 
				
			||||||
 | 
					app.use(bodyParser.json());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Адрес сервера данного приложения (для доступа из Интернета)
 | 
				
			||||||
 | 
					const SERVER_URL = '';
 | 
				
			||||||
 | 
					// Адрес сервера Loop
 | 
				
			||||||
 | 
					const LOOP_URL = '';
 | 
				
			||||||
 | 
					// Порт на котором будет слушать наш сервер
 | 
				
			||||||
 | 
					const PORT = 4000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Описание первой формы
 | 
				
			||||||
 | 
					const form1 = {
 | 
				
			||||||
 | 
					  title: 'Первая форма',
 | 
				
			||||||
 | 
					  icon: 'icon.png', // Иконку для каждой формы можно задать свою
 | 
				
			||||||
 | 
					  fields: [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      type: 'text',
 | 
				
			||||||
 | 
					      name: 'message',
 | 
				
			||||||
 | 
					      modal_label: 'Тут какое-то поле',
 | 
				
			||||||
 | 
					      position: 1,
 | 
				
			||||||
 | 
					      is_required: true,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  ],
 | 
				
			||||||
 | 
					  submit: {
 | 
				
			||||||
 | 
					    // Куда отправлять запрос после нажатия кнопки "Отправить"
 | 
				
			||||||
 | 
					    path: '/second_modal',
 | 
				
			||||||
 | 
					    // Контекст для запроса
 | 
				
			||||||
 | 
					    expand: {
 | 
				
			||||||
 | 
					      // Запрашиваем данные пользователя который вызвал действие
 | 
				
			||||||
 | 
					      acting_user: "all",
 | 
				
			||||||
 | 
					      // запрашиваем канал в котором было вызвано действие
 | 
				
			||||||
 | 
					      channel: "all",
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Описание второй формы
 | 
				
			||||||
 | 
					const form2 = {
 | 
				
			||||||
 | 
					  title: 'Вторая форма',
 | 
				
			||||||
 | 
					  icon: 'icon.png',
 | 
				
			||||||
 | 
					  fields: [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      type: 'text',
 | 
				
			||||||
 | 
					      name: 'message2',
 | 
				
			||||||
 | 
					      modal_label: 'Еще одно поле',
 | 
				
			||||||
 | 
					      position: 1,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  ],
 | 
				
			||||||
 | 
					  submit: {
 | 
				
			||||||
 | 
					    // Куда отправлять запрос после нажатия кнопки "Отправить"
 | 
				
			||||||
 | 
					    path: '/second_result',
 | 
				
			||||||
 | 
					    expand: {
 | 
				
			||||||
 | 
					      // Запрашиваем данные пользователя который вызвал действие
 | 
				
			||||||
 | 
					      acting_user: "all",
 | 
				
			||||||
 | 
					      // запрашиваем канал в котором было вызвано действие
 | 
				
			||||||
 | 
					      channel: "all",
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Отправка сообщения в канал Loop
 | 
				
			||||||
 | 
					const createPost = async (bot_access_token, channel_id, message) => {
 | 
				
			||||||
 | 
					  try {
 | 
				
			||||||
 | 
					    await fetch(`${LOOP_URL}/api/v4/posts`, {
 | 
				
			||||||
 | 
					      method: 'POST',
 | 
				
			||||||
 | 
					      headers: {
 | 
				
			||||||
 | 
					        Authorization: 'Bearer ' + bot_access_token,
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      body: JSON.stringify({
 | 
				
			||||||
 | 
					        channel_id,
 | 
				
			||||||
 | 
					        message,
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  } catch (e) {
 | 
				
			||||||
 | 
					    console.error('Error when create post', e);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Обработчик результата первой формы
 | 
				
			||||||
 | 
					app.post('/second_modal', (req, res) => {
 | 
				
			||||||
 | 
					  const context = req.body.context;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Отправляем данные формы в канал
 | 
				
			||||||
 | 
					  createPost(
 | 
				
			||||||
 | 
					    context.bot_access_token,
 | 
				
			||||||
 | 
					    context.channel.id,
 | 
				
			||||||
 | 
					    '### Заполнена форма 1\n```json\n' + JSON.stringify(req.body.values, null, 2) + '\n```',
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Отвечаем второй формой. Обязательно статус 200 (не 201 и тд)
 | 
				
			||||||
 | 
					  res.status(200).json({
 | 
				
			||||||
 | 
					    type: 'form',
 | 
				
			||||||
 | 
					    form: form2,
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Обработчик результата второй формы
 | 
				
			||||||
 | 
					app.post('/second_result', (req, res) => {
 | 
				
			||||||
 | 
					  const context = req.body.context;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Отправляем результат в канал
 | 
				
			||||||
 | 
					  createPost(
 | 
				
			||||||
 | 
					    context.bot_access_token,
 | 
				
			||||||
 | 
					    context.channel.id,
 | 
				
			||||||
 | 
					    '### Заполнена форма 2\n```json\n' + JSON.stringify(req.body.values, null, 2) + '\n```',
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Отвечаем что все хорошо. Обязательно статус 200 (не 201 и тд)
 | 
				
			||||||
 | 
					  res.status(200).json({
 | 
				
			||||||
 | 
					    type: 'ok',
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Данный метод будет вызываться при открытии любого канала, любым пользователем
 | 
				
			||||||
 | 
					// Отвечает за отрисовку кнопки в сайдбаре
 | 
				
			||||||
 | 
					app.post('/bindings', (req, res) => {
 | 
				
			||||||
 | 
					  res.status(200).json({
 | 
				
			||||||
 | 
					    type: 'ok',
 | 
				
			||||||
 | 
					    data: [
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        // Место где показать кнопку
 | 
				
			||||||
 | 
					        location: '/channel_header',
 | 
				
			||||||
 | 
					        // Описание кнопки
 | 
				
			||||||
 | 
					        bindings: [
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            // идентификатор, который будет отправлен в запросе
 | 
				
			||||||
 | 
					            location: 'send-button',
 | 
				
			||||||
 | 
					            // Иконка кнопки
 | 
				
			||||||
 | 
					            icon: 'icon.png',
 | 
				
			||||||
 | 
					            // Подпись для кнопки
 | 
				
			||||||
 | 
					            label: 'Открыть форму',
 | 
				
			||||||
 | 
					            // Первая форма
 | 
				
			||||||
 | 
					            form: form1,
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Манифест для установки приложения
 | 
				
			||||||
 | 
					app.get('/manifest.json', (req, res) => {
 | 
				
			||||||
 | 
					  res.json({
 | 
				
			||||||
 | 
					    app_id: 'ru.loop.dialog-sequence-example',
 | 
				
			||||||
 | 
					    version: '0.1.0',
 | 
				
			||||||
 | 
					    display_name: 'Loop Dialog Sequence Example',
 | 
				
			||||||
 | 
					    description: 'An app that opens modal dialogs sequentially',
 | 
				
			||||||
 | 
					    icon: 'icon.png',
 | 
				
			||||||
 | 
					    homepage_url: 'https://git.wilix.dev/loop/integration-examples',
 | 
				
			||||||
 | 
					    // Разрешения для приложения
 | 
				
			||||||
 | 
					    requested_permissions: [
 | 
				
			||||||
 | 
					      // разрешение, чтобы приложение могло писать от имени бота
 | 
				
			||||||
 | 
					      'act_as_bot',
 | 
				
			||||||
 | 
					      // разрешение, чтобы получать данные пользователя, который вызывает действия
 | 
				
			||||||
 | 
					      'act_as_user'
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    // Разрешения для установки кнопок или команд
 | 
				
			||||||
 | 
					    requested_locations: [
 | 
				
			||||||
 | 
					      // Устанавливает кнопку во всех каналах в сайдбаре или в заголовке канала
 | 
				
			||||||
 | 
					      // (расположение завит от того, включен ли сайдбар)
 | 
				
			||||||
 | 
					      '/channel_header'
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    app_type: 'http',
 | 
				
			||||||
 | 
					    http: {
 | 
				
			||||||
 | 
					      root_url: SERVER_URL
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Сервим иконки из папки. Все иконки всегда будут искаться по пути /static
 | 
				
			||||||
 | 
					app.use('/static', express.static('./static'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					app.listen(PORT, () => {
 | 
				
			||||||
 | 
					  console.log(`Server is running on port ${PORT}`);
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
							
								
								
									
										16
									
								
								dialog-sequence/package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								dialog-sequence/package.json
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,16 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "name": "loop-dialog-sequence-example",
 | 
				
			||||||
 | 
					  "version": "0.1.0",
 | 
				
			||||||
 | 
					  "description": "Example App for dialog sequence",
 | 
				
			||||||
 | 
					  "scripts": {
 | 
				
			||||||
 | 
					    "start": "node ./index.js"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "engines": {
 | 
				
			||||||
 | 
					    "node": "21"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "license": "MIT",
 | 
				
			||||||
 | 
					  "dependencies": {
 | 
				
			||||||
 | 
					    "body-parser": "^1.20.2",
 | 
				
			||||||
 | 
					    "express": "4.17.1"
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,4 +0,0 @@
 | 
				
			|||||||
{
 | 
					 | 
				
			||||||
  "name": "modal-pages-test",
 | 
					 | 
				
			||||||
  "packageManager": "yarn@4.1.1"
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										12
									
								
								yarn.lock
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								yarn.lock
									
									
									
									
									
								
							@ -1,12 +0,0 @@
 | 
				
			|||||||
# This file is generated by running "yarn install" inside your project.
 | 
					 | 
				
			||||||
# Manual changes might be lost - proceed with caution!
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
__metadata:
 | 
					 | 
				
			||||||
  version: 8
 | 
					 | 
				
			||||||
  cacheKey: 10c0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
"modal-pages-test@workspace:.":
 | 
					 | 
				
			||||||
  version: 0.0.0-use.local
 | 
					 | 
				
			||||||
  resolution: "modal-pages-test@workspace:."
 | 
					 | 
				
			||||||
  languageName: unknown
 | 
					 | 
				
			||||||
  linkType: soft
 | 
					 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user