Compare commits

...

7 Commits

20 changed files with 132 additions and 79 deletions

View File

@ -60,8 +60,9 @@ public class MergeRequestsServiceImpl implements MergeRequestsService {
public MergeRequest create(@NonNull MergeRequest mergeRequest) { public MergeRequest create(@NonNull MergeRequest mergeRequest) {
final boolean botUserReviewer = isBotUserReviewer(mergeRequest); final boolean botUserReviewer = isBotUserReviewer(mergeRequest);
final boolean botUserAssignee = isBotUserAssigneeAndNotAuthor(mergeRequest); final boolean botUserAssignee = isBotUserAssigneeAndNotAuthor(mergeRequest);
final boolean botUserAuthor = personInformation.getId().equals(mergeRequest.getAuthor().getId());
mergeRequest.setNotification(botUserReviewer || botUserAssignee); mergeRequest.setNotification(botUserReviewer || botUserAssignee || botUserAuthor);
mergeRequest.setUserAssignee(botUserAssignee); mergeRequest.setUserAssignee(botUserAssignee);
mergeRequest.setUserReviewer(botUserReviewer); mergeRequest.setUserReviewer(botUserReviewer);

View File

@ -1,5 +1,9 @@
# Общая архитектура # Общая архитектура
!!! warning
Данный раздел находится в процессе написания
Поддерживается два режима работы: периодические запуски на ПК и запуск на сервере в режиме 24/7. Поддерживается два режима работы: периодические запуски на ПК и запуск на сервере в режиме 24/7.
## Схема БД { id="schema-database" } ## Схема БД { id="schema-database" }
@ -23,6 +27,3 @@
Не везде имется возможность установить произвольные Webhook. Например, вряд ли кто-то позволит вам установить Webhook из корпоративного GitLab во внешнюю сеть. Переодическое обращение к GitLab API можно выполнять прямо с рабочей машины. Не везде имется возможность установить произвольные Webhook. Например, вряд ли кто-то позволит вам установить Webhook из корпоративного GitLab во внешнюю сеть. Переодическое обращение к GitLab API можно выполнять прямо с рабочей машины.
В будущем планирую добавить поддержку и Webhook. В будущем планирую добавить поддержку и Webhook.
## Отслеживание репозиториев
Ключевым (рутовым) элементом являются репозитории.

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 244 KiB

View File

@ -0,0 +1,30 @@
# Взаимодействие с ботом
Главное меню бота вызывается с помощью команды `/start`
!!! note
На данный момент главное меню содержит только пункт: "Добавить новый репозиторий". В будущем функционал существенно расширится.
## Добавить новый репозиторий
Если во время первичной инициализации не стали добавлять все доступные репозитории, или не включили автоматическое отслеживание появления новых репозиториев, то вы можете добавлять репозитории самостоятельно.
Для этого:
* Вызовите главное меню командой `/start`
* Выберете пункт `Add repository`, который позволяет поставить репозиторий на отслеживание
* Скопируйте ссылку на репозиторий из адресной строки браузера и отправьте ее боту.
* Если все пройдет успешно, то вы получите уведомление `👍 Projects added successfully!`
Это позволит вам получать все уведомления репозитория и его сущностей, таких как MR, пайплайны и так далее.
!!! tip "Массовое добавление"
Если вы хотите добавить множество репозиториев разом, то вы можете это сделать. Сформируйте сообщение с несколькими ссылками, где каждая ссылка на репозиторий будет на новой строке:
```
https://gitlab.com/groupname/projectname1/repositoryname1
https://gitlab.com/groupname/projectname1/repositoryname2
https://gitlab.com/groupname/projectname2/repositoryname3
```

View File

@ -1,6 +1,16 @@
# Взаимодействие с GitLab # Взаимодействие с GitLab
## Добавить новый репозиторий
## Ответ в треде ## Ответ в треде
Допустим вас упомянули в обсуждении, сразу знаете что ответить? Не тратьте время, отвечайте прямо из телеграм. Для этого просто ответьте на сообщение и напишите ваш комментарий. Допустим вас упомянули в обсуждении, сразу знаете что ответить? Не тратьте время, отвечайте прямо из телеграм. Для этого просто ответьте на сообщение и напишите ваш комментарий.
Просто ответьте на сообщение уведомления:
<figure markdown>
![telegram-thread-answer.png](img/telegram-thread-answer.png){ loading=lazy align=left width="700" }
</figure>
Так это будет выглядеть в GitLab:
<figure markdown>
![gitlab-thread-answer.png](img/gitlab-thread-answer.png){ loading=lazy align=left width="700" }
</figure>

View File

@ -190,14 +190,20 @@
## Уведомление о пайплайне ## Уведомление о пайплайне
Полезно сразу узнавать, что сборка закончилась успешно или упала. Полезно сразу узнавать, что сборка закончилась успешно или упала.
!!! question "Я буду получать уведомление обо всех пайплайнах?"
Нет. Вы будете получать уведомление только о тех пайплайнах, в которых выступили инициатором. Напримр, запустили CI руками из GitLab, или нажали кнопку Merge в MR.
<figure markdown> <figure markdown>
![notify about new pipeline](img/notify-new-pipeline.png){ loading=lazy width="500" } ![notify about new pipeline](img/notify-new-pipeline.png){ loading=lazy width="500" }
</figure> </figure>
Уведомление содержит: Уведомление содержит:
- Предыдущий статус пайплайна и новый - Предыдущий статус пайплайна и новый статус
- - Номер пайплайна
- Название репозитория
- Ветка, для которой запускалась сборка
Доступные быстрые действия: Доступные быстрые действия:

View File

@ -2,10 +2,13 @@
Есть несколько способов запустить бота-помощника. Бот был спроектирован таким образом, чтобы работать локально на вашем ПК, но вы можете запустить его на сервере в режиме 24/4. Есть несколько способов запустить бота-помощника. Бот был спроектирован таким образом, чтобы работать локально на вашем ПК, но вы можете запустить его на сервере в режиме 24/4.
Первым делом вам предложат ввести имя для бота. Для начала выполните эти действия:
1. [Создание бота в Telegram](creating-telegram-bot.md)
2. [Получение персонального токена в GitLab](create-gitlab-token.md)
## Конфигурация ## Конфигурация
Несмотря на то, какой вариант запуска вы вберете, необходимо указать следующие переменные среды: Вне зависимости от того, какой способ вы выберете, необходимо будет указать данные переменные среды:
* `TELEGRAM_BOT_TOKEN` — токен, который вы получили при [создании бота](creating-telegram-bot.md). * `TELEGRAM_BOT_TOKEN` — токен, который вы получили при [создании бота](creating-telegram-bot.md).
* `TELEGRAM_BOT_USERNAME` — название, которое вы дали боту. Оканчивается на bot. * `TELEGRAM_BOT_USERNAME` — название, которое вы дали боту. Оканчивается на bot.
@ -99,21 +102,3 @@ docker run --name gitlab-notify \
--env DATASOURCE_PASSWORD=value \ --env DATASOURCE_PASSWORD=value \
--network="host" upagge/gitlab-telegram-notify:latest --network="host" upagge/gitlab-telegram-notify:latest
``` ```
## Запуск в IDEA
## Запуск JAR релиза
Скачать актуальный jar-файл всегда можно на странице релизов GitHub.
``` shell
java -DTELEGRAM_BOT_USERNAME=value \
-DTELEGRAM_BOT_TOKEN=value \
-DTELEGRAM_PERSON_ID=value \
-DDATASOURCE_URL=value \
-DDATASOURCE_PASSWORD=value \
-DDATASOURCE_USERNAME=value \
-DGITLAB_PERSONAL_TOKEN=value \
-DGITLAB_URL=value \
-jar gitlab-notification.jar
```

View File

@ -1 +1,19 @@
# Создание токена GitLab # Создание токена GitLab
Для взаимодействия с GitLab необходим персональный токен доступа.
Чтобы его получить перейдите по адресу: [https://gitlab.com/-/profile/personal_access_tokens](https://gitlab.com/-/profile/personal_access_tokens)
!!! tip "Корпоративный GitLab"
Замените `https://gitlab.com/` на адрес своего GitLab, если вы используете self-host решение.
* Придумайте название токену, например, `GitLab Notify`.
* Выдайте права на чтение - `read_api`
!!! info "Уровень разрешений"
Выберете уровень разрешения `api`, если планируете пользоваться такими функциями, как: [ответ в треде](../features/interaction-gitlab.md#ответ-в-треде)
* Нажмите кнопку `Create personal access token`.
* Сохраните полученный токен.

View File

@ -6,7 +6,7 @@
Первые два пункта диалогового меню будет про название бота. Учтите, что это называние общедоступно и случайноы пользователь Telegram сможет найти вашего бота. Первые два пункта диалогового меню будет про название бота. Учтите, что это называние общедоступно и случайноы пользователь Telegram сможет найти вашего бота.
Не переживайте, приложение имеет встроенную защиту от несанкционарованного доступа к боту. Но не смотря на это, ==не рекомендуется использовать в названии бота название организации, или вашу фамилию. Лучше использовать случайное имя.== Не переживайте, приложение имеет встроенную [защиту от несанкционарованного доступа к боту](../privacy/index.md#access-control). Но не смотря на это, ==не рекомендуется использовать в названии бота название организации, или вашу фамилию. Лучше использовать случайное имя.==
После регистрации вам будет выдан токен доступа. Он будет использоваться при запуске ассистента. После регистрации вам будет выдан токен доступа. Он будет использоваться при запуске ассистента.

View File

@ -1,5 +1,7 @@
# Инициализация бота # Инициализация бота
В данном видео демонстрируется процесс первичной настройки бота, чтобы вы знали, чего ожидать:
<video controls> <video controls>
<source id="mp4" src="../mp4/init-start.mp4" type="video/mp4"> <source id="mp4" src="../mp4/init-start.mp4" type="video/mp4">
</videos> </videos>

View File

@ -1,10 +0,0 @@
# Hello Mutiny!
Once you made Mutiny available to your classpath, you can start writing code.
Let's start with this simple program:
## Test
### Test 2
## Test 4

View File

@ -7,9 +7,9 @@ hide:
--- ---
# GitLab Notification Персональный Telegram бот для GitLab # GitLab Notification Персональный Telegram бот для GitLab
Персональный ассистент для упрощения работы с GitLab. Получайте персональные уведомления о событиях в GitLab: новый MR на ревью, новый ответ в треде и многое другое. Персональный ассистент призван упростить работу с GitLab. Получайте персональные уведомления о событиях в GitLab, ничего не пропустите и не забудьте.
Бота можно запустить как для облачного GitLab, так и для Self-host решений. Бота-ассистента можно запустить как для облачного GitLab, так и для Self-host решений.
!!! info "GodFather Telegram" !!! info "GodFather Telegram"

View File

@ -4,13 +4,17 @@
!!! tip "Доверие" !!! tip "Доверие"
Вы не должны верить мне на слово. Вы можете [самостоятельно изучить код, он открыт и не сложен.](https://github.com/uPagge/gitlab-notification) После проверки можно самостоятельно собрать jar и упаковать его в Docker. Либо запускать код прямо из Idea. Вы не должны верить мне на слово. Вы можете [самостоятельно изучить код, он открыт и не сложен.](https://github.com/uPagge/gitlab-notification) После проверки можно самостоятельно собрать jar и [упаковать его в Docker](https://github.com/uPagge/gitlab-notification/blob/master/Dockerfile). Либо запускать код прямо из Idea.
## Защита токена GitLab ## Защита токена GitLab
Для работы ассистента необходим персональный токен GitLab. Он указывается в переменные среды и нигде дополнительно не дублируется. Таким образом токен не попадает в Telegram и хранится только у вас на компьютере и в контейнере приложения. Для работы ассистента необходим персональный токен GitLab. Он указывается в переменные среды и нигде дополнительно не хранится и не передается. Таким образом токен не попадает в Telegram и хранится только у вас на компьютере и в контейнере приложения.
Токен используется только при обращении к указанному GitLab, и только для выполнения описанных в документации возможностей. Никакой скрытой работы не выполняется, по возможности обо всех взаимодействиях с GitLab дополнительно сообщается во время настройки. Токен используется только при обращении к указанному GitLab, и только для выполнения описанных в документации возможностей. Никакой скрытой работы не выполняется, по возможности обо всех взаимодействиях с GitLab дополнительно сообщается во время настройки.
!!! question "А что, если ты заполучишь токен?"
Ну начнем с того, что мне ваш токен даром не нужен. Изучайте код, если мне не верите, или не пользуйтесь моим ботом. Эта страница призвана ответить на возникающие вопросы безопаности решения, не более этого. Дополнительно убеждать никого не собираюсь.
## Уровни конфиденциальности ## Уровни конфиденциальности
Некоторые уведомления могут содержать множество чувствительной информации. Например, уведомления о новых сообщениях в тредах. Возможно вы не захотите раскрывать столько информации о вашей разработке телеграму, ведь через него идет получение уведомлений. Специально для таких случаев предусмотрены уровни конфиденциальности разных типов уведомлений. Некоторые уведомления могут содержать множество чувствительной информации. Например, уведомления о новых сообщениях в тредах. Возможно вы не захотите раскрывать столько информации о вашей разработке телеграму, ведь через него идет получение уведомлений. Специально для таких случаев предусмотрены уровни конфиденциальности разных типов уведомлений.
@ -22,7 +26,7 @@
Прочитать подробнее можно в разделе: [Работа с базой данных](../architecture/concept.md#schema-database) Прочитать подробнее можно в разделе: [Работа с базой данных](../architecture/concept.md#schema-database)
## Несанкционированный доступ ## Несанкционированный доступ { id="access-control" }
==Все боты в Telegram являются публичными.== Это значит, что ваш бот может быть найден через поиск в Telegram. Поэтому ==не рекомендуется давать название боту, которое может раскрыть его предназначение.== ==Все боты в Telegram являются публичными.== Это значит, что ваш бот может быть найден через поиск в Telegram. Поэтому ==не рекомендуется давать название боту, которое может раскрыть его предназначение.==
Даже если кто-то случайно напишет вашему боту ничего не случится. ==В боте встроена проверка прав доступа.== Вот как она работает: Даже если кто-то случайно напишет вашему боту ничего не случится. ==В боте встроена проверка прав доступа.== Вот как она работает:

View File

@ -10,7 +10,8 @@ nav:
- Конфиденциальность: privacy/index.md - Конфиденциальность: privacy/index.md
- Возможности: - Возможности:
- Уведомления: features/notify.md - Уведомления: features/notify.md
- Быстрые действия: features/interaction-gitlab.md - Взаимодействие с GitLab: features/interaction-gitlab.md
- features/interaction-bot.md
- Быстрый старт: - Быстрый старт:
- getting-started/create-gitlab-token.md - getting-started/create-gitlab-token.md
- getting-started/creating-telegram-bot.md - getting-started/creating-telegram-bot.md

View File

@ -32,9 +32,9 @@ public class SchedulerService {
private final MergeRequestsService mergeRequestsService; private final MergeRequestsService mergeRequestsService;
private final DiscussionService discussionService; private final DiscussionService discussionService;
@Scheduled(cron = "0 */1 * * * *") @Scheduled(cron = "0 0 */1 * * *")
public void newMergeRequest() { public void newProjects() {
log.info("Запуск процесса обновления данных c GitLab"); log.info("Запуск процесса получение новых репозиториев c GitLab");
if (!settingService.isFirstStart()) { if (!settingService.isFirstStart()) {
if (settingService.isOwnerProjectScan()) { if (settingService.isOwnerProjectScan()) {
projectParser.parseAllProjectOwner(); projectParser.parseAllProjectOwner();
@ -42,8 +42,24 @@ public class SchedulerService {
if (settingService.isPrivateProjectScan()) { if (settingService.isPrivateProjectScan()) {
projectParser.parseAllPrivateProject(); projectParser.parseAllPrivateProject();
} }
mergeRequestParser.parsingOldMergeRequest(); }
log.info("Конец процесса получение новых репозиториев c GitLab");
}
@Scheduled(cron = "0 */15 * * * *")
public void newMergeRequests() {
log.info("Запуск процесса получение новых MR c GitLab");
if (!settingService.isFirstStart()) {
mergeRequestParser.parsingNewMergeRequest(); mergeRequestParser.parsingNewMergeRequest();
}
log.info("Конец процесса получение новых MR c GitLab");
}
@Scheduled(cron = "0 */1 * * * *")
public void newMergeRequest() {
log.info("Запуск процесса обновления данных c GitLab");
if (!settingService.isFirstStart()) {
mergeRequestParser.parsingOldMergeRequest();
pipelineParser.scanOldPipeline(); pipelineParser.scanOldPipeline();
pipelineParser.scanNewPipeline(); pipelineParser.scanNewPipeline();
discussionParser.scanOldDiscussions(); discussionParser.scanOldDiscussions();

View File

@ -44,7 +44,7 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<godfather.telegram.version>0.0.50</godfather.telegram.version> <godfather.telegram.version>0.0.51</godfather.telegram.version>
<haiti.utils.version>2.7.2</haiti.utils.version> <haiti.utils.version>2.7.2</haiti.utils.version>
<haiti.utils.fields.version>0.0.11</haiti.utils.fields.version> <haiti.utils.fields.version>0.0.11</haiti.utils.fields.version>
<haiti.filter.version>0.0.5</haiti.filter.version> <haiti.filter.version>0.0.5</haiti.filter.version>

View File

@ -1,12 +1,12 @@
package dev.struchkov.bot.gitlab.telegram.service; package dev.struchkov.bot.gitlab.telegram.service;
import dev.struchkov.bot.gitlab.context.service.AppSettingService; import dev.struchkov.bot.gitlab.context.service.AppSettingService;
import dev.struchkov.bot.gitlab.context.service.NotifyService;
import dev.struchkov.bot.gitlab.context.utils.Icons; import dev.struchkov.bot.gitlab.context.utils.Icons;
import dev.struchkov.bot.gitlab.core.config.properties.AppProperty; import dev.struchkov.bot.gitlab.core.config.properties.AppProperty;
import dev.struchkov.bot.gitlab.core.config.properties.PersonProperty; import dev.struchkov.bot.gitlab.core.config.properties.PersonProperty;
import dev.struchkov.godfather.simple.domain.BoxAnswer; import dev.struchkov.godfather.simple.domain.BoxAnswer;
import dev.struchkov.godfather.simple.domain.SentBox; import dev.struchkov.godfather.simple.domain.SentBox;
import dev.struchkov.godfather.telegram.domain.ClientBotCommand;
import dev.struchkov.godfather.telegram.simple.context.service.TelegramSending; import dev.struchkov.godfather.telegram.simple.context.service.TelegramSending;
import dev.struchkov.godfather.telegram.simple.context.service.TelegramService; import dev.struchkov.godfather.telegram.simple.context.service.TelegramService;
import jakarta.annotation.PostConstruct; import jakarta.annotation.PostConstruct;
@ -17,6 +17,7 @@ import okhttp3.Request;
import okhttp3.Response; import okhttp3.Response;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.UUID; import java.util.UUID;
@ -29,8 +30,8 @@ import static dev.struchkov.haiti.utils.Checker.checkNotBlank;
/** /**
* @author upagge 19.01.2021 * @author upagge 19.01.2021
*/ */
@Component
@Slf4j @Slf4j
@Component
@RequiredArgsConstructor @RequiredArgsConstructor
public class StartNotify { public class StartNotify {
@ -39,8 +40,6 @@ public class StartNotify {
private final TelegramSending sending; private final TelegramSending sending;
private final TelegramService telegramService; private final TelegramService telegramService;
private final NotifyService notifyService;
private final AppProperty appProperty; private final AppProperty appProperty;
private final AppSettingService settingService; private final AppSettingService settingService;
private final PersonProperty personProperty; private final PersonProperty personProperty;
@ -66,7 +65,6 @@ public class StartNotify {
.payload(DISABLE_WEB_PAGE_PREVIEW, true) .payload(DISABLE_WEB_PAGE_PREVIEW, true)
.build(); .build();
sending.send(boxAnswer); sending.send(boxAnswer);
sendNotice(); sendNotice();
} }
registrationForStatistic(); registrationForStatistic();
@ -102,7 +100,7 @@ public class StartNotify {
final BoxAnswer notice = BoxAnswer.builder() final BoxAnswer notice = BoxAnswer.builder()
.message(noticeMessage) .message(noticeMessage)
.recipientPersonId(personProperty.getTelegramId()) .recipientPersonId(personProperty.getTelegramId())
// .payload(DISABLE_WEB_PAGE_PREVIEW, true) .payload(DISABLE_WEB_PAGE_PREVIEW, true)
.build(); .build();
final Optional<SentBox> optSentBox = sending.send(notice); final Optional<SentBox> optSentBox = sending.send(notice);
if (optSentBox.isPresent()) { if (optSentBox.isPresent()) {
@ -117,17 +115,12 @@ public class StartNotify {
} }
} }
// @PostConstruct @PostConstruct
// public void demo() { public void createCommands() {
// notifyService.send( final ClientBotCommand clientBotCommand = new ClientBotCommand();
// DiscussionNewNotify.builder() clientBotCommand.setDescription("Open general menu");
// .authorName("Ivan Ivanov") clientBotCommand.setKey("start");
// .threadId("1") telegramService.addCommand(List.of(clientBotCommand));
// .discussionMessage("Кажется здесь можно сделать лучше.") }
// .mergeRequestName("Merge Request Name")
// .url("https://ya.ru")
// .build()
// );
// }
} }

View File

@ -521,11 +521,9 @@ public class InitSettingFlow implements UnitConfiguration {
final ButtonClickAttachment buttonClick = Attachments.findFirstButtonClick(mail.getAttachments()).orElseThrow(); final ButtonClickAttachment buttonClick = Attachments.findFirstButtonClick(mail.getAttachments()).orElseThrow();
final DiscussionLevel level = DiscussionLevel.valueOf(buttonClick.getRawCallBackData().toUpperCase()); final DiscussionLevel level = DiscussionLevel.valueOf(buttonClick.getRawCallBackData().toUpperCase());
settingService.setDiscussionLevel(level); settingService.setDiscussionLevel(level);
replaceBoxAnswer("\uD83D\uDC4D you have successfully set the privacy level for threads"); return replaceBoxAnswer("\uD83D\uDC4D you have successfully set the privacy level for threads");
}) })
.callBack( .callBack(sentBox -> scheduledExecutorService.schedule(() -> sending.deleteMessage(sentBox.getPersonId(), sentBox.getMessageId()), 6, TimeUnit.SECONDS))
sentBox -> scheduledExecutorService.schedule(() -> sending.deleteMessage(sentBox.getPersonId(), sentBox.getMessageId()), 6, TimeUnit.SECONDS)
)
.next(endSetting) .next(endSetting)
.build(); .build();
} }
@ -541,8 +539,8 @@ public class InitSettingFlow implements UnitConfiguration {
return BoxAnswer.builder() return BoxAnswer.builder()
.message( .message(
""" """
Configuration completed successfully 🎉 Configuration completed successfully
Developer: [Struchkov.Dev](https://mark.struchkov.dev) 🧑💻 Developer: [Struchkov.Dev](https://mark.struchkov.dev)
""" """
).keyBoard(inlineKeyBoard(simpleButton("Open Menu", "/start"))) ).keyBoard(inlineKeyBoard(simpleButton("Open Menu", "/start")))
.payload(DISABLE_WEB_PAGE_PREVIEW, true) .payload(DISABLE_WEB_PAGE_PREVIEW, true)

View File

@ -14,7 +14,6 @@ public final class UnitName {
public static final String ANSWER_NOTE = "answerNote"; public static final String ANSWER_NOTE = "answerNote";
public static final String TEXT_PARSER_PRIVATE_PROJECT = "textParserPrivateProject"; public static final String TEXT_PARSER_PRIVATE_PROJECT = "textParserPrivateProject";
public static final String CHECK_PARSER_PRIVATE_PROJECT_YES = "checkParserPrivateProject"; public static final String CHECK_PARSER_PRIVATE_PROJECT_YES = "checkParserPrivateProject";
public static final String TEXT_PARSE_OWNER_PROJECT = "textParseOwnerProject";
public static final String CHECK_PARSE_OWNER_PROJECT_YES = "checkParseOwnerProject"; public static final String CHECK_PARSE_OWNER_PROJECT_YES = "checkParseOwnerProject";
public static final String END_SETTING = "endSetting"; public static final String END_SETTING = "endSetting";
public static final String ACCESS_ERROR = "ACCESS_ERROR"; public static final String ACCESS_ERROR = "ACCESS_ERROR";
@ -24,7 +23,6 @@ public final class UnitName {
public static final String AUTO_PARSE_PRIVATE_PROJECT = "AUTO_PARSE_PRIVATE_PROJECT"; public static final String AUTO_PARSE_PRIVATE_PROJECT = "AUTO_PARSE_PRIVATE_PROJECT";
public static final String AUTO_PARSE_OWNER_PROJECT = "AUTO_PARSE_PUBLIC_PROJECT"; public static final String AUTO_PARSE_OWNER_PROJECT = "AUTO_PARSE_PUBLIC_PROJECT";
public static final String TEXT_AUTO_PARSE_OWNER_PROJECT = "TEXT_AUTO_PARSE_OWNER_PROJECT"; public static final String TEXT_AUTO_PARSE_OWNER_PROJECT = "TEXT_AUTO_PARSE_OWNER_PROJECT";
public static final String GUIDE_START = "GUIDE_START";
public static final String TEXT_PARSER_OWNER_PROJECT = "TEXT_PARSER_OWNER_PROJECT"; public static final String TEXT_PARSER_OWNER_PROJECT = "TEXT_PARSER_OWNER_PROJECT";
// команды // команды