Compare commits

...

166 Commits

Author SHA1 Message Date
f21964eee2
Запуск нового cicd
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-30 22:27:04 +03:00
02fd8a016d
Снепшотные репозитории 2022-12-30 22:23:48 +03:00
fb1822a0ac
Вынес плагин релизов из профиля релизов 2022-12-30 13:27:19 +03:00
2311cd33ab Добавил плагин релизов в профиль release 2022-12-18 17:22:54 +03:00
d41bfae7ff [maven-release-plugin] prepare for next development iteration 2022-12-18 17:17:36 +03:00
408bc6022b [maven-release-plugin] prepare release v.0.0.41 2022-12-18 17:17:36 +03:00
c5950f7d81 Настройка CICD 2022-12-18 17:17:17 +03:00
3359314848 [maven-release-plugin] prepare for next development iteration 2022-12-18 17:14:03 +03:00
22a5d50ea8 [maven-release-plugin] prepare release v.0.0.40 2022-12-18 17:14:03 +03:00
f9ae7b187d Настройка CICD 2022-12-18 17:13:00 +03:00
8e1090c608 Настройка CICD 2022-12-18 17:07:52 +03:00
3637599e0c Настройка CICD
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-18 16:54:27 +03:00
7df4c093ba Настройка CICD 2022-12-18 16:54:15 +03:00
3845d3e0db Merge remote-tracking branch 'public/master' 2022-12-18 16:50:28 +03:00
e1ddbf8a8f test
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 13:50:27 +00:00
b03ffed637 Merge remote-tracking branch 'public/master' 2022-12-18 16:50:25 +03:00
a2bcb31085 test
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-18 13:50:24 +00:00
b0b454ff00 Merge remote-tracking branch 'public/master' 2022-12-18 16:50:22 +03:00
52d70a1dd4 test
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-18 13:50:22 +00:00
933f1182df Merge remote-tracking branch 'public/master' 2022-12-18 16:50:19 +03:00
445c67a9de test
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-18 13:50:18 +00:00
f09dd42574 test
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-18 13:50:16 +00:00
fc2d478d1d Настройка CICD 2022-12-18 16:50:13 +03:00
aa8aef7d04 test
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-18 13:50:13 +00:00
820c27fa4c test
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-18 13:50:10 +00:00
568f6afbf9 test
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-18 13:50:08 +00:00
d1e8ca88e8 test
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-18 13:50:05 +00:00
f22b8e6941 test
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-18 13:50:03 +00:00
284b9a2bc7 test
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-18 13:50:00 +00:00
80aa674ed3 test
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-18 13:49:57 +00:00
9ccc7688d5 test
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-18 13:49:54 +00:00
29bd34ebda test
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-18 13:49:51 +00:00
e08fd0e135 test
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-18 13:49:49 +00:00
402f8cbd7e test
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-18 13:49:46 +00:00
5c9f1fb72a test
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-18 13:49:43 +00:00
04b9fc7473 test
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-18 13:49:40 +00:00
e26ae25712 test
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-18 13:49:38 +00:00
0b7e235774 test
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-18 13:49:35 +00:00
99e1875d26 test
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-18 13:49:33 +00:00
7a8044f4ca test
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-18 13:49:30 +00:00
028938f00b test
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-18 13:49:28 +00:00
8a0153d5b0 test
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-18 13:49:25 +00:00
8fdfad675e test
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-18 13:49:23 +00:00
19ac9030d4 test
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-18 13:49:20 +00:00
09475f57e4 test
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-18 13:49:17 +00:00
19f678442d test
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-18 13:49:15 +00:00
88f38b0fac test
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-18 13:49:12 +00:00
647033859c test
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-18 13:49:10 +00:00
7d9b9d7bfd test
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-18 13:49:07 +00:00
b16ef5ce73 test
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-18 13:49:04 +00:00
7f65ec0ed3 Настройка CICD
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-18 16:48:59 +03:00
a8a7a6130f Настройка CICD
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 16:47:38 +03:00
adb7191cfe Настройка CICD
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 16:47:23 +03:00
fab62dfa55 Настройка CICD
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 16:46:51 +03:00
e97e33282d Настройка CICD
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 16:46:08 +03:00
1785a5d819 Настройка CICD
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 14:45:26 +03:00
26d3416f4f Настройка CICD
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 14:44:57 +03:00
126160e331 Настройка CICD
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 14:43:50 +03:00
10a07b322a Настройка CICD
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 14:42:40 +03:00
a92893e63f Настройка CICD 2022-12-18 14:42:26 +03:00
be2332d370 Настройка CICD
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 14:37:00 +03:00
e652b12f90 Настройка CICD
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 14:35:48 +03:00
c795ff30cc Настройка CICD
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 14:32:07 +03:00
ff56a9441d Настройка CICD
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 14:31:01 +03:00
d43e2150d8 Настройка CICD
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 14:30:27 +03:00
cc79b67b9b Настройка CICD
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 14:29:26 +03:00
6648bc1dc6 Настройка CICD
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 14:28:40 +03:00
bee956c7d7 Настройка CICD
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 14:23:50 +03:00
1c792e488f Настройка CICD
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 10:46:13 +03:00
1c1ab65a80 Настройка CICD
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 10:44:05 +03:00
5300bc5ecb Настройка CICD
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 10:43:49 +03:00
bef853a3ab Настройка CICD
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 10:42:54 +03:00
ee7e178f03 Настройка CICD
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 10:41:12 +03:00
90f4659beb Настройка CICD
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 10:40:30 +03:00
d608b6ffd3 Настройка CICD
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 10:34:28 +03:00
ee3e25993a Настройка CICD
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-18 10:33:21 +03:00
2464251311 Настройка CICD
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 10:33:00 +03:00
9bc76f0d94 Настройка CICD
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-18 10:32:20 +03:00
b8edee1cc6 Настройка CICD
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-18 10:31:44 +03:00
bf9404fb35 Добавил ssh key
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 06:57:33 +03:00
c6338635cf Добавил ssh key
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 06:57:06 +03:00
e081e9af4c Добавил ssh key
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 06:55:54 +03:00
34b3515c37 Добавил ssh key
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 06:55:23 +03:00
f4399bc0af Добавил ssh key
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 06:50:08 +03:00
bf0e5a3c11 Добавил ssh key
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 06:49:39 +03:00
d780aba701 Добавил ssh key
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 06:49:11 +03:00
cc6b588ab8 Добавил ssh key
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 06:48:57 +03:00
3c87887b59 Добавил ssh key
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 06:47:19 +03:00
65e1ef0bf3 Добавил ssh key
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 06:47:01 +03:00
a4b8dbf77d Добавил ssh key
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 06:45:38 +03:00
7c3c100447 Добавил ssh key
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 06:42:43 +03:00
b269d2295b Добавил ssh key
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 06:40:31 +03:00
93b4944929 Добавил ssh key
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 06:40:09 +03:00
ca25e8dfe8 Добавил ssh key
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 06:37:21 +03:00
4b7ce5f649 Добавил ssh key
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 06:36:28 +03:00
32af3a68be Добавил ssh key
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 06:31:54 +03:00
b25a8dc132 Добавил ssh key
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 06:29:36 +03:00
7a968205ea Добавил ssh key
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 06:27:51 +03:00
3c987a9c72 Добавил ssh key
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 06:25:41 +03:00
18407b6366 Добавил ssh key
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 06:25:12 +03:00
4c26875261 Добавил ssh key
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 06:24:54 +03:00
b2a32d99bd Добавил ssh key
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 06:23:17 +03:00
7b5811e0cf Добавил ssh key
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 06:22:31 +03:00
a8d9a03bc2 Добавил ssh key
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 06:21:44 +03:00
37302905d0 Добавил ssh key
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 06:21:16 +03:00
f4b4d81b10 Добавил ssh key
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 06:20:36 +03:00
a44a2f3535 Добавил ssh key
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 06:18:47 +03:00
b2f0f0f33a Добавил ssh key
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 06:18:33 +03:00
da4b053d35 Добавил ssh key
Some checks reported errors
continuous-integration/drone/push Build encountered an error
2022-12-18 06:15:54 +03:00
d1168e0833 Добавил ssh key 2022-12-18 06:15:33 +03:00
d54ef69aff Добавил ssh key
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 06:00:32 +03:00
2ddbd505a5 Настройка CICD
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 05:35:56 +03:00
19fbd941a4 Настройка CICD 2022-12-18 05:34:33 +03:00
a4767439aa Заменил scm в pom 2022-12-18 05:32:15 +03:00
460772367e Заменил scm в pom 2022-12-18 05:31:16 +03:00
a509e4bc0f Настройка CICD
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 05:29:04 +03:00
c00c8f90a0 Настройка CICD
Some checks reported errors
continuous-integration/drone/push Build was killed
2022-12-18 05:27:56 +03:00
41570759f6 Вернул openjdk для сборки
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 05:24:59 +03:00
5d3206fdb4 Вернул openjdk для сборки
Some checks reported errors
continuous-integration/drone/push Build encountered an error
2022-12-18 05:24:09 +03:00
0318a08b78 Настройка автоматический смены версий
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-18 05:18:30 +03:00
b0c1123225 [maven-release-plugin] prepare for next development iteration 2022-12-18 05:14:21 +03:00
d951c45049 [maven-release-plugin] prepare release v.0.0.39 2022-12-18 05:14:21 +03:00
3d59cb8989 Настройка автоматический смены версий 2022-12-18 05:14:02 +03:00
7710e2b274 [maven-release-plugin] prepare for next development iteration 2022-12-18 05:06:02 +03:00
104d59dde6 [maven-release-plugin] prepare release v.0.0.38 2022-12-18 05:06:02 +03:00
bdb7be787c Настройка автоматический смены версий 2022-12-18 05:05:46 +03:00
ebca79abb9 [maven-release-plugin] prepare for next development iteration 2022-12-18 05:04:51 +03:00
3b19ec130a [maven-release-plugin] prepare release v.0.0.37 2022-12-18 05:04:51 +03:00
4a58750325 Новый базовый образ для сборки 2022-12-18 05:04:32 +03:00
061536b663 [maven-release-plugin] prepare for next development iteration 2022-12-18 04:58:54 +03:00
3b588ad0ca [maven-release-plugin] prepare release v.0.0.36 2022-12-18 04:58:54 +03:00
cad7dc9cef Настройка автоматический смены версий 2022-12-18 04:58:36 +03:00
61e98c75b2 [maven-release-plugin] prepare for next development iteration 2022-12-18 04:52:29 +03:00
154d1e792b [maven-release-plugin] prepare release v.0.0.35 2022-12-18 04:52:29 +03:00
e59777f65d [maven-release-plugin] prepare for next development iteration 2022-12-18 04:48:43 +03:00
49484342b6 [maven-release-plugin] prepare release v.0.0.34 2022-12-18 04:48:43 +03:00
7cb3a0a059 Настройка автоматический смены версий 2022-12-18 04:48:14 +03:00
bc66a0164d [maven-release-plugin] prepare for next development iteration 2022-12-18 04:46:22 +03:00
eb403f96d6 [maven-release-plugin] prepare release v.0.0.33 2022-12-18 04:46:22 +03:00
04c0a58f22 Настройка автоматический смены версий 2022-12-18 04:45:22 +03:00
333edfb8e5 Добавил тег релиза 2022-12-18 04:38:47 +03:00
edbd20163f update drone 2022-12-18 04:37:03 +03:00
f71ed56e1b Коммит 2022-12-18 04:34:17 +03:00
b3f63e6b3c v.0.0.32 2022-12-13 21:54:09 +03:00
6f64494504 Добавил возможность устанавливать получателя в BoxAnswer 2022-12-13 21:52:22 +03:00
ad69ea3702 v.0.0.31 2022-12-12 14:03:53 +03:00
cb3557fe9b v.0.0.30 2022-12-12 10:22:46 +03:00
e7bf89c24d Рефакторинг пре-процессинга перед отправкой сообщения 2022-12-12 10:21:19 +03:00
b2046cc977 Добавил возможность отправки промежуточного сообщения в AnswerCheck 2022-12-09 21:15:00 +03:00
eaaca3be6c Переход на String вместо Long для id юзера 2022-12-09 20:39:24 +03:00
eb2e7ba012 Revert "Revert "release-0.0.27""
This reverts commit 7c3711ab90.
2022-09-21 19:15:29 +03:00
7c3711ab90 Revert "release-0.0.27"
This reverts commit 1a2d2d4602.
2022-09-21 19:15:16 +03:00
1a2d2d4602 release-0.0.27 2022-09-19 20:22:10 +03:00
dd6b166506 Добавил версию для реактивного Quarkus 2022-08-07 07:07:10 +03:00
d2cf3ed645 Обновление api 2022-08-02 21:55:45 +03:00
d4f6a672ef Небольшой рефакторинг 2022-07-30 10:27:09 +03:00
0bbdcaae07 Добавил новый тип триггера 2022-07-26 09:27:18 +03:00
eaeb220515 Большое улучшение функциональности 2022-07-21 00:50:14 +03:00
87c565f4d2 Доработки для загрузки фото 2022-07-19 20:36:31 +03:00
9192b7cd97 Изменил подход к возникающим событиям и их обработки 2022-07-15 17:47:40 +03:00
fc3f9563e2 Добавил новый юнит ReplaceCmd, который позволяет заменять тригеры для юнитов. Также добавил новый признак юнитов, возможность отключать сохранение в историю сценария. 2022-07-15 10:27:48 +03:00
6d9454fd03 Добавил возможность устанавливать юниты, которые всегда будут участвовать в обработке. Добавил возможность устанавливать юнит для ответов, когда никакой юнит для ответа не найден 2022-07-15 08:45:14 +03:00
2a9413ab46 Удалил код первой попытки линивой инициализации 2022-07-15 08:13:34 +03:00
29145fe093 Добавил возможность возвращать пользователя назад в сценарии по названию юнита 2022-07-13 20:39:23 +03:00
996194264e Множественные изменения и улучшения:
* Удалил все типы вложений, теперь типы вложений реализуются в библиотеках для каждого конкретного мессенджера.
* Теперь сохраняется история перемещения пользователя по сценарию. Сохраняется сообщение и название юнита. Это позволяет откатывать пользователя назад.
* Реализовал два новых юнита. RollBackCmd позволяет откатить пользователя назад в сценарии на произвольное количество юнитов. TeleportCmd позволяет перенести пользователя в произвольное место сценария.
* Удалил AnswerProcessing, вместо него можно использовать AnswerText.
2022-07-10 00:25:53 +03:00
78b2dda570 Добавил ErrorHandler 2022-07-03 22:02:15 +03:00
204 changed files with 6314 additions and 3476 deletions

69
.drone.yml Normal file
View File

@ -0,0 +1,69 @@
---
kind: pipeline
type: docker
name: snapshot-publish
trigger:
branch:
- develop
volumes:
- name: m2
host:
path: /drone/volume/m2
steps:
- name: publish
image: maven:3.8.5-openjdk-17
privileged: true
volumes:
- name: m2
path: /root/.m2/repository
environment:
MAVEN_SETTINGS:
from_secret: MAVEN_SETTINGS
commands:
- echo "$MAVEN_SETTINGS" >> maven-settings.xml
- mvn --settings maven-settings.xml -U -P snapshot clean deploy
---
kind: pipeline
type: docker
name: release-publish
trigger:
ref:
- refs/tags/v.*.*.*
volumes:
- name: m2
host:
path: /drone/volume/m2
steps:
- name: publish maven central
image: maven:3.8.5-openjdk-17
privileged: true
volumes:
- name: m2
path: /root/.m2/repository
environment:
GPG_PRIVATE_KEY:
from_secret: GPG_PRIVATE_KEY
MAVEN_SETTINGS:
from_secret: MAVEN_SETTINGS
GPG_PASSPHRASE:
from_secret: GPG_PASSPHRASE
commands:
- echo "$GPG_PRIVATE_KEY" >> gpg.key
- echo "$MAVEN_SETTINGS" >> maven-settings.xml
- gpg --pinentry-mode loopback --passphrase $GPG_PASSPHRASE --import gpg.key
- mvn --settings maven-settings.xml -U -P ossrh,release clean deploy
---
kind: signature
hmac: d30cbf3dfe171a8912b3171a0b7e5345f0cd80b65c1386d3207bffc06b56c3db
...

50
.drone.yml.back Normal file
View File

@ -0,0 +1,50 @@
kind: pipeline
type: docker
name: haiti-framework
steps:
- name: publish maven central
image: maven:3.8.5-openjdk-17
privileged: true
volumes:
- name: m2
path: /root/.m2/repository
environment:
GPG_PRIVATE_KEY:
from_secret: GPG_PRIVATE_KEY
MAVEN_SETTINGS:
from_secret: MAVEN_SETTINGS
GPG_PASSPHRASE:
from_secret: GPG_PASSPHRASE
SSH_KEY:
from_secret: SSH_KEY
commands:
- eval $(ssh-agent -s)
- mkdir -p ~/.ssh
- chmod 700 ~/.ssh
- echo "$SSH_KEY" | ssh-add -
- ssh-keyscan -p 222 git.struchkov.dev >> ~/.ssh/known_hosts
- git branch -a
# - echo "test" >> test.txt
# - git add --all
# - git commit -m test
# - git remote add deploy ssh://git@git.struchkov.dev:222/Godfather-Bots/godfather.git
# - git remote -v
# - git push deploy HEAD:master
# - ssh-keyscan -t rsa git.struchkov.dev >> ~/.ssh/known_hosts
# - chmod 644 ~/.ssh/known_hosts
# - echo "$GPG_PRIVATE_KEY" >> gpg.key
# - echo "$MAVEN_SETTINGS" >> maven-settings.xml
# - gpg --pinentry-mode loopback --passphrase $GPG_PASSPHRASE --import gpg.key
# - mvn --settings maven-settings.xml -T 1C -U release:clean release:prepare release:perform --batch-mode
trigger:
branch:
- master
volumes:
- name: m2
host:
path: /drone/volume/m2

View File

@ -1,17 +0,0 @@
image: maven:3.8.5-openjdk-17
variables:
MAVEN_OPTS: "-Dmaven.repo.local=./.m2/repository"
stages:
- deploy
deploy:
stage: deploy
only:
- /^v.*$/
except:
- branches
before_script:
- gpg --pinentry-mode loopback --passphrase $GPG_PASSPHRASE --import $GPG_PRIVATE_KEY
script:
- 'mvn --settings $MAVEN_SETTINGS -U -P ossrh,release clean deploy'

View File

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>dev.struchkov.godfather</groupId>
<artifactId>bot-context</artifactId>
<version>0.0.42-SNAPSHOT</version>
</parent>
<artifactId>bot-context-main</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>dev.struchkov.godfather</groupId>
<artifactId>bot-domain-main</artifactId>
</dependency>
<dependency>
<groupId>dev.struchkov.haiti</groupId>
<artifactId>haiti-utils</artifactId>
</dependency>
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -1,8 +1,8 @@
package dev.struchkov.godfather.context.utils;
package dev.struchkov.godfather.main.context.utils;
import dev.struchkov.godfather.context.domain.keyboard.button.SimpleButton;
import dev.struchkov.godfather.context.domain.keyboard.simple.SimpleKeyBoard;
import dev.struchkov.godfather.context.domain.keyboard.simple.SimpleKeyBoardLine;
import dev.struchkov.godfather.main.domain.keyboard.button.SimpleButton;
import dev.struchkov.godfather.main.domain.keyboard.simple.SimpleKeyBoard;
import dev.struchkov.godfather.main.domain.keyboard.simple.SimpleKeyBoardLine;
import java.util.Arrays;
import java.util.List;

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>dev.struchkov.godfather</groupId>
<artifactId>bot-context</artifactId>
<version>0.0.42-SNAPSHOT</version>
</parent>
<artifactId>bot-context-quarkus</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>dev.struchkov.godfather</groupId>
<artifactId>bot-domain-main</artifactId>
</dependency>
<dependency>
<groupId>io.smallrye.reactive</groupId>
<artifactId>smallrye-mutiny-vertx-core</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,10 @@
package dev.struchkov.godfather.quarkus.context.service;
import dev.struchkov.godfather.main.domain.content.Message;
import io.smallrye.mutiny.Uni;
public interface Accessibility {
Uni<Void> check(Message message);
}

View File

@ -0,0 +1,19 @@
package dev.struchkov.godfather.quarkus.context.service;
import dev.struchkov.godfather.main.domain.content.Message;
import io.smallrye.mutiny.Uni;
/**
* Используется для перехвата исключений, которые возникают при обработке юнитов.
*/
public interface ErrorHandler {
/**
* Метод, который должен как-то обработать исключение.
*
* @param message Сообщение, после которого возникло исключение.
* @param e Объект исключения.
*/
Uni<Void> handle(Message message, Throwable e);
}

View File

@ -0,0 +1,12 @@
package dev.struchkov.godfather.quarkus.context.service;
import dev.struchkov.godfather.main.domain.event.Event;
import io.smallrye.mutiny.Uni;
public interface EventHandler<T extends Event> {
Uni<Void> handle(T event);
String getEventType();
}

View File

@ -0,0 +1,18 @@
package dev.struchkov.godfather.quarkus.context.service;
import dev.struchkov.godfather.main.domain.content.Message;
import io.smallrye.mutiny.Uni;
import org.jetbrains.annotations.NotNull;
/**
* Интерфес для изменения запроса пользователя перед тем, как он попадет в подсистему обработки.
* Например можно исправить опечатки, перевести сообщение на другой язык и так далее.
*
* @author upagge [08/07/2019]
*/
@FunctionalInterface
public interface Modifiable<T extends Message> {
Uni<Void> change(@NotNull T content);
}

View File

@ -0,0 +1,18 @@
package dev.struchkov.godfather.quarkus.context.service;
import io.smallrye.mutiny.Uni;
import org.jetbrains.annotations.NotNull;
import java.util.Set;
public interface PersonSettingService {
Uni<Set<String>> getAllPersonIdDisableMessages(@NotNull Set<String> personIds);
Uni<Boolean> getStateProcessingByPersonId(@NotNull String personId);
Uni<Void> disableMessageProcessing(@NotNull String personId);
Uni<Void> enableMessageProcessing(@NotNull String personId);
}

View File

@ -0,0 +1,11 @@
package dev.struchkov.godfather.quarkus.context.service;
import dev.struchkov.godfather.main.domain.BoxAnswer;
import io.smallrye.mutiny.Uni;
@FunctionalInterface
public interface PreSendProcessing {
Uni<BoxAnswer> pretreatment(BoxAnswer boxAnswer);
}

View File

@ -0,0 +1,17 @@
package dev.struchkov.godfather.quarkus.context.service;
import io.smallrye.mutiny.Uni;
import java.util.Map;
/**
* TODO: Добавить описание класса.
*
* @author upagge [13/07/2019]
*/
@FunctionalInterface
public interface Pusher<D> {
Uni<Void> push(String personId, Map<String, D> saveElement);
}

View File

@ -0,0 +1,30 @@
package dev.struchkov.godfather.quarkus.context.service;
import dev.struchkov.godfather.main.domain.BoxAnswer;
import dev.struchkov.godfather.main.domain.SendType;
import io.smallrye.mutiny.Uni;
import org.jetbrains.annotations.NotNull;
/**
* Интерфейс для отправки ответов пользователю.
*
* @author upagge [08/07/2019]
*/
public interface Sending {
/**
* Отправляет сообщение пользователю
*
* @param boxAnswer Объект с данными, которые необходимо отправить
*/
Uni<Void> send(@NotNull BoxAnswer boxAnswer);
void addPreSendProcess(@NotNull PreSendProcessing processing);
/**
* Возвращает тип объекта отправляющего ответ пользователя. В зависимости от типа ответ будет отправлен с помощью
* разных методов.
*/
SendType getType();
}

View File

@ -0,0 +1,20 @@
package dev.struchkov.godfather.quarkus.context.service;
import dev.struchkov.godfather.main.domain.UnitPointer;
import io.smallrye.mutiny.Uni;
import org.jetbrains.annotations.NotNull;
/**
* Сервис для взаимодействия с сущностью {@link UnitPointer}.
*
* @author upagge [07/07/2019]
*/
public interface UnitPointerService {
Uni<UnitPointer> save(@NotNull UnitPointer unitPointer);
Uni<String> getUnitNameByPersonId(@NotNull String personId);
Uni<Void> removeByPersonId(@NotNull String personId);
}

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>dev.struchkov.godfather</groupId>
<artifactId>bot-context</artifactId>
<version>0.0.42-SNAPSHOT</version>
</parent>
<artifactId>bot-context-simple</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>dev.struchkov.godfather</groupId>
<artifactId>bot-domain-main</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,9 @@
package dev.struchkov.godfather.simple.context.service;
import dev.struchkov.godfather.main.domain.content.Message;
public interface Accessibility {
boolean check(Message message);
}

View File

@ -0,0 +1,18 @@
package dev.struchkov.godfather.simple.context.service;
import dev.struchkov.godfather.main.domain.content.Message;
/**
* Используется для перехвата исключений, которые возникают при обработке юнитов.
*/
public interface ErrorHandler {
/**
* Метод, который должен как-то обработать исключение.
*
* @param message Сообщение, после которого возникло исключение.
* @param e Объект исключения.
*/
void handle(Message message, Exception e);
}

View File

@ -0,0 +1,11 @@
package dev.struchkov.godfather.simple.context.service;
import dev.struchkov.godfather.main.domain.event.Event;
public interface EventHandler<T extends Event> {
void handle(T event);
String getEventType();
}

View File

@ -1,6 +1,6 @@
package dev.struchkov.godfather.context.service;
package dev.struchkov.godfather.simple.context.service;
import dev.struchkov.godfather.context.domain.content.Message;
import dev.struchkov.godfather.main.domain.content.Message;
import org.jetbrains.annotations.NotNull;
/**

View File

@ -0,0 +1,18 @@
package dev.struchkov.godfather.simple.context.service;
import org.jetbrains.annotations.NotNull;
import java.util.Optional;
import java.util.Set;
public interface PersonSettingService {
Set<String> getAllPersonIdDisableMessages(@NotNull Set<String> personIds);
Optional<Boolean> getStateProcessingByPersonId(@NotNull String personId);
void disableMessageProcessing(@NotNull String personId);
void enableMessageProcessing(@NotNull String personId);
}

View File

@ -0,0 +1,10 @@
package dev.struchkov.godfather.simple.context.service;
import dev.struchkov.godfather.main.domain.BoxAnswer;
@FunctionalInterface
public interface PreSendProcessing {
BoxAnswer pretreatment(BoxAnswer boxAnswer);
}

View File

@ -1,4 +1,4 @@
package dev.struchkov.godfather.core.service.save.push;
package dev.struchkov.godfather.simple.context.service;
import java.util.Map;
@ -10,6 +10,6 @@ import java.util.Map;
@FunctionalInterface
public interface Pusher<D> {
void push(Map<String, D> saveElement);
void push(String personId, Map<String, D> saveElement);
}

View File

@ -1,6 +1,7 @@
package dev.struchkov.godfather.context.service.sender;
package dev.struchkov.godfather.simple.context.service;
import dev.struchkov.godfather.context.domain.BoxAnswer;
import dev.struchkov.godfather.main.domain.BoxAnswer;
import dev.struchkov.godfather.main.domain.SendType;
import org.jetbrains.annotations.NotNull;
/**
@ -11,12 +12,13 @@ import org.jetbrains.annotations.NotNull;
public interface Sending {
/**
* Отрпавляет ответ пользователю
* Отравляет сообщение пользователю.
*
* @param personId Идентификатор пользователя
* @param boxAnswer Объект с данными, которые необходимо отправить
*/
void send(@NotNull Long personId, @NotNull BoxAnswer boxAnswer);
void send(@NotNull BoxAnswer boxAnswer);
void addPreSendProcess(@NotNull PreSendProcessing processing);
/**
* Возвращает тип объекта отправляющего ответ пользователя. В зависимости от типа ответ будет отправлен с помощью

View File

@ -1,6 +1,6 @@
package dev.struchkov.godfather.context.service;
package dev.struchkov.godfather.simple.context.service;
import dev.struchkov.godfather.context.domain.UnitPointer;
import dev.struchkov.godfather.main.domain.UnitPointer;
import org.jetbrains.annotations.NotNull;
import java.util.Optional;
@ -14,8 +14,8 @@ public interface UnitPointerService {
UnitPointer save(@NotNull UnitPointer unitPointer);
Optional<String> getUnitNameByPersonId(@NotNull Long personId);
Optional<String> getUnitNameByPersonId(@NotNull String personId);
void removeByPersonId(@NotNull Long personId);
void removeByPersonId(@NotNull String personId);
}

View File

@ -1,20 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>dev.struchkov.godfather</groupId>
<artifactId>godfather-bot</artifactId>
<version>0.0.7</version>
<version>0.0.42-SNAPSHOT</version>
</parent>
<artifactId>bot-context</artifactId>
<packaging>pom</packaging>
<modules>
<module>bot-context-main</module>
<module>bot-context-simple</module>
<module>bot-context-quarkus</module>
</modules>
<name>Bot Context</name>
<description>Доменные сущности, интерфейсы, для библиотеки Godfather</description>
<dependencies>
<dependency>
<groupId>dev.struchkov</groupId>
<artifactId>autoresponder</artifactId>
</dependency>
<dependency>
<groupId>dev.struchkov.haiti</groupId>
<artifactId>haiti-utils</artifactId>

View File

@ -1,27 +0,0 @@
package dev.struchkov.godfather.context.domain;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
/**
* Основная сущность для сокрытия id у других сущностей.
*
* @author upagge [28/07/2019]
*/
@MappedSuperclass
public class BasicEntity {
@Id
@GeneratedValue
protected Long id;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}

View File

@ -1,118 +0,0 @@
package dev.struchkov.godfather.context.domain.content;
import dev.struchkov.godfather.context.domain.BasicEntity;
import javax.persistence.Column;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.MappedSuperclass;
import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
import java.util.Objects;
/**
* Абстрактная сущность - Сообщение от пользователя.
*
* @author upagge [08/07/2019]
*/
@MappedSuperclass
public abstract class Message extends BasicEntity {
/**
* Тип сообщения.
*/
@Column(name = "type")
@Enumerated(value = EnumType.STRING)
protected ContentType type;
/**
* Дата создания.
*/
@NotNull
@Column(name = "create_date")
private LocalDateTime createDate;
/**
* Дата добавления в базу.
*/
@Column(name = "add_date")
private LocalDateTime addDate;
/**
* Идентификатор пользователя, отправившего сообщение.
*/
@NotNull
@Column(name = "person_id")
private Long personId;
/**
* Текстовое сообщение.
*/
@Column(name = "text")
private String text;
public Message(Message source) {
this.personId = source.getPersonId();
this.text = source.getText();
this.createDate = source.getCreateDate();
this.id = source.getPersonId();
this.type = source.getType();
}
public Message() {
}
public ContentType getType() {
return type;
}
public void setType(ContentType type) {
this.type = type;
}
public LocalDateTime getCreateDate() {
return createDate;
}
public void setCreateDate(LocalDateTime createDate) {
this.createDate = createDate;
}
public LocalDateTime getAddDate() {
return addDate;
}
public void setAddDate(LocalDateTime addDate) {
this.addDate = addDate;
}
public Long getPersonId() {
return personId;
}
public void setPersonId(Long personId) {
this.personId = personId;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Message message = (Message) o;
return type == message.type && Objects.equals(createDate, message.createDate) && Objects.equals(addDate, message.addDate) && Objects.equals(personId, message.personId) && Objects.equals(text, message.text);
}
@Override
public int hashCode() {
return Objects.hash(type, createDate, addDate, personId, text);
}
}

View File

@ -1,29 +0,0 @@
package dev.struchkov.godfather.context.domain.content.attachment;
import dev.struchkov.godfather.context.domain.BasicEntity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
/**
* Абстрактная сущность, для всех вложений к сообщениям от пользователей.
*
* @author upagge [08/07/2019]
*/
@Entity
public abstract class Attachment extends BasicEntity {
/**
* Тип сущности.
*/
@Column(name = "type")
@Enumerated(value = EnumType.STRING)
protected AttachmentType type;
public AttachmentType getType() {
return type;
}
}

View File

@ -1,14 +0,0 @@
package dev.struchkov.godfather.context.domain.content.attachment;
/**
* Тип вложения {@link Attachment} к сообщению.
*
* @author upagge [08/07/2019]
*/
public enum AttachmentType {
AUDIO_MESSAGE,
GEO,
LINK
}

View File

@ -1,25 +0,0 @@
package dev.struchkov.godfather.context.domain.content.attachment;
import java.net.URL;
/**
* Вложение типа "Аудиосообщение".
*
* @author upagge [08/07/2019]
*/
public class AudioMessage extends Attachment {
/**
* Ссылка на аудиозапись в формате odd.
*/
private URL linkOdd;
public AudioMessage() {
type = AttachmentType.AUDIO_MESSAGE;
}
public AudioMessage(URL linkOdd) {
this.linkOdd = linkOdd;
}
}

View File

@ -1,69 +0,0 @@
package dev.struchkov.godfather.context.domain.content.attachment;
/**
* Вложение типа "Карта".
*
* @author upagge [08/07/2019]
*/
public class Geo extends Attachment {
/**
* Географические координаты.
*/
private GeoCoordinate geoCoordinate;
/**
* Название страны.
*/
private String country;
/**
* Название города.
*/
private String city;
private Geo() {
type = AttachmentType.GEO;
}
public static Builder builder() {
return new Geo().new Builder();
}
public GeoCoordinate getGeoCoordinate() {
return geoCoordinate;
}
public String getCountry() {
return country;
}
public String getCity() {
return city;
}
public class Builder {
private Builder() {
}
public Builder coordinate(Float lat, Float aLong) {
Geo.this.geoCoordinate = new GeoCoordinate(lat, aLong);
return this;
}
public Builder country(String countryName) {
Geo.this.country = countryName;
return this;
}
public Builder city(String cityName) {
Geo.this.city = cityName;
return this;
}
public Geo build() {
return Geo.this;
}
}
}

View File

@ -1,41 +0,0 @@
package dev.struchkov.godfather.context.domain.content.attachment;
/**
* Сущность для хранения географических координат.
*
* @author upagge [08/07/2019]
*/
public class GeoCoordinate {
/**
* Широта.
*/
private Float latitude;
/**
* Долгота.
*/
private Float longitude;
public GeoCoordinate(Float latitude, Float longitude) {
this.latitude = latitude;
this.longitude = longitude;
}
public Float getLatitude() {
return latitude;
}
public void setLatitude(Float latitude) {
this.latitude = latitude;
}
public Float getLongitude() {
return longitude;
}
public void setLongitude(Float longitude) {
this.longitude = longitude;
}
}

View File

@ -1,19 +0,0 @@
package dev.struchkov.godfather.context.domain.content.attachment;
public class Link extends Attachment {
private String url;
public Link() {
this.type = AttachmentType.LINK;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}

View File

@ -1,14 +0,0 @@
package dev.struchkov.godfather.context.exception;
/**
* Ошибка таймера.
*
* @author upagge [08/07/2019]
*/
public class TimerSettingException extends AppBotException {
public TimerSettingException(String message) {
super(message);
}
}

View File

@ -1,47 +0,0 @@
package dev.struchkov.godfather.context.repository;
import dev.struchkov.godfather.context.domain.content.Message;
import org.jetbrains.annotations.NotNull;
import java.time.LocalDateTime;
import java.util.List;
/**
* Интерфейс взаимодействия со всеми наследниками текстовых запросов пользователей.
*
* @author upagge [08/07/2019]
*/
public interface ContentRepository<T extends Message> {
/**
* Добавить сообщение в хранилище
*
* @param content Объект сообщени
* @return Идентификатор сообщения в хранилище
*/
T add(@NotNull T content);
/**
* Получить все сообщения за определенный временной диапазон
*
* @param dateFrom Начало временного диапазона
* @param dateTo Конец диапазона
* @return Список сообщений
*/
List<T> betweenByCreateDateTime(@NotNull LocalDateTime dateFrom, @NotNull LocalDateTime dateTo);
List<T> betweenByAddDateTime(@NotNull LocalDateTime dateFrom, @NotNull LocalDateTime dateTo);
/**
* Удаляет данные за указанный период
*
* @param dateFrom Дата начала
* @param dateTo Дата окончания
*/
void deleteAllByAddDateBetween(@NotNull LocalDateTime dateFrom, @NotNull LocalDateTime dateTo);
void deleteAllByAddDateBefore(@NotNull LocalDateTime date);
void deleteAllByAddDateAfter(@NotNull LocalDateTime date);
}

View File

@ -1,16 +0,0 @@
package dev.struchkov.godfather.context.repository;
import java.util.Optional;
import java.util.Set;
public interface PersonSettingRepository {
Set<Long> findAllByAllowedProcessing(Set<Long> personIds);
void disableMessageProcessing(Long personId);
void enableMessageProcessing(Long personId);
Optional<Boolean> findStateByPersonId(Long personId);
}

View File

@ -1,76 +0,0 @@
package dev.struchkov.godfather.context.repository.impl.local;
import dev.struchkov.godfather.context.domain.content.Mail;
import dev.struchkov.godfather.context.repository.ContentRepository;
import org.jetbrains.annotations.NotNull;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
/**
* Локальная реализация репозитория на основе {@link ArrayList} для взаимодействия с сущностью {@link Mail}.
*
* @author upagge [27/07/2019]
*/
public class MailRepositoryList implements ContentRepository<Mail> {
private final List<Mail> mails = new ArrayList<>();
private Long count = 0L;
@Override
public Mail add(Mail mail) {
mail.setId(count++);
mails.add(mail);
return mail;
}
@Override
public List<Mail> betweenByCreateDateTime(@NotNull LocalDateTime dateFrom, @NotNull LocalDateTime dateTo) {
ArrayList<Mail> rezultMails = new ArrayList<>();
for (int i = mails.size() - 1; i >= 0; i--) {
Mail mail = mails.get(i);
if (isTimePeriod(dateFrom, dateTo, mail.getAddDate())) {
rezultMails.add(mail);
} else if (mail.getCreateDate().isBefore(dateFrom)) {
break;
}
}
return rezultMails;
}
@Override
public List<Mail> betweenByAddDateTime(@NotNull LocalDateTime dateFrom, @NotNull LocalDateTime dateTo) {
ArrayList<Mail> rezultMails = new ArrayList<>();
for (int i = mails.size() - 1; i >= 0; i--) {
Mail mail = mails.get(i);
LocalDateTime addDate = mail.getAddDate();
if (isTimePeriod(dateFrom, dateTo, addDate)) {
rezultMails.add(mail);
} else if (addDate.isBefore(dateFrom)) {
break;
}
}
return rezultMails;
}
@Override
public void deleteAllByAddDateBetween(@NotNull LocalDateTime dateFrom, @NotNull LocalDateTime dateTo) {
mails.removeIf(mail -> dateFrom.isBefore(mail.getAddDate()) && dateTo.isAfter(mail.getAddDate()));
}
@Override
public void deleteAllByAddDateBefore(@NotNull LocalDateTime date) {
mails.removeIf(mail -> date.isBefore(mail.getAddDate()));
}
@Override
public void deleteAllByAddDateAfter(@NotNull LocalDateTime date) {
mails.removeIf(mail -> date.isAfter(mail.getAddDate()));
}
private boolean isTimePeriod(@NotNull LocalDateTime dateFrom, @NotNull LocalDateTime dateTo, @NotNull LocalDateTime dateTime) {
return dateFrom.isBefore(dateTime) && dateTo.isAfter(dateTime);
}
}

View File

@ -1,9 +0,0 @@
package dev.struchkov.godfather.context.service;
import dev.struchkov.godfather.context.domain.content.Message;
public interface EventProvider<M extends Message> {
void sendEvent(M message);
}

View File

@ -1,12 +0,0 @@
package dev.struchkov.godfather.context.service;
import dev.struchkov.godfather.context.domain.content.Mail;
/**
* Интерфейс для взаимодействия с личными сообщениями.
*
* @author upagge [08/07/2019]
*/
public interface MailService extends MessageService<Mail> {
}

View File

@ -1,49 +0,0 @@
package dev.struchkov.godfather.context.service;
import dev.struchkov.godfather.context.domain.content.Message;
import org.jetbrains.annotations.NotNull;
import java.time.LocalDateTime;
import java.util.List;
/**
* Интерфейс взаимодйствия с наследниками текстовых сообщений пользователей.
*
* @author upagge [08/07/2019]
*/
public interface MessageService<T extends Message> {
void add(@NotNull T event);
/**
* Получить список сообщений за заданный временной интервал
*
* @param dateFrom Начало интервала
* @param dateTo Конец интервала
* @return Список сообщений
*/
List<T> getByAddDateTime(@NotNull LocalDateTime dateFrom, @NotNull LocalDateTime dateTo);
/**
* Получить список ПОСЛЕДНИХ сообщений для каждого пользователя за заданных временной интервал
*
* @param dateFrom Начало интервала
* @param dateTo Конец интервала
* @return Список сообщений
*/
List<T> getLastEventByCreateDateTime(@NotNull LocalDateTime dateFrom, @NotNull LocalDateTime dateTo);
List<T> getLastEventByAddDateTime(@NotNull LocalDateTime dateFrom, @NotNull LocalDateTime dateTo);
/**
* Возвращает новые сообщения от последнего запроса.
*/
List<T> getNewMessage();
void deleteAllByAddDateBetween(@NotNull LocalDateTime dateFrom, @NotNull LocalDateTime dateTo);
void deleteAllByAddDateBefore(@NotNull LocalDateTime date);
void deleteAllByAddDateAfter(@NotNull LocalDateTime date);
}

View File

@ -1,18 +0,0 @@
package dev.struchkov.godfather.context.service;
import org.jetbrains.annotations.NotNull;
import java.util.Optional;
import java.util.Set;
public interface PersonSettingService {
Set<Long> getAllPersonIdDisableMessages(@NotNull Set<Long> personIds);
Optional<Boolean> getStateProcessingByPersonId(@NotNull Long personId);
void disableMessageProcessing(@NotNull Long personId);
void enableMessageProcessing(@NotNull Long personId);
}

View File

@ -1,113 +0,0 @@
package dev.struchkov.godfather.context.service.impl;
import dev.struchkov.godfather.context.domain.content.Mail;
import dev.struchkov.godfather.context.repository.ContentRepository;
import dev.struchkov.godfather.context.service.MailService;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.time.Clock;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class MailServiceImpl implements MailService {
private static final Logger log = LoggerFactory.getLogger(MailServiceImpl.class);
private final ContentRepository<Mail> mailRepository;
private boolean newMessage = false;
private LocalDateTime oldDateTime = LocalDateTime.now(Clock.tickSeconds(ZoneId.systemDefault()));
public MailServiceImpl(ContentRepository<Mail> mailRepository) {
this.mailRepository = mailRepository;
}
//TODO [13.04.2022]: Подобная реализация с newMessage вызовет проблемы с несколькими инстансами.
@Override
public void add(Mail mail) {
mailRepository.add(mail);
newMessage = true;
log.trace("Сообщение добавлено в репозиторий | {}", mail);
}
@Override
public List<Mail> getByAddDateTime(LocalDateTime timeFrom, LocalDateTime timeTo) {
log.trace("Запрошены все сообщения {} - {} ", timeFrom, timeTo);
return mailRepository.betweenByAddDateTime(timeFrom, timeTo);
}
@Override
public List<Mail> getLastEventByCreateDateTime(LocalDateTime timeFrom, LocalDateTime timeTo) {
log.trace("Запрошены последние сообщения {} - {} ", timeFrom, timeTo);
final List<Mail> mails = mailRepository.betweenByCreateDateTime(timeFrom, timeTo);
if (mails != null && !mails.isEmpty()) {
return findLastMailEachUser(mails);
} else {
return Collections.emptyList();
}
}
@Override
public List<Mail> getLastEventByAddDateTime(LocalDateTime timeFrom, LocalDateTime timeTo) {
log.trace("Запрошены последние сообщения {} - {} ", timeFrom, timeTo);
final List<Mail> mails = mailRepository.betweenByAddDateTime(timeFrom, timeTo);
if (mails != null && !mails.isEmpty()) {
return findLastMailEachUser(mails);
} else {
return Collections.emptyList();
}
}
@Override
public List<Mail> getNewMessage() {
final LocalDateTime newData = LocalDateTime.now(Clock.tickSeconds(ZoneId.systemDefault())).plusNanos(999999999);
if (newMessage) {
final List<Mail> lastEventByAddDateTime = getLastEventByAddDateTime(oldDateTime, newData);
newMessage = false;
oldDateTime = newData;
return lastEventByAddDateTime;
}
return Collections.emptyList();
}
@Override
public void deleteAllByAddDateBetween(@NotNull LocalDateTime dateFrom, @NotNull LocalDateTime dateTo) {
mailRepository.deleteAllByAddDateBetween(dateFrom, dateTo);
}
@Override
public void deleteAllByAddDateBefore(@NotNull LocalDateTime date) {
mailRepository.deleteAllByAddDateBefore(date);
}
@Override
public void deleteAllByAddDateAfter(@NotNull LocalDateTime date) {
mailRepository.deleteAllByAddDateAfter(date);
}
/**
* Возвращает только последнее сообщение каждого пользователя переданного из списка.
*/
private List<Mail> findLastMailEachUser(List<Mail> mails) {
final Set<Long> people = new HashSet<>();
final List<Mail> returnMails = new ArrayList<>();
for (int i = mails.size() - 1; i >= 0; i--) {
if (!people.contains(mails.get(i).getPersonId())) {
returnMails.add(mails.get(i));
people.add(mails.get(i).getPersonId());
}
}
if (!returnMails.isEmpty()) {
return returnMails;
} else {
return Collections.emptyList();
}
}
}

View File

@ -1,10 +0,0 @@
package dev.struchkov.godfather.context.service.usercode;
import dev.struchkov.godfather.context.domain.content.Message;
@FunctionalInterface
public interface CheckData<C extends Message> {
boolean checked(C content);
}

View File

@ -1,10 +0,0 @@
package dev.struchkov.godfather.context.service.usercode;
import java.util.List;
@FunctionalInterface
public interface Insert {
List<String> insert(Long personId);
}

View File

@ -1,10 +0,0 @@
package dev.struchkov.godfather.context.service.usercode;
import dev.struchkov.godfather.context.domain.BoxAnswer;
import dev.struchkov.godfather.context.domain.content.Message;
public interface MessageFunction<M extends Message> {
void build(M message, BoxAnswer.Builder builder);
}

View File

@ -1,11 +0,0 @@
package dev.struchkov.godfather.context.service.usercode;
import dev.struchkov.godfather.context.domain.BoxAnswer;
import dev.struchkov.godfather.context.domain.content.Message;
@FunctionalInterface
public interface ProcessingData<C extends Message> {
BoxAnswer processing(C content);
}

View File

@ -1,19 +0,0 @@
package dev.struchkov.godfather.context.utils;
import dev.struchkov.godfather.context.domain.content.EmptyMessage;
import dev.struchkov.godfather.context.domain.content.Message;
/**
* Класс для хранения объекта заглушки для {@link Message}.
*
* @author upagge [08/07/2019]
*/
public class MessageUtils {
public static final EmptyMessage EMPTY_MESSAGE = new EmptyMessage();
private MessageUtils() {
throw new IllegalStateException(Messages.UTILITY_CLASS);
}
}

View File

@ -1,16 +0,0 @@
package dev.struchkov.godfather.context.utils;
/**
* Класс утилита, содержащий сообщения об ошибках, и сообщения логирования.
*
* @author upagge [15/08/2019]
*/
public class Messages {
public static final String UTILITY_CLASS = "Класс утилита";
private Messages() {
throw new IllegalStateException(UTILITY_CLASS);
}
}

View File

@ -1,34 +0,0 @@
package dev.struchkov.godfather.context.utils;
import dev.struchkov.godfather.context.domain.BoxAnswer;
import dev.struchkov.godfather.context.domain.content.Message;
import dev.struchkov.godfather.context.service.sender.Sending;
import static dev.struchkov.haiti.utils.Exceptions.utilityClass;
/**
* Используется для отправки сообщений определенного типа.
*
* @author upagge
*/
public class Sender {
private Sender() {
utilityClass();
}
public static void sends(Message message, BoxAnswer boxAnswer, Sending sending) {
switch (sending.getType()) {
case PUBLIC:
break;
case PRIVATE:
privateSend(message, boxAnswer, sending);
break;
}
}
private static void privateSend(Message message, BoxAnswer boxAnswer, Sending sending) {
sending.send(message.getPersonId(), boxAnswer);
}
}

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>dev.struchkov.godfather</groupId>
<artifactId>bot-core</artifactId>
<version>0.0.42-SNAPSHOT</version>
</parent>
<artifactId>bot-core-main</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>dev.struchkov.godfather</groupId>
<artifactId>bot-domain-main</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -1,4 +1,6 @@
package dev.struchkov.godfather.core.utils;
package dev.struchkov.godfather.main.core.unit;
import static dev.struchkov.haiti.utils.Exceptions.utilityClass;
/**
* Тип Unit-а. Обределяет способ обработки.
@ -9,14 +11,14 @@ public class TypeUnit {
public static final String TEXT = "TEXT";
public static final String SAVE = "SAVE";
public static final String PROCESSING = "PROCESSING";
public static final String TIMER = "TIMER";
public static final String CHECK = "CHECK";
public static final String VALIDITY = "VALIDITY";
public static final String ACCOUNT = "ACCOUNT";
public static final String BACK_CMD = "BACK_CMD";
public static final String REPLACE_CMD = "REPLACE_CMD";
private TypeUnit() {
throw new IllegalStateException("Утилитарный класс");
utilityClass();
}

View File

@ -1,4 +1,4 @@
package dev.struchkov.godfather.core.domain.unit;
package dev.struchkov.godfather.main.core.unit;
/**
* Тип активации Unit-а. Определяет порядок обработки Unit.

View File

@ -1,4 +1,4 @@
package dev.struchkov.godfather.context.utils;
package dev.struchkov.godfather.main.core.utils;
import org.jetbrains.annotations.NotNull;

View File

@ -0,0 +1,21 @@
package dev.struchkov.godfather.main.core.utils;
import dev.struchkov.godfather.main.domain.content.EmptyMessage;
import dev.struchkov.godfather.main.domain.content.Message;
import static dev.struchkov.haiti.utils.Exceptions.utilityClass;
/**
* Класс для хранения объекта заглушки для {@link Message}.
*
* @author upagge [08/07/2019]
*/
public final class MessageUtils {
public static final EmptyMessage EMPTY_MESSAGE = new EmptyMessage();
private MessageUtils() {
utilityClass();
}
}

View File

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>dev.struchkov.godfather</groupId>
<artifactId>bot-core</artifactId>
<version>0.0.42-SNAPSHOT</version>
</parent>
<artifactId>bot-core-quarkus</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>dev.struchkov.godfather</groupId>
<artifactId>bot-core-main</artifactId>
</dependency>
<dependency>
<groupId>dev.struchkov.godfather</groupId>
<artifactId>bot-context-quarkus</artifactId>
</dependency>
<dependency>
<groupId>dev.struchkov.godfather</groupId>
<artifactId>bot-data-quarkus</artifactId>
</dependency>
<dependency>
<groupId>io.smallrye.reactive</groupId>
<artifactId>smallrye-mutiny-vertx-core</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,208 @@
package dev.struchkov.godfather.quarkus.core;
import dev.struchkov.autoresponder.Responder;
import dev.struchkov.godfather.exception.ConfigAppException;
import dev.struchkov.godfather.main.core.unit.TypeUnit;
import dev.struchkov.godfather.main.core.unit.UnitActiveType;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.quarkus.context.service.ErrorHandler;
import dev.struchkov.godfather.quarkus.context.service.Modifiable;
import dev.struchkov.godfather.quarkus.context.service.PersonSettingService;
import dev.struchkov.godfather.quarkus.context.service.Sending;
import dev.struchkov.godfather.quarkus.core.action.ActionUnit;
import dev.struchkov.godfather.quarkus.core.action.AnswerCheckAction;
import dev.struchkov.godfather.quarkus.core.action.AnswerSaveAction;
import dev.struchkov.godfather.quarkus.core.action.AnswerTextAction;
import dev.struchkov.godfather.quarkus.core.action.cmd.ReplaceCmdAction;
import dev.struchkov.godfather.quarkus.core.service.StorylineService;
import dev.struchkov.godfather.quarkus.core.unit.MainUnit;
import dev.struchkov.godfather.quarkus.core.unit.UnitRequest;
import dev.struchkov.haiti.context.exception.NotFoundException;
import io.smallrye.mutiny.Multi;
import io.smallrye.mutiny.Uni;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import static dev.struchkov.haiti.utils.Checker.checkEmpty;
import static dev.struchkov.haiti.utils.Checker.checkNotNull;
import static java.lang.Boolean.TRUE;
import static java.util.Collections.emptyList;
import static java.util.Collections.emptySet;
public class GeneralAutoResponder<M extends Message> {
private final PersonSettingService personSettingService;
private final StorylineService<M> storyLineService;
protected Map<String, ActionUnit> actionUnitMap = new HashMap<>();
protected List<Modifiable<M>> modifiable;
private ErrorHandler errorHandler;
protected GeneralAutoResponder(
Sending sending,
PersonSettingService personSettingService,
StorylineService<M> storyLineService
) {
this.personSettingService = personSettingService;
this.storyLineService = storyLineService;
init(sending);
}
private void init(Sending sending) {
actionUnitMap.put(TypeUnit.CHECK, new AnswerCheckAction<>(sending));
actionUnitMap.put(TypeUnit.TEXT, new AnswerTextAction(sending));
actionUnitMap.put(TypeUnit.REPLACE_CMD, new ReplaceCmdAction());
}
public void initModifiable(List<Modifiable<M>> modifiable) {
this.modifiable = modifiable;
}
public void initActionUnit(String typeUnit, ActionUnit<? extends MainUnit<M>, M> actionUnit) {
if (!actionUnitMap.containsKey(typeUnit)) {
actionUnitMap.put(typeUnit, actionUnit);
} else {
throw new ConfigAppException("Обработка такого типа юнита уже зарегистрирована");
}
}
public void initSaveAction(AnswerSaveAction<M, ?> answerSaveAction) {
actionUnitMap.put(TypeUnit.SAVE, answerSaveAction);
}
/**
* Позволяет установить перехватчик и обработчик исключений, возникающих при обработке юнитов.
*/
public void setErrorHandler(ErrorHandler errorHandler) {
this.errorHandler = errorHandler;
}
public void setDefaultUnit(String unitName) {
storyLineService.setDefaultUnit(unitName);
}
public Uni<Void> processingNewMessage(M newMessage) {
return Uni.createFrom().item(newMessage)
.onItem().ifNotNull().transformToUni(
message -> personSettingService.getStateProcessingByPersonId(newMessage.getPersonId())
.replaceIfNullWith(TRUE)
.chain(
state -> {
if (TRUE.equals(state)) {
return processing(newMessage);
}
return Uni.createFrom().voidItem();
}
)
).replaceWithVoid();
}
public Uni<Void> processingNewMessages(List<M> newMessages) {
return Uni.createFrom().item(newMessages)
.onItem().ifNotNull().transformToUni(
messages -> {
if (checkEmpty(newMessages)) return Uni.createFrom().voidItem();
final Set<String> personIds = newMessages.stream()
.map(Message::getPersonId)
.collect(Collectors.toSet());
return personSettingService.getAllPersonIdDisableMessages(personIds)
.replaceIfNullWith(emptySet())
.onItem().transformToMulti(
disableIds -> {
final List<M> allowedMessages = newMessages.stream()
.filter(message -> !disableIds.contains(message.getPersonId()))
.toList();
return Multi.createFrom().iterable(allowedMessages);
}
)
.onItem().transform(this::processing)
.toUni().replaceWithVoid();
}
);
}
private Uni<Void> processing(M message) {
return Uni.createFrom().item(message)
.onItem().ifNotNull().transform(m -> modifiable)
.replaceIfNullWith(emptyList())
.onItem().transformToMulti(modifiables -> Multi.createFrom().iterable(modifiables))
.onItem().transformToUni(mModifiable -> mModifiable.change(message))
.concatenate().toUni().replaceWith(
storyLineService.getNextUnitByPersonId(message.getPersonId())
.onItem().ifNotNull().transformToUni(
nextUnits -> Uni.createFrom().optional(
Responder.nextUnit(message, nextUnits).or(storyLineService::getDefaultUnit)
)
).onItem().ifNotNull().transformToUni(answerUnit -> answer(UnitRequest.of(answerUnit, message)))
);
}
public Uni<Void> answer(UnitRequest<MainUnit, M> unitRequest) {
return getAction(unitRequest)
.chain(request -> activeUnitAfter(unitRequest))
.onFailure().call(
throwable -> {
if (checkNotNull(errorHandler)) {
return errorHandler.handle(unitRequest.getMessage(), throwable);
}
return Uni.createFrom().voidItem();
}
)
.replaceWithVoid();
}
private Uni<UnitRequest<MainUnit, M>> activeUnitAfter(UnitRequest<MainUnit, M> unitRequest) {
final Set<MainUnit<M>> nextUnits = unitRequest.getUnit().getNextUnits();
if (checkNotNull(nextUnits)) {
Optional<MainUnit<M>> first = nextUnits.stream()
.filter(unit -> UnitActiveType.AFTER.equals(unit.getActiveType()))
.findFirst();
if (first.isPresent()) {
return Uni.createFrom().voidItem().onItem().transformToUni(
v -> getAction(UnitRequest.of(first.get(), unitRequest.getMessage()))
)
.onItem().transformToUni(
uR -> activeUnitAfter(UnitRequest.of(first.get(), unitRequest.getMessage()))
);
}
}
return Uni.createFrom().item(unitRequest);
}
private Uni<UnitRequest<MainUnit, M>> getAction(UnitRequest<MainUnit, M> unitRequest) {
final MainUnit<M> unit = unitRequest.getUnit();
final M message = unitRequest.getMessage();
final String typeUnit = unit.getType();
if (actionUnitMap.containsKey(typeUnit)) {
ActionUnit<MainUnit, M> actionUnit = actionUnitMap.get(typeUnit);
return actionUnit.action(unitRequest)
.onItem().transformToUni(
newUnitRequest -> {
final Optional<MainUnit<M>> optDefaultUnit = storyLineService.getDefaultUnit();
if (!unit.isNotSaveHistory() && (optDefaultUnit.isEmpty() || !optDefaultUnit.get().equals(unit))) {
return Uni.combine().all().unis(
Uni.createFrom().item(newUnitRequest),
storyLineService.save(message.getPersonId(), unit.getName(), message)
).asTuple();
}
return Uni.combine().all().unis(Uni.createFrom().item(newUnitRequest), Uni.createFrom().voidItem()).asTuple();
}
).onItem().transformToUni(
t -> {
final UnitRequest<MainUnit, M> newUnitRequest = t.getItem1();
final MainUnit<M> newUnit = newUnitRequest.getUnit();
return !unit.equals(newUnit) ? getAction(newUnitRequest) : Uni.createFrom().item(unitRequest);
}
);
} else {
throw new NotFoundException("ActionUnit для типа {0} не зарегистрирован", unit.getType());
}
}
}

View File

@ -0,0 +1,61 @@
package dev.struchkov.godfather.quarkus.core;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.quarkus.core.unit.MainUnit;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import static dev.struchkov.haiti.utils.Checker.checkNull;
import static dev.struchkov.haiti.utils.Inspector.isNotNull;
public class Storyline<M extends Message> {
private final Set<MainUnit<M>> startingUnits = new HashSet<>();
private final Set<MainUnit<M>> globalUnits = new HashSet<>();
private final Map<String, MainUnit<M>> units = new HashMap<>();
public Storyline(Set<MainUnit<M>> startingUnits, Map<String, MainUnit<M>> units) {
this.startingUnits.addAll(startingUnits);
this.units.putAll(units);
}
public void addGlobalUnits(Set<MainUnit<M>> globalUnits) {
this.globalUnits.addAll(globalUnits);
}
public Set<MainUnit<M>> getGlobalUnits() {
return globalUnits;
}
/**
* Получить юнит по названию.
*
* @param unitName Название юнита.
*/
public Optional<MainUnit<M>> getUnit(String unitName) {
isNotNull(unitName);
return Optional.ofNullable(units.get(unitName));
}
public Set<MainUnit<M>> getStartingUnits() {
return startingUnits;
}
//TODO [22.06.2022]: Временное решение ленивой связки юнитов, пока не будет реализован нормальный механизм.
public void link(@NotNull String firstName, @NotNull String secondName) {
isNotNull(firstName, secondName);
final MainUnit<M> firstUnit = units.get(firstName);
final MainUnit<M> secondUnit = units.get(secondName);
isNotNull(firstUnit, secondUnit);
if (checkNull(firstUnit.getNextUnits())) {
firstUnit.setNextUnits(new HashSet<>());
}
firstUnit.getNextUnits().add(secondUnit);
}
}

View File

@ -1,10 +1,10 @@
package dev.struchkov.godfather.core;
package dev.struchkov.godfather.quarkus.core;
import dev.struchkov.godfather.context.domain.UnitDefinition;
import dev.struchkov.godfather.context.domain.annotation.Unit;
import dev.struchkov.godfather.context.exception.UnitConfigException;
import dev.struchkov.godfather.core.domain.unit.LazyUnit;
import dev.struchkov.godfather.core.domain.unit.MainUnit;
import dev.struchkov.godfather.exception.UnitConfigException;
import dev.struchkov.godfather.main.domain.UnitDefinition;
import dev.struchkov.godfather.main.domain.annotation.Unit;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.quarkus.core.unit.MainUnit;
import dev.struchkov.haiti.utils.Inspector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -21,20 +21,21 @@ import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import static dev.struchkov.godfather.context.exception.UnitConfigException.unitConfigException;
import static dev.struchkov.godfather.exception.UnitConfigException.unitConfigException;
public class StorylineMaker {
public class StorylineFactory<M extends Message> {
private static final Logger log = LoggerFactory.getLogger(StorylineMaker.class);
private static final Logger log = LoggerFactory.getLogger(StorylineFactory.class);
private final List<Object> configurations = new ArrayList<>();
private final Map<String, UnitDefinition> unitDefinitions = new HashMap<>();
private final Map<String, MainUnit> unitMap = new HashMap<>();
private final Set<String> lazyUnits = new HashSet<>();
private final Set<String> mainUnits = new HashSet<>();
private final Map<String, MainUnit<M>> unitMap = new HashMap<>();
public StorylineMaker(List<Object> unitConfigurations) {
private final Set<String> mainUnits = new HashSet<>();
private final Set<String> globalUnits = new HashSet<>();
public StorylineFactory(List<Object> unitConfigurations) {
this.configurations.addAll(unitConfigurations);
}
@ -42,45 +43,36 @@ public class StorylineMaker {
return unitDefinitions;
}
public Map<String, MainUnit> getUnitMap() {
public Map<String, MainUnit<M>> getUnitMap() {
return unitMap;
}
public StoryLine createStoryLine() {
public Storyline<M> createStoryLine() {
generateUnitDefinitions();
try {
createUnitMap();
createLazy();
final Set<MainUnit> mainUnit = getMainUnit();
return new StoryLine(mainUnit, unitMap);
final Set<MainUnit<M>> mainUnit = getMainUnit();
final Set<MainUnit<M>> globalUnit = getGlobalUnit();
final Storyline<M> storyline = new Storyline<>(mainUnit, unitMap);
storyline.addGlobalUnits(globalUnit);
return storyline;
} catch (IllegalAccessException | InvocationTargetException e) {
log.error(e.getMessage(), e);
}
throw new UnitConfigException("Ошибка построения StoryLine");
}
private Set<MainUnit> getMainUnit() {
private Set<MainUnit<M>> getMainUnit() {
Inspector.isNotEmpty(mainUnits, unitConfigException("Не задан ни один mainUnit. Установите хотя бы для одного Unit флаг mainUnit"));
return mainUnits.stream()
.map(unitMap::get)
.collect(Collectors.toSet());
}
private void createLazy() throws IllegalAccessException, InvocationTargetException {
final List<UnitDefinition> lazyDefinitions = unitDefinitions.values().stream()
.filter(UnitDefinition::isLazy)
.toList();
for (UnitDefinition lazyDefinition : lazyDefinitions) {
final MainUnit lazyUnit = createUnit(lazyDefinition);
unitMap.put(lazyDefinition.getName(), lazyUnit);
for (String dependentUnit : lazyDefinition.getDependentUnits()) {
final MainUnit mainUnit = unitMap.get(dependentUnit);
final Set<MainUnit> nextUnits = mainUnit.getNextUnits();
if (nextUnits != null) {
nextUnits.add(lazyUnit);
}
}
}
private Set<MainUnit<M>> getGlobalUnit() {
return globalUnits.stream()
.map(unitMap::get)
.collect(Collectors.toSet());
}
private void createUnitMap() throws IllegalAccessException, InvocationTargetException {
@ -89,20 +81,12 @@ public class StorylineMaker {
final Set<String> nextUnitNames = unitDefinition.getNextUnitNames();
if (nextUnitNames.isEmpty() || unitMap.keySet().containsAll(nextUnitNames)) {
createUnit(unitDefinition);
} else if (unitDefinition.isLazy()) {
createLazyUnit(unitDefinition);
}
}
}
}
private void createLazyUnit(UnitDefinition unitDefinition) {
final String unitName = unitDefinition.getName();
unitMap.put(unitName, LazyUnit.create(unitName, unitDefinition));
}
private MainUnit createUnit(UnitDefinition unitDefinition) throws IllegalAccessException, InvocationTargetException {
private MainUnit<M> createUnit(UnitDefinition unitDefinition) throws IllegalAccessException, InvocationTargetException {
final Object objectConfig = unitDefinition.getObjectConfig();
final String currentUnitName = unitDefinition.getName();
final Method method = unitDefinition.getMethod();
@ -112,13 +96,12 @@ public class StorylineMaker {
.map(Unit::value)
.map(unitMap::get)
.toArray();
MainUnit newUnit = (MainUnit) method.invoke(objectConfig, nextUnits);
MainUnit<M> newUnit = (MainUnit<M>) method.invoke(objectConfig, nextUnits);
newUnit.setName(currentUnitName);
unitMap.put(currentUnitName, newUnit);
final Set<String> dependentUnitsName = unitDefinition.getDependentUnits();
dependentUnitsName.removeAll(lazyUnits);
for (String dependentUnitName : dependentUnitsName) {
final Set<String> dependentNextUnitNames = unitDefinitions.get(dependentUnitName).getNextUnitNames();
if (unitMap.keySet().containsAll(dependentNextUnitNames)) {
@ -145,14 +128,13 @@ public class StorylineMaker {
unitDefinition.setName(unitName);
unitDefinition.setMethod(method);
unitDefinition.setObjectConfig(config);
unitDefinition.setLazy(unitConfig.lazy());
if (unitConfig.lazy()) {
lazyUnits.add(unitName);
}
if (unitConfig.mainUnit()) {
if (unitConfig.main()) {
mainUnits.add(unitName);
}
if (unitConfig.global()) {
globalUnits.add(unitName);
}
final Parameter[] nextUnits = method.getParameters();
if (nextUnits.length > 0) {

View File

@ -0,0 +1,23 @@
package dev.struchkov.godfather.quarkus.core.action;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.quarkus.core.unit.MainUnit;
import dev.struchkov.godfather.quarkus.core.unit.UnitRequest;
import io.smallrye.mutiny.Uni;
/**
* Интерфейс для обработки Unit-ов.
*
* @author upagge [11/07/2019]
*/
@FunctionalInterface
public interface ActionUnit<U extends MainUnit, M extends Message> {
/**
* Метод обработки Unit-а.
*
* @return Новый Unit, который может нуждаться в обработке
*/
Uni<UnitRequest<MainUnit, M>> action(UnitRequest<U, M> unitRequest);
}

View File

@ -0,0 +1,61 @@
package dev.struchkov.godfather.quarkus.core.action;
import dev.struchkov.godfather.main.domain.BoxAnswer;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.quarkus.context.service.Sending;
import dev.struchkov.godfather.quarkus.core.unit.AnswerCheck;
import dev.struchkov.godfather.quarkus.core.unit.MainUnit;
import dev.struchkov.godfather.quarkus.core.unit.UnitRequest;
import io.smallrye.mutiny.Uni;
import java.util.Objects;
import static dev.struchkov.haiti.utils.Checker.checkNotNull;
import static dev.struchkov.haiti.utils.Checker.checkTrue;
/**
* Обработчик Unit-а {@link AnswerCheck}.
*
* @author upagge [11/07/2019]
*/
public class AnswerCheckAction<M extends Message> implements ActionUnit<AnswerCheck<M>, M> {
private final Sending sending;
public AnswerCheckAction(Sending sending) {
this.sending = sending;
}
@Override
public Uni<UnitRequest<MainUnit, M>> action(UnitRequest<AnswerCheck<M>, M> unitRequest) {
final AnswerCheck<M> unit = unitRequest.getUnit();
final M message = unitRequest.getMessage();
return unit.getCheck().checked(message)
.onItem().call(checkValue -> {
if (checkTrue(checkValue)) {
final BoxAnswer answerIfTrue = unit.getIntermediateAnswerIfTrue();
if (checkNotNull(answerIfTrue)) {
answerIfTrue.setRecipientIfNull(message.getPersonId());
return sending.send(answerIfTrue);
}
} else {
final BoxAnswer answerIfFalse = unit.getIntermediateAnswerIfFalse();
if (checkNotNull(answerIfFalse)) {
answerIfFalse.setRecipientIfNull(message.getPersonId());
return sending.send(answerIfFalse);
}
}
return Uni.createFrom().voidItem();
})
.onItem().transform(
checkValue -> {
if (checkTrue(checkValue)) {
return UnitRequest.of(Objects.requireNonNullElse(unit.getUnitTrue(), unit), message);
} else {
return UnitRequest.of(Objects.requireNonNullElse(unit.getUnitFalse(), unit), message);
}
}
);
}
}

View File

@ -0,0 +1,75 @@
package dev.struchkov.godfather.quarkus.core.action;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.quarkus.context.service.Pusher;
import dev.struchkov.godfather.quarkus.core.unit.AnswerSave;
import dev.struchkov.godfather.quarkus.core.unit.MainUnit;
import dev.struchkov.godfather.quarkus.core.unit.UnitRequest;
import dev.struchkov.godfather.quarkus.core.unit.func.CheckSave;
import dev.struchkov.godfather.quarkus.core.unit.func.PreservableData;
import dev.struchkov.godfather.quarkus.data.preser.AnswerSavePreservable;
import io.smallrye.mutiny.Uni;
import static dev.struchkov.haiti.utils.Checker.checkNotNull;
/**
* Обработчик Unit-а {@link AnswerSave}.
*
* @author upagge [11/07/2019]
*/
public class AnswerSaveAction<M extends Message, D> implements ActionUnit<AnswerSave<M, D>, M> {
@Override
public Uni<UnitRequest<MainUnit, M>> action(UnitRequest<AnswerSave<M, D>, M> unitRequest) {
final AnswerSave<M, D> answerSave = unitRequest.getUnit();
final M message = unitRequest.getMessage();
final AnswerSavePreservable<D> preservable = answerSave.getPreservable();
final String personId = message.getPersonId();
final CheckSave<M> checkSave = answerSave.getCheckSave();
if (checkNotNull(checkSave)) {
return Uni.createFrom().voidItem()
.onItem().transformToUni(
v -> checkSave.check(message)
.onItem().transform(
unit -> {
if (checkNotNull(unit)) {
return UnitRequest.of(unit, message);
}
return UnitRequest.of(answerSave, message);
}
)
);
}
final PreservableData<D, M> preservableData = answerSave.getPreservableData();
final Pusher<D> pusher = answerSave.getPusher();
return Uni.createFrom().voidItem()
.onItem().transformToUni(
v -> {
if (checkNotNull(preservableData)) {
return preservableData.getData(message);
}
return Uni.createFrom().nullItem();
}
).onItem().transformToUni(
dataFromSave -> {
if (checkNotNull(dataFromSave)) {
return preservable.save(personId, answerSave.getKey(), dataFromSave);
}
return Uni.createFrom().nullItem();
}
).onItem().transformToUni(
v -> {
if (checkNotNull(pusher)) {
return preservable.push(personId, pusher);
}
return Uni.createFrom().nullItem();
}
).onItem().transform(
v -> UnitRequest.of(answerSave, message)
);
}
}

View File

@ -0,0 +1,59 @@
package dev.struchkov.godfather.quarkus.core.action;
import dev.struchkov.godfather.main.core.utils.InsertWords;
import dev.struchkov.godfather.main.domain.BoxAnswer;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.quarkus.context.service.Sending;
import dev.struchkov.godfather.quarkus.core.unit.AnswerText;
import dev.struchkov.godfather.quarkus.core.unit.MainUnit;
import dev.struchkov.godfather.quarkus.core.unit.UnitRequest;
import io.smallrye.mutiny.Uni;
import static dev.struchkov.haiti.utils.Checker.checkNotEmpty;
import static dev.struchkov.haiti.utils.Checker.checkNotNull;
/**
* Обработчик Unit-а {@link AnswerText}.
*
* @author upagge [11/07/2019]
*/
public class AnswerTextAction implements ActionUnit<AnswerText<Message>, Message> {
private final Sending sending;
public AnswerTextAction(Sending sending) {
this.sending = sending;
}
@Override
public Uni<UnitRequest<MainUnit, Message>> action(UnitRequest<AnswerText<Message>, Message> unitRequest) {
final Message message = unitRequest.getMessage();
final AnswerText<Message> unit = unitRequest.getUnit();
return Uni.createFrom().voidItem()
.chain(request -> unit.getAnswer().processing(message))
.onItem().ifNotNull().transformToUni(boxAnswer -> replaceMarkers(unit, message, boxAnswer))
.onItem().ifNotNull().transformToUni(boxAnswer -> {
final Sending answerTextSending = unit.getSending();
boxAnswer.setRecipientIfNull(message.getPersonId());
if (checkNotNull(answerTextSending)) {
return answerTextSending.send(boxAnswer);
} else {
return sending.send(boxAnswer);
}
}).replaceWith(UnitRequest.of(unit, message));
}
private Uni<BoxAnswer> replaceMarkers(AnswerText<Message> answerText, Message message, BoxAnswer boxAnswer) {
return Uni.createFrom().item(answerText.getInsert())
.onItem().ifNotNull().transformToUni(insert -> insert.insert(message.getPersonId()))
.onItem().ifNotNull().transform(words -> {
if (checkNotEmpty(words)) {
final String newMessage = InsertWords.insert(boxAnswer.getMessage(), words);
boxAnswer.setMessage(newMessage);
}
return boxAnswer;
})
.replaceIfNullWith(boxAnswer);
}
}

View File

@ -0,0 +1,19 @@
package dev.struchkov.godfather.quarkus.core.action.cmd;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.quarkus.core.action.ActionUnit;
import dev.struchkov.godfather.quarkus.core.unit.MainUnit;
import dev.struchkov.godfather.quarkus.core.unit.UnitRequest;
import dev.struchkov.godfather.quarkus.core.unit.cmd.ReplaceCmd;
import io.smallrye.mutiny.Uni;
public class ReplaceCmdAction implements ActionUnit<ReplaceCmd<Message>, Message> {
@Override
public Uni<UnitRequest<MainUnit, Message>> action(UnitRequest<ReplaceCmd<Message>, Message> unitRequest) {
final ReplaceCmd<Message> unit = unitRequest.getUnit();
final Message message = unitRequest.getMessage();
return Uni.createFrom().item(UnitRequest.of(unit.getThisUnit(), message));
}
}

View File

@ -0,0 +1,45 @@
package dev.struchkov.godfather.quarkus.core.action.cmd;
import dev.struchkov.godfather.main.domain.StorylineHistory;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.quarkus.core.action.ActionUnit;
import dev.struchkov.godfather.quarkus.core.service.StorylineService;
import dev.struchkov.godfather.quarkus.core.unit.MainUnit;
import dev.struchkov.godfather.quarkus.core.unit.UnitRequest;
import dev.struchkov.godfather.quarkus.core.unit.cmd.RollBackCmd;
import io.smallrye.mutiny.Uni;
import static dev.struchkov.godfather.exception.RollBackException.rollBackException;
public class RollBackCmdAction<M extends Message> implements ActionUnit<RollBackCmd<M>, M> {
private final StorylineService<M> storyLineService;
public RollBackCmdAction(StorylineService<M> storyLineService) {
this.storyLineService = storyLineService;
}
@Override
public Uni<UnitRequest<MainUnit, M>> action(UnitRequest<RollBackCmd<M>, M> unitRequest) {
final RollBackCmd<M> unit = unitRequest.getUnit();
final M message = unitRequest.getMessage();
final int countToBack = unit.getCountBack();
final String rollbackUnitName = unit.getRollbackUnitName();
final Uni<StorylineHistory> uniHistory = (rollbackUnitName != null)
? storyLineService.replaceUserToBack(message.getPersonId(), rollbackUnitName).onItem().ifNull().failWith(rollBackException("Юнит для возвращения не был найден"))
: storyLineService.replaceUserToBack(message.getPersonId(), countToBack).onItem().ifNull().failWith(rollBackException("Юнит для возвращения не был найден"));
return uniHistory
.onItem().transform(
history -> {
final String unitName = history.getUnitName();
final MainUnit<M> nextUnit = storyLineService.getUnitByName(unitName).orElse(unit);
final M oldMessage = (M) history.getMessage();
return UnitRequest.of(nextUnit, oldMessage);
}
);
}
}

View File

@ -0,0 +1,26 @@
package dev.struchkov.godfather.quarkus.core.provider;
import dev.struchkov.godfather.main.domain.content.Mail;
import dev.struchkov.godfather.quarkus.context.service.EventHandler;
import dev.struchkov.godfather.quarkus.core.GeneralAutoResponder;
import io.smallrye.mutiny.Uni;
public class StoryLineHandler implements EventHandler<Mail> {
private final GeneralAutoResponder<Mail> generalAutoResponder;
public StoryLineHandler(GeneralAutoResponder<Mail> generalAutoResponder) {
this.generalAutoResponder = generalAutoResponder;
}
@Override
public Uni<Void> handle(Mail message) {
return generalAutoResponder.processingNewMessage(message);
}
@Override
public String getEventType() {
return Mail.TYPE;
}
}

View File

@ -0,0 +1,42 @@
package dev.struchkov.godfather.quarkus.core.service;
import dev.struchkov.godfather.quarkus.context.service.PersonSettingService;
import dev.struchkov.godfather.quarkus.data.repository.PersonSettingRepository;
import dev.struchkov.haiti.utils.Inspector;
import io.smallrye.mutiny.Uni;
import org.jetbrains.annotations.NotNull;
import java.util.Set;
public class PersonSettingServiceImpl implements PersonSettingService {
private final PersonSettingRepository personSettingRepository;
public PersonSettingServiceImpl(PersonSettingRepository personSettingRepository) {
this.personSettingRepository = personSettingRepository;
}
@Override
public Uni<Set<String>> getAllPersonIdDisableMessages(@NotNull Set<String> personIds) {
Inspector.isNotNull(personIds);
return personSettingRepository.findAllByAllowedProcessing(personIds);
}
@Override
public Uni<Boolean> getStateProcessingByPersonId(@NotNull String personId) {
return personSettingRepository.findStateByPersonId(personId);
}
@Override
public Uni<Void> disableMessageProcessing(@NotNull String personId) {
Inspector.isNotNull(personId);
return personSettingRepository.disableMessageProcessing(personId);
}
@Override
public Uni<Void> enableMessageProcessing(@NotNull String personId) {
Inspector.isNotNull(personId);
return personSettingRepository.enableMessageProcessing(personId);
}
}

View File

@ -0,0 +1,59 @@
package dev.struchkov.godfather.quarkus.core.service;
import dev.struchkov.godfather.main.domain.ContextKey;
import dev.struchkov.godfather.quarkus.data.StorylineContext;
import io.smallrye.mutiny.Uni;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.Map;
import static dev.struchkov.haiti.context.exception.NotFoundException.notFoundException;
import static dev.struchkov.haiti.utils.Inspector.isNotNull;
public class StorylineContextMapImpl implements StorylineContext {
private final Map<String, Map<String, Object>> map = new HashMap<>();
public Uni<Void> save(@NotNull String personId, @NotNull ContextKey<?> key, Object objectForSave) {
isNotNull(personId, key);
map.computeIfAbsent(personId, k -> new HashMap<>()).put(key.getValue(), objectForSave);
return Uni.createFrom().voidItem();
}
public <T> Uni<T> getByKey(@NotNull String personId, @NotNull ContextKey<T> key) {
isNotNull(personId, key);
if (map.containsKey(personId)) {
final Map<String, Object> storage = map.get(personId);
final T object = (T) storage.get(key.getValue());
if (object != null && object.getClass().equals(key.getType())) {
return Uni.createFrom().item(object);
}
}
return Uni.createFrom().nullItem();
}
@Override
public <T> Uni<T> getByKeyOrThrow(@NotNull String personId, @NotNull ContextKey<T> key) {
return getByKey(personId, key)
.onItem().ifNull().failWith(notFoundException("Не найдено значение ключа {0}, для пользователя {1}", key.getValue(), personId));
}
public Uni<Map<String, Object>> getAllSaveElement(@NotNull String personId) {
isNotNull(personId);
return Uni.createFrom().item(map.get(personId));
}
public Uni<Void> removeAll(@NotNull String personId) {
isNotNull(personId);
map.remove(personId);
return Uni.createFrom().voidItem();
}
public Uni<Void> removeByKey(@NotNull String personId, @NotNull ContextKey<?> key) {
isNotNull(personId, key);
map.computeIfAbsent(personId, k -> new HashMap<>()).remove(key.getValue());
return Uni.createFrom().voidItem();
}
}

View File

@ -0,0 +1,133 @@
package dev.struchkov.godfather.quarkus.core.service;
import dev.struchkov.godfather.main.domain.StorylineHistory;
import dev.struchkov.godfather.main.domain.UnitPointer;
import dev.struchkov.godfather.main.domain.content.Mail;
import dev.struchkov.godfather.quarkus.context.service.UnitPointerService;
import dev.struchkov.godfather.quarkus.core.Storyline;
import dev.struchkov.godfather.quarkus.core.StorylineFactory;
import dev.struchkov.godfather.quarkus.core.unit.MainUnit;
import dev.struchkov.godfather.quarkus.data.repository.StorylineRepository;
import io.smallrye.mutiny.Uni;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import static dev.struchkov.haiti.utils.Checker.checkEmpty;
import static dev.struchkov.haiti.utils.Checker.checkNotEmpty;
import static dev.struchkov.haiti.utils.Checker.checkNotNull;
import static dev.struchkov.haiti.utils.Inspector.isNotNull;
/**
* Отвечает за работу со сценарием в личных сообщениях с пользователем.
*/
public class StorylineMailService implements StorylineService<Mail> {
private final UnitPointerService unitPointerService;
private final StorylineRepository storylineRepository;
private final Storyline<Mail> storyLine;
private String defaultUnitName;
public StorylineMailService(
UnitPointerService unitPointerService,
StorylineRepository storylineRepository,
List<Object> unitConfigurations
) {
this.storyLine = new StorylineFactory<Mail>(unitConfigurations).createStoryLine();
this.unitPointerService = unitPointerService;
this.storylineRepository = storylineRepository;
}
@Override
public Uni<Void> save(@NotNull StorylineHistory storylineHistory) {
isNotNull(storylineHistory);
return storylineRepository.save(storylineHistory);
}
@Override
public Uni<MainUnit<Mail>> getUnitNameByPersonId(@NotNull String personId) {
isNotNull(personId);
return unitPointerService.getUnitNameByPersonId(personId)
.onItem().transform(
unitName -> {
if (checkNotNull(unitName)) {
return storyLine.getUnit(unitName).orElse(null);
} else {
return null;
}
}
);
}
@Override
public Uni<Set<MainUnit<Mail>>> getNextUnitByPersonId(@NotNull String personId) {
return getUnitNameByPersonId(personId)
.flatMap(
unit -> {
if (checkNotNull(unit) && checkNotEmpty(unit.getNextUnits())) {
return Uni.createFrom().item(unit.getNextUnits());
} else {
return storylineRepository.cleanHistoryByPersonId(personId)
.onItem().transform(v -> storyLine.getStartingUnits());
}
}
).map(
nextUnits -> {
if (checkEmpty(nextUnits)) {
return storyLine.getGlobalUnits();
} else {
nextUnits.addAll(storyLine.getGlobalUnits());
return nextUnits;
}
}
);
}
@Override
public Uni<Void> save(String personId, String unitName, Mail mail) {
isNotNull(personId, unitName, mail);
return unitPointerService.save(new UnitPointer(personId, unitName))
.onItem().transformToUni(u -> {
final StorylineHistory storylineHistory = new StorylineHistory();
storylineHistory.setPersonId(personId);
storylineHistory.setUnitName(unitName);
storylineHistory.setMessage(mail);
return storylineRepository.save(storylineHistory);
}).replaceWithVoid();
}
@Override
public Uni<StorylineHistory> replaceUserToBack(String personId, int countUnitsToBack) {
return storylineRepository.findByCountLast(personId, countUnitsToBack);
}
@Override
public Uni<StorylineHistory> replaceUserToBack(String personId, String unitName) {
return storylineRepository.findByCountLast(personId, unitName);
}
@Override
public Optional<MainUnit<Mail>> getDefaultUnit() {
if (defaultUnitName == null) return Optional.empty();
return storyLine.getUnit(defaultUnitName);
}
@Override
public void setDefaultUnit(String defaultUnit) {
defaultUnitName = defaultUnit;
}
//TODO [22.06.2022]: Временное решение для ленивой инициализации
@Override
public void lazyLink(String firstName, String secondName) {
storyLine.link(firstName, secondName);
}
@Override
public Optional<MainUnit<Mail>> getUnitByName(String unitName) {
return storyLine.getUnit(unitName);
}
}

View File

@ -0,0 +1,37 @@
package dev.struchkov.godfather.quarkus.core.service;
import dev.struchkov.godfather.main.domain.StorylineHistory;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.quarkus.core.unit.MainUnit;
import io.smallrye.mutiny.Uni;
import org.jetbrains.annotations.NotNull;
import java.util.Optional;
import java.util.Set;
public interface StorylineService<M extends Message> {
Uni<Void> save(@NotNull StorylineHistory storylineHistory);
Uni<MainUnit<M>> getUnitNameByPersonId(@NotNull String personId);
Uni<Set<MainUnit<M>>> getNextUnitByPersonId(@NotNull String personId);
Uni<Void> save(String personId, String name, M message);
Uni<StorylineHistory> replaceUserToBack(String personId, int countUnitsToBack);
Uni<StorylineHistory> replaceUserToBack(String personId, String unitName);
Optional<MainUnit<M>> getDefaultUnit();
/**
* Ленивая (поздняя) связка юнитов между собой. Осуществляется уже после создания сценария. С помощью данного подхода можно реализовать циклические зависимости юнитов.
*/
void lazyLink(String firstName, String secondName);
Optional<MainUnit<M>> getUnitByName(String unitName);
void setDefaultUnit(String unitName);
}

View File

@ -0,0 +1,32 @@
package dev.struchkov.godfather.quarkus.core.service;
import dev.struchkov.godfather.main.domain.UnitPointer;
import dev.struchkov.godfather.quarkus.context.service.UnitPointerService;
import dev.struchkov.godfather.quarkus.data.repository.UnitPointerRepository;
import io.smallrye.mutiny.Uni;
import org.jetbrains.annotations.NotNull;
public class UnitPointerServiceImpl implements UnitPointerService {
private final UnitPointerRepository unitPointerRepository;
public UnitPointerServiceImpl(UnitPointerRepository unitPointerRepository) {
this.unitPointerRepository = unitPointerRepository;
}
@Override
public Uni<UnitPointer> save(@NotNull UnitPointer unitPointer) {
return unitPointerRepository.save(unitPointer);
}
@Override
public Uni<String> getUnitNameByPersonId(@NotNull String personId) {
return unitPointerRepository.findUnitNameByPersonId(personId);
}
@Override
public Uni<Void> removeByPersonId(@NotNull String personId) {
return unitPointerRepository.removeByPersonId(personId);
}
}

View File

@ -0,0 +1,259 @@
package dev.struchkov.godfather.quarkus.core.unit;
import dev.struchkov.autoresponder.entity.KeyWord;
import dev.struchkov.godfather.main.core.unit.TypeUnit;
import dev.struchkov.godfather.main.core.unit.UnitActiveType;
import dev.struchkov.godfather.main.domain.BoxAnswer;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.quarkus.context.service.Accessibility;
import dev.struchkov.godfather.quarkus.core.unit.func.CheckData;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
/**
* Обработчик запроса, который реализует конструкцию IF в сценарии.
*
* @author upagge [08/07/2019]
*/
public class AnswerCheck<M extends Message> extends MainUnit<M> {
/**
* Unit для true.
*/
private final MainUnit unitTrue;
/**
* Unit для false.
*/
private final MainUnit unitFalse;
/**
* Временный ответ. Отправляется сразу после проверки условия, если оно true. Предполагается, что после условия следующий Unit может долго обрабатывать какой-то результат. Поэтому можно передать пользователю какое-то сообщение, наподобие: "Подождите идет обработка".
*/
private final BoxAnswer intermediateAnswerIfTrue;
/**
* Промежуточный ответ. Отправляется сразу после проверки условия, если оно false. Предполагается, что после условия следующий Unit может долго обрабатывать какой-то результат. Поэтому можно передать пользователю какое-то сообщение, наподобие: "Подождите идет обработка".
*/
private final BoxAnswer intermediateAnswerIfFalse;
/**
* Условие проверки.
*/
private final CheckData<M> check;
private AnswerCheck(Builder<M> builder) {
super(
builder.name,
builder.description,
builder.triggerWords,
builder.triggerPhrases,
builder.triggerCheck,
builder.triggerPatterns,
builder.matchThreshold,
builder.priority,
new HashSet<>(),
builder.activeType,
builder.notSaveHistory,
builder.accessibility,
TypeUnit.CHECK
);
unitTrue = builder.unitTrue;
unitFalse = builder.unitFalse;
check = builder.check;
intermediateAnswerIfTrue = builder.intermediateAnswerIfTrue;
intermediateAnswerIfFalse = builder.intermediateAnswerIfFalse;
}
public static <M extends Message> Builder<M> builder() {
return new Builder<>();
}
public MainUnit getUnitTrue() {
return unitTrue;
}
public MainUnit getUnitFalse() {
return unitFalse;
}
public CheckData<M> getCheck() {
return check;
}
public BoxAnswer getIntermediateAnswerIfTrue() {
return intermediateAnswerIfTrue;
}
public BoxAnswer getIntermediateAnswerIfFalse() {
return intermediateAnswerIfFalse;
}
public static final class Builder<M extends Message> {
private String name = UUID.randomUUID().toString();
private String description;
private Set<KeyWord> triggerWords;
private Set<String> triggerPhrases;
private Predicate<M> triggerCheck;
private Set<Pattern> triggerPatterns;
private Integer matchThreshold;
private Integer priority;
private UnitActiveType activeType;
private Accessibility accessibility;
private boolean notSaveHistory;
private MainUnit unitTrue;
private MainUnit unitFalse;
private CheckData<M> check;
private BoxAnswer intermediateAnswerIfFalse;
private BoxAnswer intermediateAnswerIfTrue;
private Builder() {
}
public Builder<M> name(String name) {
this.name = name;
return this;
}
public Builder<M> description(String description) {
this.description = description;
return this;
}
public Builder<M> triggerWords(Set<KeyWord> val) {
if (triggerWords == null) {
triggerWords = new HashSet<>();
}
triggerWords.addAll(val);
return this;
}
public Builder<M> triggerWord(KeyWord val) {
if (triggerWords == null) {
triggerWords = new HashSet<>();
}
triggerWords.add(val);
return this;
}
public Builder<M> triggerStringWords(Set<String> val) {
if (triggerWords == null) {
triggerWords = new HashSet<>();
}
triggerWords.addAll(val.stream().map(KeyWord::of).collect(Collectors.toSet()));
return this;
}
public Builder<M> triggerWord(String val) {
if (triggerWords == null) {
triggerWords = new HashSet<>();
}
triggerWords.add(KeyWord.of(val));
return this;
}
public Builder<M> triggerPhrase(String... val) {
if (triggerPhrases == null) {
triggerPhrases = new HashSet<>();
}
if (val.length == 1) {
triggerPhrases.add(val[0]);
} else {
triggerPhrases.addAll(Set.of(val));
}
triggerPhrases.addAll(Set.of(val));
return this;
}
public Builder<M> triggerPattern(Pattern... val) {
if (triggerPatterns == null) {
triggerPatterns = new HashSet<>();
}
if (val.length == 1) {
triggerPatterns.add(val[0]);
} else {
triggerPatterns.addAll(Set.of(val));
}
triggerPatterns.addAll(Set.of(val));
return this;
}
public Builder<M> triggerCheck(Predicate<M> trigger) {
triggerCheck = trigger;
return this;
}
public Builder<M> matchThreshold(Integer val) {
matchThreshold = val;
return this;
}
public Builder<M> priority(Integer val) {
priority = val;
return this;
}
public Builder<M> unitTrue(MainUnit unitTrue) {
this.unitTrue = unitTrue;
return this;
}
public Builder<M> unitFalse(MainUnit unitFalse) {
this.unitFalse = unitFalse;
return this;
}
public Builder<M> check(CheckData<M> check) {
this.check = check;
return this;
}
public Builder<M> accessibility(Accessibility val) {
accessibility = val;
return this;
}
public Builder<M> activeType(UnitActiveType val) {
activeType = val;
return this;
}
public Builder<M> notSaveHistory() {
notSaveHistory = true;
return this;
}
public Builder<M> intermediateAnswer(BoxAnswer val) {
intermediateAnswerIfTrue = val;
intermediateAnswerIfFalse = val;
return this;
}
public Builder<M> intermediateAnswerIfTrue(BoxAnswer val) {
intermediateAnswerIfTrue = val;
return this;
}
public Builder<M> intermediateAnswerIfFalse(BoxAnswer val) {
intermediateAnswerIfFalse = val;
return this;
}
public AnswerCheck<M> build() {
// isNotNull(check, unitConfigException("Необходимо установить параметр проверки."));
// isAnyNotNull(unitConfigException("Необходимо задать хотя бы один unit результата проверки."));
return new AnswerCheck<>(this);
}
}
}

View File

@ -0,0 +1,284 @@
package dev.struchkov.godfather.quarkus.core.unit;
import dev.struchkov.autoresponder.entity.KeyWord;
import dev.struchkov.godfather.main.core.unit.TypeUnit;
import dev.struchkov.godfather.main.core.unit.UnitActiveType;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.quarkus.context.service.Accessibility;
import dev.struchkov.godfather.quarkus.context.service.Pusher;
import dev.struchkov.godfather.quarkus.core.unit.func.CheckSave;
import dev.struchkov.godfather.quarkus.core.unit.func.PreservableData;
import dev.struchkov.godfather.quarkus.data.preser.AnswerSavePreservable;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static dev.struchkov.haiti.utils.Checker.checkNull;
/**
* Обработчик для сохранения ответов пользователя. Так же допускается скрытое сохранение.
*
* @author upagge [08/07/2019]
*/
public class AnswerSave<M extends Message, D> extends MainUnit<M> {
/**
* Объект отвечающий за сохранение - репозиторий.
*/
private final AnswerSavePreservable<D> preservable;
/**
* Ключ для данных.
*/
private final String key;
/**
* Отправка результатов.
*/
private final Pusher<D> pusher;
/**
* Данные для скрытого сохранения.
*/
private final PreservableData<D, M> preservableData;
/**
* Скрытое сохранение.
*/
private final boolean hidden;
private final CheckSave<M> checkSave;
private AnswerSave(Builder<M, D> builder) {
super(
builder.name,
builder.description,
builder.triggerWords,
builder.triggerPhrases,
builder.triggerCheck,
builder.triggerPatterns,
builder.matchThreshold,
builder.priority,
builder.nextUnits,
(builder.hidden) ? UnitActiveType.AFTER : UnitActiveType.DEFAULT,
builder.notSaveHistory,
builder.accessibility,
TypeUnit.SAVE
);
maintenanceNextUnit(nextUnits);
preservable = builder.preservable;
key = builder.key;
pusher = builder.pusher;
preservableData = builder.preservableData;
hidden = builder.hidden;
checkSave = builder.checkSave;
}
public static <M extends Message, D> Builder<M, D> builder() {
return new Builder<>();
}
private void maintenanceNextUnit(Collection<MainUnit<M>> units) {
if (units != null) {
units.forEach(mainUnit -> mainUnit.setActiveType(UnitActiveType.AFTER));
}
}
public AnswerSavePreservable<D> getPreservable() {
return preservable;
}
public String getKey() {
return key;
}
public Pusher<D> getPusher() {
return pusher;
}
public PreservableData<D, M> getPreservableData() {
return preservableData;
}
public boolean isHidden() {
return hidden;
}
public CheckSave<M> getCheckSave() {
return checkSave;
}
public static final class Builder<M extends Message, D> {
private String name = UUID.randomUUID().toString();
private String description;
private Set<MainUnit<M>> nextUnits;
private Set<KeyWord> triggerWords;
private Set<String> triggerPhrases;
private Set<Pattern> triggerPatterns;
private Predicate<M> triggerCheck;
private Integer matchThreshold;
private Integer priority;
private Accessibility accessibility;
private boolean notSaveHistory;
private AnswerSavePreservable<D> preservable;
private String key;
private Pusher<D> pusher;
private PreservableData<D, M> preservableData;
private boolean hidden;
private CheckSave<M> checkSave;
private Builder() {
}
public Builder<M, D> name(String name) {
this.name = name;
return this;
}
public Builder<M, D> description(String description) {
this.description = description;
return this;
}
public Builder<M, D> triggerWords(Set<KeyWord> val) {
if (checkNull(triggerWords)) {
triggerWords = new HashSet<>();
}
triggerWords.addAll(val);
return this;
}
public Builder<M, D> triggerWord(KeyWord val) {
if (checkNull(triggerWords)) {
triggerWords = new HashSet<>();
}
triggerWords.add(val);
return this;
}
public Builder<M, D> triggerStringWords(Set<String> val) {
if (checkNull(triggerWords)) {
triggerWords = new HashSet<>();
}
triggerWords.addAll(val.stream().map(KeyWord::of).collect(Collectors.toSet()));
return this;
}
public Builder<M, D> triggerWord(String val) {
if (checkNull(triggerWords)) {
triggerWords = new HashSet<>();
}
triggerWords.add(KeyWord.of(val));
return this;
}
public Builder<M, D> triggerPhrase(String... val) {
if (checkNull(triggerPhrases)) {
triggerPhrases = new HashSet<>();
}
if (val.length == 1) {
triggerPhrases.add(val[0]);
} else {
triggerPhrases.addAll(Set.of(val));
}
triggerPhrases.addAll(Set.of(val));
return this;
}
public Builder<M, D> triggerPattern(Pattern... val) {
if (checkNull(triggerPatterns)) {
triggerPatterns = new HashSet<>();
}
if (val.length == 1) {
triggerPatterns.add(val[0]);
} else {
triggerPatterns.addAll(Set.of(val));
}
triggerPatterns.addAll(Set.of(val));
return this;
}
public Builder<M, D> triggerCheck(Predicate<M> trigger) {
triggerCheck = trigger;
return this;
}
public Builder<M, D> matchThreshold(Integer val) {
matchThreshold = val;
return this;
}
public Builder<M, D> priority(Integer val) {
priority = val;
return this;
}
public Builder<M, D> next(MainUnit<M> val) {
if (checkNull(nextUnits)) {
nextUnits = new HashSet<>();
}
nextUnits.add(val);
return this;
}
public Builder<M, D> preservable(AnswerSavePreservable<D> val) {
this.preservable = val;
return this;
}
public Builder<M, D> key(String val) {
this.key = val;
return this;
}
public Builder<M, D> pusher(Pusher<D> val) {
this.pusher = val;
return this;
}
public Builder<M, D> preservableData(PreservableData<D, M> val) {
this.preservableData = val;
return this;
}
public Builder<M, D> hidden(boolean val) {
this.hidden = val;
return this;
}
public Builder<M, D> checkSave(CheckSave<M> val) {
this.checkSave = val;
return this;
}
public Builder<M, D> accessibility(Accessibility val) {
accessibility = val;
return this;
}
public Builder<M, D> notSaveHistory() {
notSaveHistory = true;
return this;
}
public AnswerSave<M, D> build() {
// isNotNull(preservable, "Не указан репозиторий для сохранения формы пользователя");
// if (checkNull(pusher)) {
// isNotNull(preservableData, "Не указаны данные для сохранения");
// Inspector.isNotNull(key, "Не указан ключ для сохранения");
// }
return new AnswerSave<>(this);
}
}
}

View File

@ -0,0 +1,261 @@
package dev.struchkov.godfather.quarkus.core.unit;
import dev.struchkov.autoresponder.entity.KeyWord;
import dev.struchkov.godfather.main.core.unit.TypeUnit;
import dev.struchkov.godfather.main.core.unit.UnitActiveType;
import dev.struchkov.godfather.main.domain.BoxAnswer;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.quarkus.context.service.Accessibility;
import dev.struchkov.godfather.quarkus.context.service.Sending;
import dev.struchkov.godfather.quarkus.core.unit.func.Insert;
import dev.struchkov.godfather.quarkus.core.unit.func.ProcessingData;
import io.smallrye.mutiny.Uni;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
/**
* Используется для отправки ответа пользователю.
*
* @author upagge [08/07/2019]
*/
public class AnswerText<M extends Message> extends MainUnit<M> {
/**
* Объект, который необходимо отправить пользователю.
*/
private final ProcessingData<M> answer;
/**
* Информация, которую необходимо вставить вместо маркеров в строку ответа.
*/
private final Insert insert;
/**
* Объект нестандартной отправки ответа.
*/
private final Sending sender;
private AnswerText(Builder<M> builder) {
super(
builder.name,
builder.description,
builder.triggerWords,
builder.triggerPhrases,
builder.triggerCheck,
builder.triggerPatterns,
builder.matchThreshold,
builder.priority,
builder.nextUnits,
builder.activeType,
builder.notSaveHistory,
builder.accessibility,
TypeUnit.TEXT
);
answer = builder.boxAnswer;
insert = builder.insert;
sender = builder.sending;
}
public static <M extends Message> AnswerText<M> of(String message) {
return AnswerText.<M>builder().answer(BoxAnswer.boxAnswer(message)).build();
}
public static <M extends Message> AnswerText<M> of(BoxAnswer boxAnswer) {
return AnswerText.<M>builder().answer(boxAnswer).build();
}
public static <M extends Message> Builder<M> builder() {
return new Builder<>();
}
public ProcessingData<M> getAnswer() {
return answer;
}
public Insert getInsert() {
return insert;
}
public Sending getSending() {
return sender;
}
public static final class Builder<M extends Message> {
private String name = UUID.randomUUID().toString();
private String description;
private Set<MainUnit<M>> nextUnits;
private Set<KeyWord> triggerWords;
private Set<String> triggerPhrases;
private Predicate<M> triggerCheck;
private Set<Pattern> triggerPatterns;
private Integer matchThreshold;
private Integer priority;
private UnitActiveType activeType;
private Accessibility accessibility;
private boolean notSaveHistory;
private ProcessingData<M> boxAnswer;
private Insert insert;
private Sending sending;
private Builder() {
}
public Builder<M> name(String name) {
this.name = name;
return this;
}
public Builder<M> description(String description) {
this.description = description;
return this;
}
public Builder<M> processing(Consumer<M> answer) {
this.boxAnswer = message -> {
answer.accept(message);
return null;
};
return this;
}
public Builder<M> answer(Function<M, Uni<BoxAnswer>> answer) {
this.boxAnswer = answer::apply;
return this;
}
public Builder<M> answer(BoxAnswer answer) {
this.boxAnswer = message -> Uni.createFrom().item(answer);
return this;
}
public Builder<M> answer(Supplier<BoxAnswer> answer) {
this.boxAnswer = message -> Uni.createFrom().item(answer.get());
return this;
}
public Builder<M> insert(Insert insert) {
this.insert = insert;
return this;
}
public Builder<M> sending(Sending sending) {
this.sending = sending;
return this;
}
public Builder<M> triggerWords(Set<KeyWord> val) {
if (triggerWords == null) {
triggerWords = new HashSet<>();
}
triggerWords.addAll(val);
return this;
}
public Builder<M> triggerWord(KeyWord val) {
if (triggerWords == null) {
triggerWords = new HashSet<>();
}
triggerWords.add(val);
return this;
}
public Builder<M> triggerStringWords(Set<String> val) {
if (triggerWords == null) {
triggerWords = new HashSet<>();
}
triggerWords.addAll(val.stream().map(KeyWord::of).collect(Collectors.toSet()));
return this;
}
public Builder<M> triggerWord(String val) {
if (triggerWords == null) {
triggerWords = new HashSet<>();
}
triggerWords.add(KeyWord.of(val));
return this;
}
public Builder<M> triggerPhrase(String... val) {
if (triggerPhrases == null) {
triggerPhrases = new HashSet<>();
}
if (val.length == 1) {
triggerPhrases.add(val[0]);
} else {
triggerPhrases.addAll(Set.of(val));
}
triggerPhrases.addAll(List.of(val));
return this;
}
public Builder<M> triggerPattern(Pattern... val) {
if (triggerPatterns == null) {
triggerPatterns = new HashSet<>();
}
if (val.length == 1) {
triggerPatterns.add(val[0]);
} else {
triggerPatterns.addAll(Set.of(val));
}
triggerPatterns.addAll(Set.of(val));
return this;
}
public Builder<M> triggerCheck(Predicate<M> trigger) {
triggerCheck = trigger;
return this;
}
public Builder<M> matchThreshold(Integer val) {
matchThreshold = val;
return this;
}
public Builder<M> priority(Integer val) {
priority = val;
return this;
}
public Builder<M> next(MainUnit<M> val) {
if (nextUnits == null) {
nextUnits = new HashSet<>();
}
nextUnits.add(val);
return this;
}
public Builder<M> accessibility(Accessibility val) {
accessibility = val;
return this;
}
public Builder<M> notSaveHistory() {
notSaveHistory = true;
return this;
}
public Builder<M> activeType(UnitActiveType val) {
activeType = val;
return this;
}
public AnswerText<M> build() {
// isNotNull(boxAnswer, UnitConfigException.unitConfigException("BoxAnswer обязательный параметр юнита"));
return new AnswerText<>(this);
}
}
}

View File

@ -0,0 +1,118 @@
package dev.struchkov.godfather.quarkus.core.unit;
import dev.struchkov.autoresponder.entity.KeyWord;
import dev.struchkov.autoresponder.entity.Unit;
import dev.struchkov.godfather.main.core.unit.UnitActiveType;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.quarkus.context.service.Accessibility;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.Predicate;
import java.util.regex.Pattern;
/**
* Главный обработчик {@link Unit}, от него наследуются все остальные Unit-ы.
*
* @author upagge [08/07/2019]
*/
public abstract class MainUnit<M extends Message> extends Unit<MainUnit<M>, M> {
/**
* Уникальное имя юнита
*/
private String name;
/**
* Описание юнита, что он делает. Никак не влияет на работу юнита и не участвует в ней. Возможно отображение этого текста в логах.
*/
private final String description;
/**
* Тип Unit-а.
*/
protected final String type;
/**
* Режим срабатывания Unit-а.
*/
protected UnitActiveType activeType;
/**
* Проверка доступа пользователя к юниту.
*/
private final Accessibility accessibility;
private final boolean notSaveHistory;
protected MainUnit(
String name,
String description,
Set<KeyWord> keyWords,
Set<String> phrases,
Predicate<M> triggerCheck,
Set<Pattern> patterns,
Integer matchThreshold,
Integer priority,
Set<MainUnit<M>> nextUnits,
UnitActiveType activeType,
boolean notSaveHistory,
Accessibility accessibility,
String type
) {
super(keyWords, phrases, triggerCheck, patterns, matchThreshold, priority, nextUnits);
this.name = name;
this.description = description;
this.activeType = Optional.ofNullable(activeType).orElse(UnitActiveType.DEFAULT);
this.accessibility = accessibility;
this.type = type;
this.notSaveHistory = notSaveHistory;
}
public String getType() {
return type;
}
public UnitActiveType getActiveType() {
return activeType;
}
public void setActiveType(UnitActiveType activeType) {
this.activeType = activeType;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public boolean isNotSaveHistory() {
return notSaveHistory;
}
public Optional<Accessibility> getAccessibility() {
return Optional.ofNullable(accessibility);
}
public String getDescription() {
return description;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MainUnit<?> unit = (MainUnit<?>) o;
return name.equals(unit.name);
}
@Override
public int hashCode() {
return Objects.hash(name);
}
}

View File

@ -0,0 +1,33 @@
package dev.struchkov.godfather.quarkus.core.unit;
import dev.struchkov.godfather.main.domain.content.Message;
/**
* Сущность инкапсулирует в себе данные, необходимые для обработки сценария.
*
* @param <U> Тип юнита
* @param <M> Тип сообщения
*/
public class UnitRequest<U extends MainUnit, M extends Message> {
private final U unit;
private final M message;
private UnitRequest(U unit, M message) {
this.unit = unit;
this.message = message;
}
public static <U extends MainUnit<M>, M extends Message> UnitRequest<U, M> of(U mainUnit, M message) {
return new UnitRequest<>(mainUnit, message);
}
public U getUnit() {
return unit;
}
public M getMessage() {
return message;
}
}

View File

@ -0,0 +1,164 @@
package dev.struchkov.godfather.quarkus.core.unit.cmd;
import dev.struchkov.autoresponder.entity.KeyWord;
import dev.struchkov.godfather.main.core.unit.TypeUnit;
import dev.struchkov.godfather.main.core.unit.UnitActiveType;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.quarkus.core.unit.MainUnit;
import dev.struchkov.haiti.utils.Checker;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
public class ReplaceCmd<M extends Message> extends MainUnit<M> {
private final MainUnit thisUnit;
private ReplaceCmd(Builder<M> builder) {
super(
builder.name,
builder.description,
builder.triggerWords,
builder.triggerPhrases,
builder.triggerCheck,
builder.triggerPatterns,
builder.matchThreshold,
builder.priority,
new HashSet<>(),
builder.activeType,
true,
null,
TypeUnit.REPLACE_CMD
);
this.thisUnit = builder.thisUnit;
}
public static <M extends Message> Builder<M> builder() {
return new Builder<>();
}
public MainUnit getThisUnit() {
return thisUnit;
}
public static final class Builder<M extends Message> {
private String name = UUID.randomUUID().toString();
private String description;
private Set<String> triggerPhrases;
private Predicate<M> triggerCheck;
private Set<Pattern> triggerPatterns;
private Set<KeyWord> triggerWords;
private Integer matchThreshold;
private Integer priority;
private UnitActiveType activeType = UnitActiveType.AFTER;
private MainUnit thisUnit;
private Builder() {
}
public Builder<M> name(String name) {
this.name = name;
return this;
}
public Builder<M> description(String description) {
this.description = description;
return this;
}
public Builder<M> triggerWords(Set<KeyWord> val) {
if (Checker.checkNull(triggerWords)) {
triggerWords = new HashSet<>();
}
triggerWords.addAll(val);
return this;
}
public Builder<M> triggerWord(KeyWord val) {
if (Checker.checkNull(triggerWords)) {
triggerWords = new HashSet<>();
}
triggerWords.add(val);
return this;
}
public Builder<M> triggerStringWords(Set<String> val) {
if (Checker.checkNull(triggerWords)) {
triggerWords = new HashSet<>();
}
triggerWords.addAll(val.stream().map(KeyWord::of).collect(Collectors.toSet()));
return this;
}
public Builder<M> triggerWord(String val) {
if (Checker.checkNull(triggerWords)) {
triggerWords = new HashSet<>();
}
triggerWords.add(KeyWord.of(val));
return this;
}
public Builder<M> triggerPhrase(String... val) {
if (Checker.checkNull(triggerPhrases)) {
triggerPhrases = new HashSet<>();
}
if (val.length == 1) {
triggerPhrases.add(val[0]);
} else {
triggerPhrases.addAll(Set.of(val));
}
return this;
}
public Builder<M> triggerPattern(Pattern... val) {
if (Checker.checkNull(triggerPatterns)) {
triggerPatterns = new HashSet<>();
}
if (val.length == 1) {
triggerPatterns.add(val[0]);
} else {
triggerPatterns.addAll(Set.of(val));
}
triggerPatterns.addAll(Set.of(val));
return this;
}
public Builder<M> triggerCheck(Predicate<M> trigger) {
triggerCheck = trigger;
return this;
}
public Builder<M> matchThreshold(Integer val) {
matchThreshold = val;
return this;
}
public Builder<M> priority(Integer val) {
priority = val;
return this;
}
public Builder<M> activeType(UnitActiveType val) {
activeType = val;
return this;
}
public Builder<M> thisUnit(MainUnit val) {
thisUnit = val;
return this;
}
public ReplaceCmd<M> build() {
return new ReplaceCmd<>(this);
}
}
}

View File

@ -0,0 +1,212 @@
package dev.struchkov.godfather.quarkus.core.unit.cmd;
import dev.struchkov.autoresponder.entity.KeyWord;
import dev.struchkov.godfather.exception.UnitConfigException;
import dev.struchkov.godfather.main.core.unit.TypeUnit;
import dev.struchkov.godfather.main.core.unit.UnitActiveType;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.quarkus.core.unit.MainUnit;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static dev.struchkov.haiti.utils.Checker.checkNull;
/**
* Юнит, который позволяет откатить пользователя на предыдущие юниты в сценарии с сохранением ранее введенной информации в сообщениях.
*/
public class RollBackCmd<M extends Message> extends MainUnit<M> {
/**
* Количество юнитов, на которые можно откатиться назад.
*/
private final int countBack;
/**
* Имя юнита, на который нужно вернуть пользователя.
*/
private final String rollbackUnitName;
private RollBackCmd(Builder<M> builder) {
super(
builder.name,
builder.description,
builder.triggerWords,
builder.triggerPhrases,
builder.triggerCheck,
builder.triggerPatterns,
builder.matchThreshold,
builder.priority,
new HashSet<>(),
builder.activeType,
true,
null,
TypeUnit.BACK_CMD
);
this.countBack = builder.countBack;
this.rollbackUnitName = builder.rollbackUnitName;
}
public static <M extends Message> Builder<M> builder() {
return new Builder<>();
}
public static <M extends Message> RollBackCmd<M> rollBack(int countToBack) {
return RollBackCmd.<M>builder().countBack(countToBack).build();
}
public static <M extends Message> RollBackCmd<M> singleRollBack() {
return RollBackCmd.<M>builder().countBack(1).build();
}
public static <M extends Message> RollBackCmd<M> doubleRollBack() {
return RollBackCmd.<M>builder().countBack(2).build();
}
public static <M extends Message> RollBackCmd<M> rollBack(String unitName) {
return RollBackCmd.<M>builder().rollbackUnitName(unitName).build();
}
public static <M extends Message> RollBackCmd<M> rollBack(String phrase, String unitName) {
return RollBackCmd.<M>builder().triggerPhrase(phrase).rollbackUnitName(unitName).build();
}
public int getCountBack() {
return countBack;
}
public String getRollbackUnitName() {
return rollbackUnitName;
}
public static final class Builder<M extends Message> {
private String name = UUID.randomUUID().toString();
private String description;
private Set<String> triggerPhrases;
private Predicate<M> triggerCheck;
private Set<Pattern> triggerPatterns;
private Set<KeyWord> triggerWords;
private Integer matchThreshold;
private Integer priority;
private UnitActiveType activeType = UnitActiveType.DEFAULT;
private int countBack;
private String rollbackUnitName;
private Builder() {
}
public Builder<M> name(String name) {
this.name = name;
return this;
}
public Builder<M> description(String description) {
this.description = description;
return this;
}
public Builder<M> triggerWords(Set<KeyWord> val) {
if (checkNull(triggerWords)) {
triggerWords = new HashSet<>();
}
triggerWords.addAll(val);
return this;
}
public Builder<M> triggerWord(KeyWord val) {
if (checkNull(triggerWords)) {
triggerWords = new HashSet<>();
}
triggerWords.add(val);
return this;
}
public Builder<M> triggerStringWords(Set<String> val) {
if (checkNull(triggerWords)) {
triggerWords = new HashSet<>();
}
triggerWords.addAll(val.stream().map(KeyWord::of).collect(Collectors.toSet()));
return this;
}
public Builder<M> triggerWord(String val) {
if (checkNull(triggerWords)) {
triggerWords = new HashSet<>();
}
triggerWords.add(KeyWord.of(val));
return this;
}
public Builder<M> triggerPhrase(String... val) {
if (checkNull(triggerPhrases)) {
triggerPhrases = new HashSet<>();
}
if (val.length == 1) {
triggerPhrases.add(val[0]);
} else {
triggerPhrases.addAll(Set.of(val));
}
triggerPhrases.addAll(Set.of(val));
return this;
}
public Builder<M> triggerCheck(Predicate<M> trigger) {
triggerCheck = trigger;
return this;
}
public Builder<M> triggerPattern(Pattern... val) {
if (checkNull(triggerPatterns)) {
triggerPatterns = new HashSet<>();
}
if (val.length == 1) {
triggerPatterns.add(val[0]);
} else {
triggerPatterns.addAll(Set.of(val));
}
triggerPatterns.addAll(Set.of(val));
return this;
}
public Builder<M> matchThreshold(Integer val) {
matchThreshold = val;
return this;
}
public Builder<M> priority(Integer val) {
priority = val;
return this;
}
public Builder<M> activeType(UnitActiveType val) {
activeType = val;
return this;
}
public Builder<M> countBack(int val) {
countBack = val + 1;
return this;
}
public Builder<M> rollbackUnitName(String val) {
rollbackUnitName = val;
return this;
}
public RollBackCmd<M> build() {
if (rollbackUnitName == null && countBack < 2) {
throw new UnitConfigException("Ошибка конфигурирования юнита {0}: Количество юнитов для отката не должно быть меньше 1.", name);
}
return new RollBackCmd<M>(this);
}
}
}

View File

@ -0,0 +1,11 @@
package dev.struchkov.godfather.quarkus.core.unit.func;
import dev.struchkov.godfather.main.domain.content.Message;
import io.smallrye.mutiny.Uni;
@FunctionalInterface
public interface CheckData<C extends Message> {
Uni<Boolean> checked(C content);
}

View File

@ -0,0 +1,17 @@
package dev.struchkov.godfather.quarkus.core.unit.func;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.quarkus.core.unit.MainUnit;
import io.smallrye.mutiny.Uni;
/**
* TODO: Добавить описание интерфейса.
*
* @author upagge [04/08/2019]
*/
@FunctionalInterface
public interface CheckSave<M extends Message> {
Uni<MainUnit<M>> check(M content);
}

View File

@ -0,0 +1,12 @@
package dev.struchkov.godfather.quarkus.core.unit.func;
import io.smallrye.mutiny.Uni;
import java.util.List;
@FunctionalInterface
public interface Insert {
Uni<List<String>> insert(String personId);
}

View File

@ -0,0 +1,11 @@
package dev.struchkov.godfather.quarkus.core.unit.func;
import dev.struchkov.godfather.main.domain.content.Message;
import io.smallrye.mutiny.Uni;
@FunctionalInterface
public interface PreservableData<D, M extends Message> {
Uni<D> getData(M content);
}

View File

@ -0,0 +1,11 @@
package dev.struchkov.godfather.quarkus.core.unit.func;
import dev.struchkov.godfather.main.domain.BoxAnswer;
import io.smallrye.mutiny.Uni;
@FunctionalInterface
public interface ProcessingData<C> {
Uni<BoxAnswer> processing(C content);
}

View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>bot-core</artifactId>
<groupId>dev.struchkov.godfather</groupId>
<version>0.0.42-SNAPSHOT</version>
</parent>
<artifactId>bot-core-simple</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>dev.struchkov.godfather</groupId>
<artifactId>bot-core-main</artifactId>
</dependency>
<dependency>
<groupId>dev.struchkov.godfather</groupId>
<artifactId>bot-context-simple</artifactId>
</dependency>
<dependency>
<groupId>dev.struchkov.godfather</groupId>
<artifactId>bot-data-simple</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,167 @@
package dev.struchkov.godfather.simple.core;
import dev.struchkov.autoresponder.Responder;
import dev.struchkov.godfather.exception.ConfigAppException;
import dev.struchkov.godfather.main.core.unit.TypeUnit;
import dev.struchkov.godfather.main.core.unit.UnitActiveType;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.simple.context.service.Accessibility;
import dev.struchkov.godfather.simple.context.service.ErrorHandler;
import dev.struchkov.godfather.simple.context.service.Modifiable;
import dev.struchkov.godfather.simple.context.service.PersonSettingService;
import dev.struchkov.godfather.simple.context.service.Sending;
import dev.struchkov.godfather.simple.core.action.ActionUnit;
import dev.struchkov.godfather.simple.core.action.AnswerCheckAction;
import dev.struchkov.godfather.simple.core.action.AnswerSaveAction;
import dev.struchkov.godfather.simple.core.action.AnswerTextAction;
import dev.struchkov.godfather.simple.core.action.cmd.ReplaceCmdAction;
import dev.struchkov.godfather.simple.core.service.StorylineService;
import dev.struchkov.godfather.simple.core.unit.MainUnit;
import dev.struchkov.godfather.simple.core.unit.UnitRequest;
import dev.struchkov.haiti.context.exception.NotFoundException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
public class GeneralAutoResponder<M extends Message> {
private final PersonSettingService personSettingService;
private final StorylineService<M> storyLineService;
protected Map<String, ActionUnit> actionUnitMap = new HashMap<>();
protected List<Modifiable<M>> modifiable;
private ErrorHandler errorHandler;
protected GeneralAutoResponder(
Sending sending,
PersonSettingService personSettingService,
StorylineService<M> storyLineService
) {
this.personSettingService = personSettingService;
this.storyLineService = storyLineService;
init(sending);
}
private void init(Sending sending) {
actionUnitMap.put(TypeUnit.CHECK, new AnswerCheckAction<>(sending));
actionUnitMap.put(TypeUnit.TEXT, new AnswerTextAction(sending));
actionUnitMap.put(TypeUnit.REPLACE_CMD, new ReplaceCmdAction());
}
public void initModifiable(List<Modifiable<M>> modifiable) {
this.modifiable = modifiable;
}
public void initActionUnit(String typeUnit, ActionUnit<? extends MainUnit<M>, M> actionUnit) {
if (!actionUnitMap.containsKey(typeUnit)) {
actionUnitMap.put(typeUnit, actionUnit);
} else {
throw new ConfigAppException("Обработка такого типа юнита уже зарегистрирована");
}
}
public void initSaveAction(AnswerSaveAction<M, ?> answerSaveAction) {
actionUnitMap.put(TypeUnit.SAVE, answerSaveAction);
}
/**
* Позволяет установить перехватчик и обработчик исключений, возникающих при обработке юнитов.
*/
public void setErrorHandler(ErrorHandler errorHandler) {
this.errorHandler = errorHandler;
}
public void setDefaultUnit(String unitName) {
storyLineService.setDefaultUnit(unitName);
}
public void processingNewMessage(M newMessage) {
if (newMessage != null) {
final boolean state = personSettingService.getStateProcessingByPersonId(newMessage.getPersonId()).orElse(true);
if (state) {
processing(newMessage);
}
}
}
public void processingNewMessages(List<M> newMessages) {
if (newMessages != null && !newMessages.isEmpty()) {
final Set<String> personIds = newMessages.stream()
.map(Message::getPersonId)
.collect(Collectors.toSet());
final Set<String> disableIds = personSettingService.getAllPersonIdDisableMessages(personIds);
final List<M> allowedMessages = newMessages.stream()
.filter(message -> !disableIds.contains(message.getPersonId()))
.toList();
allowedMessages.parallelStream().forEach(this::processing);
}
}
private void processing(M message) {
if (modifiable != null) {
modifiable.forEach(m -> m.change(message));
}
final Set<MainUnit<M>> units = storyLineService.getNextUnitByPersonId(message.getPersonId());
final Optional<MainUnit<M>> optAnswer = Responder.nextUnit(message, units)
.or(storyLineService::getDefaultUnit);
if (optAnswer.isPresent()) {
final MainUnit<M> answer = optAnswer.get();
if (checkPermission(answer.getAccessibility(), message)) {
answer(UnitRequest.of(answer, message));
}
}
}
private boolean checkPermission(Optional<Accessibility> accessibility, M message) {
return accessibility.isEmpty() || accessibility.get().check(message);
}
public void answer(UnitRequest<MainUnit<M>, M> unitRequest) {
try {
unitRequest = getAction(unitRequest);
activeUnitAfter(unitRequest);
} catch (Exception e) {
if (errorHandler != null) {
errorHandler.handle(unitRequest.getMessage(), e);
} else {
throw e;
}
}
}
private UnitRequest<MainUnit<M>, M> activeUnitAfter(UnitRequest<MainUnit<M>, M> unitRequest) {
final Set<MainUnit<M>> nextUnits = unitRequest.getUnit().getNextUnits();
if (nextUnits != null) {
Optional<MainUnit<M>> first = nextUnits.stream()
.filter(unit -> UnitActiveType.AFTER.equals(unit.getActiveType()))
.findFirst();
if (first.isPresent()) {
getAction(UnitRequest.of(first.get(), unitRequest.getMessage()));
return activeUnitAfter(UnitRequest.of(first.get(), unitRequest.getMessage()));
}
}
return unitRequest;
}
private UnitRequest<MainUnit<M>, M> getAction(UnitRequest<MainUnit<M>, M> unitRequest) {
final MainUnit<M> unit = unitRequest.getUnit();
final M message = unitRequest.getMessage();
final String typeUnit = unit.getType();
if (actionUnitMap.containsKey(typeUnit)) {
ActionUnit actionUnit = actionUnitMap.get(typeUnit);
UnitRequest<MainUnit<M>, M> newUnitRequest = actionUnit.action(unitRequest);
final Optional<MainUnit<M>> optDefaultUnit = storyLineService.getDefaultUnit();
if (!unit.isNotSaveHistory() && (optDefaultUnit.isEmpty() || !optDefaultUnit.get().equals(unit))) {
storyLineService.save(message.getPersonId(), unit.getName(), message);
}
final MainUnit<M> newUnit = newUnitRequest.getUnit();
return !unit.equals(newUnit) ? getAction(newUnitRequest) : unitRequest;
} else {
throw new NotFoundException("ActionUnit для типа {0} не зарегистрирован", unit.getType());
}
}
}

View File

@ -0,0 +1,61 @@
package dev.struchkov.godfather.simple.core;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.simple.core.unit.MainUnit;
import dev.struchkov.haiti.utils.Inspector;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import static dev.struchkov.haiti.utils.Checker.checkNull;
public class Storyline<M extends Message> {
private final Set<MainUnit<M>> startingUnits = new HashSet<>();
private final Set<MainUnit<M>> globalUnits = new HashSet<>();
private final Map<String, MainUnit<M>> units = new HashMap<>();
public Storyline(Set<MainUnit<M>> startingUnits, Map<String, MainUnit<M>> units) {
this.startingUnits.addAll(startingUnits);
this.units.putAll(units);
}
public void addGlobalUnits(Set<MainUnit<M>> globalUnits) {
this.globalUnits.addAll(globalUnits);
}
public Set<MainUnit<M>> getGlobalUnits() {
return globalUnits;
}
/**
* Получить юнит по названию.
*
* @param unitName Название юнита.
*/
public Optional<MainUnit<M>> getUnit(String unitName) {
Inspector.isNotNull(unitName);
return Optional.ofNullable(units.get(unitName));
}
public Set<MainUnit<M>> getStartingUnits() {
return startingUnits;
}
//TODO [22.06.2022]: Временное решение ленивой связки юнитов, пока не будет реализован нормальный механизм.
public void link(@NotNull String firstName, @NotNull String secondName) {
Inspector.isNotNull(firstName, secondName);
final MainUnit<M> firstUnit = units.get(firstName);
final MainUnit<M> secondUnit = units.get(secondName);
Inspector.isNotNull(firstUnit, secondUnit);
if (checkNull(firstUnit.getNextUnits())) {
firstUnit.setNextUnits(new HashSet<>());
}
firstUnit.getNextUnits().add(secondUnit);
}
}

View File

@ -0,0 +1,167 @@
package dev.struchkov.godfather.simple.core;
import dev.struchkov.godfather.exception.UnitConfigException;
import dev.struchkov.godfather.main.domain.UnitDefinition;
import dev.struchkov.godfather.main.domain.annotation.Unit;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.simple.core.unit.MainUnit;
import dev.struchkov.haiti.utils.Inspector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import static dev.struchkov.godfather.exception.UnitConfigException.unitConfigException;
public class StorylineFactory<M extends Message> {
private static final Logger log = LoggerFactory.getLogger(StorylineFactory.class);
private final List<Object> configurations = new ArrayList<>();
private final Map<String, UnitDefinition> unitDefinitions = new HashMap<>();
private final Map<String, MainUnit<M>> unitMap = new HashMap<>();
private final Set<String> mainUnits = new HashSet<>();
private final Set<String> globalUnits = new HashSet<>();
public StorylineFactory(List<Object> unitConfigurations) {
this.configurations.addAll(unitConfigurations);
}
public Map<String, UnitDefinition> getUnitDefinitions() {
return unitDefinitions;
}
public Map<String, MainUnit<M>> getUnitMap() {
return unitMap;
}
public Storyline<M> createStoryLine() {
generateUnitDefinitions();
try {
createUnitMap();
final Set<MainUnit<M>> mainUnit = getMainUnit();
final Set<MainUnit<M>> globalUnit = getGlobalUnit();
final Storyline<M> storyline = new Storyline<>(mainUnit, unitMap);
storyline.addGlobalUnits(globalUnit);
return storyline;
} catch (IllegalAccessException | InvocationTargetException e) {
log.error(e.getMessage(), e);
}
throw new UnitConfigException("Ошибка построения StoryLine");
}
private Set<MainUnit<M>> getMainUnit() {
Inspector.isNotEmpty(mainUnits, unitConfigException("Не задан ни один mainUnit. Установите хотя бы для одного Unit флаг mainUnit"));
return mainUnits.stream()
.map(unitMap::get)
.collect(Collectors.toSet());
}
private Set<MainUnit<M>> getGlobalUnit() {
return globalUnits.stream()
.map(unitMap::get)
.collect(Collectors.toSet());
}
private void createUnitMap() throws IllegalAccessException, InvocationTargetException {
for (UnitDefinition unitDefinition : unitDefinitions.values()) {
if (!unitMap.containsKey(unitDefinition.getName())) {
final Set<String> nextUnitNames = unitDefinition.getNextUnitNames();
if (nextUnitNames.isEmpty() || unitMap.keySet().containsAll(nextUnitNames)) {
createUnit(unitDefinition);
}
}
}
}
private MainUnit<M> createUnit(UnitDefinition unitDefinition) throws IllegalAccessException, InvocationTargetException {
final Object objectConfig = unitDefinition.getObjectConfig();
final String currentUnitName = unitDefinition.getName();
final Method method = unitDefinition.getMethod();
final Object[] nextUnits = Arrays.stream(method.getParameters())
.filter(parameter -> parameter.isAnnotationPresent(Unit.class))
.map(parameter -> parameter.getAnnotation(Unit.class))
.map(Unit::value)
.map(unitMap::get)
.toArray();
MainUnit<M> newUnit = (MainUnit<M>) method.invoke(objectConfig, nextUnits);
newUnit.setName(currentUnitName);
unitMap.put(currentUnitName, newUnit);
final Set<String> dependentUnitsName = unitDefinition.getDependentUnits();
for (String dependentUnitName : dependentUnitsName) {
final Set<String> dependentNextUnitNames = unitDefinitions.get(dependentUnitName).getNextUnitNames();
if (unitMap.keySet().containsAll(dependentNextUnitNames)) {
createUnit(unitDefinitions.get(dependentUnitName));
}
}
return newUnit;
}
private void generateUnitDefinitions() {
final Map<String, Set<String>> dependentUnits = new HashMap<>();
for (Object config : configurations) {
final Class<?> classUnitConfig = config.getClass();
for (Method method : classUnitConfig.getDeclaredMethods()) {
if (method.isAnnotationPresent(Unit.class)) {
final Unit unitConfig = method.getAnnotation(Unit.class);
final String unitName = unitConfig.value();
final UnitDefinition unitDefinition = new UnitDefinition();
unitDefinition.setName(unitName);
unitDefinition.setMethod(method);
unitDefinition.setObjectConfig(config);
if (unitConfig.main()) {
mainUnits.add(unitName);
}
if (unitConfig.global()) {
globalUnits.add(unitName);
}
final Parameter[] nextUnits = method.getParameters();
if (nextUnits.length > 0) {
for (Parameter nextUnit : nextUnits) {
if (nextUnit.isAnnotationPresent(Unit.class)) {
final Unit nextUnitConfig = nextUnit.getAnnotation(Unit.class);
final String nextUnitName = nextUnitConfig.value();
unitDefinition.setNextUnitName(nextUnitName);
dependentUnits.computeIfAbsent(nextUnitName, k -> new HashSet<>());
dependentUnits.get(nextUnitName).add(unitName);
}
}
}
unitDefinitions.put(unitDefinition.getName(), unitDefinition);
}
}
}
for (Map.Entry<String, Set<String>> entry : dependentUnits.entrySet()) {
final UnitDefinition unitDefinition = unitDefinitions.get(entry.getKey());
if (unitDefinition != null) {
unitDefinition.setDependentUnits(entry.getValue());
} else {
throw new UnitConfigException("Ошибка связи юнитов. Проблема с описанием {0} юнита. Возможно вы не указали класс конфигурации для этого юнита.", entry.getKey());
}
}
}
}

View File

@ -0,0 +1,22 @@
package dev.struchkov.godfather.simple.core.action;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.simple.core.unit.MainUnit;
import dev.struchkov.godfather.simple.core.unit.UnitRequest;
/**
* Интерфейс для обработки Unit-ов.
*
* @author upagge [11/07/2019]
*/
@FunctionalInterface
public interface ActionUnit<U extends MainUnit, M extends Message> {
/**
* Метод обработки Unit-а.
*
* @return Новый Unit, который может нуждаться в обработке
*/
UnitRequest<MainUnit, M> action(UnitRequest<U, M> unitRequest);
}

View File

@ -0,0 +1,59 @@
package dev.struchkov.godfather.simple.core.action;
import dev.struchkov.godfather.main.domain.BoxAnswer;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.simple.context.service.Sending;
import dev.struchkov.godfather.simple.core.unit.AnswerCheck;
import dev.struchkov.godfather.simple.core.unit.MainUnit;
import dev.struchkov.godfather.simple.core.unit.UnitRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Objects;
import static dev.struchkov.haiti.utils.Checker.checkNotNull;
/**
* Обработчик Unit-а {@link AnswerCheck}.
*
* @author upagge [11/07/2019]
*/
public class AnswerCheckAction<M extends Message> implements ActionUnit<AnswerCheck<M>, M> {
private static final Logger log = LoggerFactory.getLogger(AnswerCheckAction.class);
private final Sending sending;
public AnswerCheckAction(Sending sending) {
this.sending = sending;
}
@Override
public UnitRequest<MainUnit, M> action(UnitRequest<AnswerCheck<M>, M> unitRequest) {
final AnswerCheck<M> unit = unitRequest.getUnit();
log.debug("Началась обработка unit: {}.", unit.getName());
final M message = unitRequest.getMessage();
MainUnit<M> unitAnswer;
if (unit.getCheck().checked(message)) {
log.debug("Unit: {}. Проверка пройдена", unit.getName());
final BoxAnswer answerIfTrue = unit.getIntermediateAnswerIfTrue();
if (checkNotNull(answerIfTrue)) {
answerIfTrue.setRecipientIfNull(message.getPersonId());
sending.send(answerIfTrue);
}
unitAnswer = unit.getUnitTrue();
} else {
log.debug("Unit: {}. Проверка НЕ пройдена", unit.getName());
final BoxAnswer answerIfFalse = unit.getIntermediateAnswerIfFalse();
if (checkNotNull(answerIfFalse)) {
answerIfFalse.setRecipientIfNull(message.getPersonId());
sending.send(answerIfFalse);
}
unitAnswer = unit.getUnitFalse();
}
log.debug("Завершилась обработка unit: {}.", unit.getName());
return UnitRequest.of(Objects.requireNonNullElse(unitAnswer, unit), message);
}
}

View File

@ -0,0 +1,51 @@
package dev.struchkov.godfather.simple.core.action;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.simple.context.service.Pusher;
import dev.struchkov.godfather.simple.core.unit.AnswerSave;
import dev.struchkov.godfather.simple.core.unit.MainUnit;
import dev.struchkov.godfather.simple.core.unit.UnitRequest;
import dev.struchkov.godfather.simple.core.unit.func.CheckSave;
import dev.struchkov.godfather.simple.core.unit.func.PreservableData;
import dev.struchkov.godfather.simple.data.preser.AnswerSavePreservable;
import static dev.struchkov.haiti.utils.Checker.checkNotNull;
/**
* Обработчик Unit-а {@link AnswerSave}.
*
* @author upagge [11/07/2019]
*/
public class AnswerSaveAction<M extends Message, D> implements ActionUnit<AnswerSave<M, D>, M> {
@Override
public UnitRequest<MainUnit, M> action(UnitRequest<AnswerSave<M, D>, M> unitRequest) {
final AnswerSave<M, D> answerSave = unitRequest.getUnit();
final M message = unitRequest.getMessage();
final AnswerSavePreservable<D> preservable = answerSave.getPreservable();
final String personId = message.getPersonId();
final CheckSave<M> checkSave = answerSave.getCheckSave();
if (checkNotNull(checkSave)) {
MainUnit<M> unit = checkSave.check(message);
if (checkNotNull(unit)) {
return UnitRequest.of(unit, message);
}
}
final PreservableData<D, M> preservableData = answerSave.getPreservableData();
if (checkNotNull(preservableData)) {
D data = preservableData.getData(message);
if (checkNotNull(data)) {
preservable.save(personId, answerSave.getKey(), data);
}
}
final Pusher<D> pusher = answerSave.getPusher();
if (checkNotNull(pusher)) {
preservable.push(personId, pusher);
}
return UnitRequest.of(answerSave, message);
}
}

View File

@ -0,0 +1,57 @@
package dev.struchkov.godfather.simple.core.action;
import dev.struchkov.godfather.main.core.utils.InsertWords;
import dev.struchkov.godfather.main.domain.BoxAnswer;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.simple.context.service.Sending;
import dev.struchkov.godfather.simple.core.unit.AnswerText;
import dev.struchkov.godfather.simple.core.unit.MainUnit;
import dev.struchkov.godfather.simple.core.unit.UnitRequest;
import java.util.List;
import java.util.Optional;
/**
* Обработчик Unit-а {@link AnswerText}.
*
* @author upagge [11/07/2019]
*/
public class AnswerTextAction implements ActionUnit<AnswerText<Message>, Message> {
private final Sending sending;
public AnswerTextAction(Sending sending) {
this.sending = sending;
}
@Override
public UnitRequest<MainUnit, Message> action(UnitRequest<AnswerText<Message>, Message> unitRequest) {
final AnswerText<Message> unit = unitRequest.getUnit();
final Message message = unitRequest.getMessage();
final Optional<BoxAnswer> optAnswer = unit.getAnswer().processing(message);
if (optAnswer.isPresent()) {
final BoxAnswer answer = optAnswer.get();
replaceMarkers(unit, message, answer);
final Sending answerTextSending = unit.getSending();
answer.setRecipientIfNull(message.getPersonId());
if (answerTextSending != null) {
answerTextSending.send(answer);
} else {
sending.send(answer);
}
}
return UnitRequest.of(unit, message);
}
private void replaceMarkers(AnswerText<Message> answerText, Message message, BoxAnswer boxAnswer) {
if (answerText.getInsert() != null) {
final List<String> words = answerText.getInsert().insert(message.getPersonId());
final String newMessage = InsertWords.insert(boxAnswer.getMessage(), words);
boxAnswer.setMessage(newMessage);
}
}
}

View File

@ -0,0 +1,18 @@
package dev.struchkov.godfather.simple.core.action.cmd;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.simple.core.action.ActionUnit;
import dev.struchkov.godfather.simple.core.unit.MainUnit;
import dev.struchkov.godfather.simple.core.unit.UnitRequest;
import dev.struchkov.godfather.simple.core.unit.cmd.ReplaceCmd;
public class ReplaceCmdAction implements ActionUnit<ReplaceCmd<Message>, Message> {
@Override
public UnitRequest<MainUnit, Message> action(UnitRequest<ReplaceCmd<Message>, Message> unitRequest) {
final ReplaceCmd<Message> unit = unitRequest.getUnit();
final Message message = unitRequest.getMessage();
return UnitRequest.of(unit.getThisUnit(), message);
}
}

View File

@ -0,0 +1,38 @@
package dev.struchkov.godfather.simple.core.action.cmd;
import dev.struchkov.godfather.main.domain.StorylineHistory;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.simple.core.action.ActionUnit;
import dev.struchkov.godfather.simple.core.service.StorylineService;
import dev.struchkov.godfather.simple.core.unit.MainUnit;
import dev.struchkov.godfather.simple.core.unit.UnitRequest;
import dev.struchkov.godfather.simple.core.unit.cmd.RollBackCmd;
import static dev.struchkov.godfather.exception.RollBackException.rollBackException;
public class RollBackCmdAction<M extends Message> implements ActionUnit<RollBackCmd<M>, M> {
private final StorylineService<M> storyLineService;
public RollBackCmdAction(StorylineService<M> storyLineService) {
this.storyLineService = storyLineService;
}
@Override
public UnitRequest<MainUnit, M> action(UnitRequest<RollBackCmd<M>, M> unitRequest) {
final RollBackCmd<M> unit = unitRequest.getUnit();
final M message = unitRequest.getMessage();
final int countToBack = unit.getCountBack();
final String rollbackUnitName = unit.getRollbackUnitName();
StorylineHistory history = rollbackUnitName != null
? storyLineService.replaceUserToBack(message.getPersonId(), rollbackUnitName).orElseThrow(rollBackException("Юнит для возвращения не был найден"))
: storyLineService.replaceUserToBack(message.getPersonId(), countToBack).orElseThrow(rollBackException("Юнит для возвращения не был найден"));
final String unitName = history.getUnitName();
final MainUnit<M> nextUnit = storyLineService.getUnitByName(unitName).orElse(unit);
final M oldMessage = (M) history.getMessage();
return UnitRequest.of(nextUnit, oldMessage);
}
}

View File

@ -0,0 +1,25 @@
package dev.struchkov.godfather.simple.core.provider;
import dev.struchkov.godfather.main.domain.content.Mail;
import dev.struchkov.godfather.simple.context.service.EventHandler;
import dev.struchkov.godfather.simple.core.GeneralAutoResponder;
public class StoryLineHandler implements EventHandler<Mail> {
private final GeneralAutoResponder<Mail> generalAutoResponder;
public StoryLineHandler(GeneralAutoResponder<Mail> generalAutoResponder) {
this.generalAutoResponder = generalAutoResponder;
}
@Override
public void handle(Mail message) {
generalAutoResponder.processingNewMessage(message);
}
@Override
public String getEventType() {
return Mail.TYPE;
}
}

View File

@ -0,0 +1,34 @@
package dev.struchkov.godfather.simple.core.pusher;
import dev.struchkov.godfather.main.domain.BoxAnswer;
import dev.struchkov.godfather.simple.context.service.Pusher;
import dev.struchkov.godfather.simple.context.service.Sending;
import java.util.Map;
import static dev.struchkov.godfather.main.domain.BoxAnswer.boxAnswer;
public class UserSanderPusher implements Pusher<String> {
private final String personId;
private final String nameForm;
private final Sending sending;
public UserSanderPusher(String personId, String nameForm, Sending sending) {
this.personId = personId;
this.nameForm = nameForm;
this.sending = sending;
}
@Override
public void push(String personId, Map<String, String> saveElement) {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("========= ").append(nameForm).append(" =========\n");
saveElement.forEach((key, value) -> stringBuilder.append(key).append(": ").append(value).append("\n"));
stringBuilder.append("====================");
final BoxAnswer boxAnswer = boxAnswer(stringBuilder.toString());
boxAnswer.setRecipientIfNull(this.personId);
sending.send(boxAnswer);
}
}

View File

@ -1,7 +1,7 @@
package dev.struchkov.godfather.core.service;
package dev.struchkov.godfather.simple.core.service;
import dev.struchkov.godfather.context.repository.PersonSettingRepository;
import dev.struchkov.godfather.context.service.PersonSettingService;
import dev.struchkov.godfather.simple.context.service.PersonSettingService;
import dev.struchkov.godfather.simple.data.repository.PersonSettingRepository;
import dev.struchkov.haiti.utils.Inspector;
import org.jetbrains.annotations.NotNull;
@ -17,24 +17,24 @@ public class PersonSettingServiceImpl implements PersonSettingService {
}
@Override
public Set<Long> getAllPersonIdDisableMessages(@NotNull Set<Long> personIds) {
public Set<String> getAllPersonIdDisableMessages(@NotNull Set<String> personIds) {
Inspector.isNotNull(personIds);
return personSettingRepository.findAllByAllowedProcessing(personIds);
}
@Override
public Optional<Boolean> getStateProcessingByPersonId(@NotNull Long personId) {
public Optional<Boolean> getStateProcessingByPersonId(@NotNull String personId) {
return personSettingRepository.findStateByPersonId(personId);
}
@Override
public void disableMessageProcessing(@NotNull Long personId) {
public void disableMessageProcessing(@NotNull String personId) {
Inspector.isNotNull(personId);
personSettingRepository.disableMessageProcessing(personId);
}
@Override
public void enableMessageProcessing(@NotNull Long personId) {
public void enableMessageProcessing(@NotNull String personId) {
Inspector.isNotNull(personId);
personSettingRepository.enableMessageProcessing(personId);
}

View File

@ -0,0 +1,55 @@
package dev.struchkov.godfather.simple.core.service;
import dev.struchkov.godfather.main.domain.ContextKey;
import dev.struchkov.godfather.simple.data.StorylineContext;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import static dev.struchkov.haiti.context.exception.NotFoundException.notFoundException;
import static dev.struchkov.haiti.utils.Inspector.isNotNull;
public class StorylineContextMapImpl implements StorylineContext {
private final Map<String, Map<String, Object>> map = new HashMap<>();
public void save(@NotNull String personId, @NotNull ContextKey<?> key, Object objectForSave) {
isNotNull(personId, key);
map.computeIfAbsent(personId, k -> new HashMap<>()).put(key.getValue(), objectForSave);
}
public <T> Optional<T> getByKey(@NotNull String personId, @NotNull ContextKey<T> key) {
isNotNull(personId, key);
if (map.containsKey(personId)) {
final Map<String, Object> storage = map.get(personId);
final T object = (T) storage.get(key.getValue());
if (object != null && object.getClass().equals(key.getType())) {
return Optional.of(object);
}
}
return Optional.empty();
}
@Override
public <T> T getByKeyOrThrow(@NotNull String personId, @NotNull ContextKey<T> key) {
return getByKey(personId, key).orElseThrow(notFoundException("Не найдено значение ключа {0}, для пользователя {1}", key.getValue(), personId));
}
public Map<String, Object> getAllSaveElement(@NotNull String personId) {
isNotNull(personId);
return map.get(personId);
}
public void removeAll(@NotNull String personId) {
isNotNull(personId);
map.remove(personId);
}
public void removeByKey(@NotNull String personId, @NotNull ContextKey<?> key) {
isNotNull(personId, key);
map.computeIfAbsent(personId, k -> new HashMap<>()).remove(key.getValue());
}
}

View File

@ -0,0 +1,110 @@
package dev.struchkov.godfather.simple.core.service;
import dev.struchkov.autoresponder.entity.Unit;
import dev.struchkov.godfather.main.domain.StorylineHistory;
import dev.struchkov.godfather.main.domain.UnitPointer;
import dev.struchkov.godfather.main.domain.content.Mail;
import dev.struchkov.godfather.simple.context.service.UnitPointerService;
import dev.struchkov.godfather.simple.core.Storyline;
import dev.struchkov.godfather.simple.core.StorylineFactory;
import dev.struchkov.godfather.simple.core.unit.MainUnit;
import dev.struchkov.godfather.simple.data.repository.StorylineRepository;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import static dev.struchkov.haiti.utils.Inspector.isNotNull;
/**
* Отвечает за работу со сценарием в личных сообщениях с пользователем.
*/
public class StorylineMailService implements StorylineService<Mail> {
private final UnitPointerService unitPointerService;
private final StorylineRepository storylineRepository;
private final Storyline<Mail> storyLine;
private String defaultUnitName;
public StorylineMailService(
UnitPointerService unitPointerService,
StorylineRepository storylineRepository,
List<Object> unitConfigurations
) {
this.storyLine = new StorylineFactory<Mail>(unitConfigurations).createStoryLine();
this.unitPointerService = unitPointerService;
this.storylineRepository = storylineRepository;
}
@Override
public void save(@NotNull StorylineHistory storylineHistory) {
isNotNull(storylineHistory);
storylineRepository.save(storylineHistory);
}
@Override
public Optional<MainUnit<Mail>> getUnitNameByPersonId(@NotNull String personId) {
isNotNull(personId);
return unitPointerService.getUnitNameByPersonId(personId)
.flatMap(storyLine::getUnit);
}
@Override
public Set<MainUnit<Mail>> getNextUnitByPersonId(@NotNull String personId) {
final Optional<Set<MainUnit<Mail>>> optMainUnits = getUnitNameByPersonId(personId)
.map(Unit::getNextUnits)
.filter(mainUnits -> !mainUnits.isEmpty());
if (optMainUnits.isEmpty()) {
storylineRepository.cleanHistoryByPersonId(personId);
}
final Set<MainUnit<Mail>> nextUnits = optMainUnits.orElse(storyLine.getStartingUnits());
nextUnits.addAll(storyLine.getGlobalUnits());
return nextUnits;
}
@Override
public void save(String personId, String unitName, Mail mail) {
isNotNull(personId, unitName, mail);
unitPointerService.save(new UnitPointer(personId, unitName));
final StorylineHistory storylineHistory = new StorylineHistory();
storylineHistory.setPersonId(personId);
storylineHistory.setUnitName(unitName);
storylineHistory.setMessage(mail);
storylineRepository.save(storylineHistory);
}
@Override
public Optional<StorylineHistory> replaceUserToBack(String personId, int countUnitsToBack) {
return storylineRepository.findByCountLast(personId, countUnitsToBack);
}
@Override
public Optional<StorylineHistory> replaceUserToBack(String personId, String unitName) {
return storylineRepository.findByCountLast(personId, unitName);
}
@Override
public Optional<MainUnit<Mail>> getDefaultUnit() {
if (defaultUnitName == null) return Optional.empty();
return storyLine.getUnit(defaultUnitName);
}
@Override
public void setDefaultUnit(String defaultUnit) {
defaultUnitName = defaultUnit;
}
//TODO [22.06.2022]: Временное решение для ленивой инициализации
@Override
public void lazyLink(String firstName, String secondName) {
storyLine.link(firstName, secondName);
}
@Override
public Optional<MainUnit<Mail>> getUnitByName(String unitName) {
return storyLine.getUnit(unitName);
}
}

View File

@ -0,0 +1,36 @@
package dev.struchkov.godfather.simple.core.service;
import dev.struchkov.godfather.main.domain.StorylineHistory;
import dev.struchkov.godfather.main.domain.content.Message;
import dev.struchkov.godfather.simple.core.unit.MainUnit;
import org.jetbrains.annotations.NotNull;
import java.util.Optional;
import java.util.Set;
public interface StorylineService<M extends Message> {
void save(@NotNull StorylineHistory storylineHistory);
Optional<MainUnit<M>> getUnitNameByPersonId(@NotNull String personId);
Set<MainUnit<M>> getNextUnitByPersonId(@NotNull String personId);
void save(String personId, String name, M message);
Optional<StorylineHistory> replaceUserToBack(String personId, int countUnitsToBack);
Optional<StorylineHistory> replaceUserToBack(String personId, String unitName);
Optional<MainUnit<M>> getDefaultUnit();
/**
* Ленивая (поздняя) связка юнитов между собой. Осуществляется уже после создания сценария. С помощью данного подхода можно реализовать циклические зависимости юнитов.
*/
void lazyLink(String firstName, String secondName);
Optional<MainUnit<M>> getUnitByName(String unitName);
void setDefaultUnit(String unitName);
}

View File

@ -1,8 +1,8 @@
package dev.struchkov.godfather.core.service;
package dev.struchkov.godfather.simple.core.service;
import dev.struchkov.godfather.context.domain.UnitPointer;
import dev.struchkov.godfather.context.repository.UnitPointerRepository;
import dev.struchkov.godfather.context.service.UnitPointerService;
import dev.struchkov.godfather.main.domain.UnitPointer;
import dev.struchkov.godfather.simple.context.service.UnitPointerService;
import dev.struchkov.godfather.simple.data.repository.UnitPointerRepository;
import org.jetbrains.annotations.NotNull;
import java.util.Optional;
@ -21,12 +21,12 @@ public class UnitPointerServiceImpl implements UnitPointerService {
}
@Override
public Optional<String> getUnitNameByPersonId(@NotNull Long personId) {
public Optional<String> getUnitNameByPersonId(@NotNull String personId) {
return unitPointerRepository.findUnitNameByPersonId(personId);
}
@Override
public void removeByPersonId(@NotNull Long personId) {
public void removeByPersonId(@NotNull String personId) {
unitPointerRepository.removeByPersonId(personId);
}

Some files were not shown because too many files have changed in this diff Show More