feature!: убрана поддержка Cloudlfare
К сожалению проксирование недоступно принципиально
This commit is contained in:
1 parent
96213e182e
commit
064bb70f32
7 files changed
+28
-56
No files matched your search
+3
-3
@@ -4,21 +4,21 @@ Django приложение связывающее все части сайта
|
|||||||
|
|
||||||
-[x] Реализует кастомный менеджер модели и кастомную модель пользователя с отключенным email.
|
-[x] Реализует кастомный менеджер модели и кастомную модель пользователя с отключенным email.
|
||||||
-[x] Модель данных для поддержки интерфейса и функционала
|
-[x] Модель данных для поддержки интерфейса и функционала
|
||||||
-[ ] Настройки домена, прокси и cloudflare у готовой точки
|
-[ ] Настройки домена и прокси у готовой точки
|
||||||
-[ ] Клиенты и статистика через API панели 3x-ui
|
-[ ] Клиенты и статистика через API панели 3x-ui
|
||||||
|
|
||||||
Зависимости: `Telegram` (интерфейс бота, пользователи, уведомления) и `serverus` (настройка серверов).
|
Зависимости: `Telegram` (интерфейс бота, пользователи, уведомления) и `serverus` (настройка серверов).
|
||||||
|
|
||||||
## Модель данных
|
## Модель данных
|
||||||
|
|
||||||
- `Point` - точка доступа: сервер с панелью 3x-ui и необязательный сервер маскировки. Владелец - `Telegram.User`. Хранит домен, cloudflare, прокси на выходе и доступ к панели.
|
- `Point` - точка доступа: сервер с панелью 3x-ui и необязательный сервер маскировки. Владелец - `Telegram.User`. Хранит домен, прокси на выходе и доступ к панели.
|
||||||
- `Server` - сервер точки с ролью `panel` или `mask`. Хранит текущие порт ssh, пароль root, ключ и отпечаток ssh, а также пароль root, присланный пользователем при добавлении (`default_root_password`).
|
- `Server` - сервер точки с ролью `panel` или `mask`. Хранит текущие порт ssh, пароль root, ключ и отпечаток ssh, а также пароль root, присланный пользователем при добавлении (`default_root_password`).
|
||||||
|
|
||||||
С маскировкой клиенты подключаются к серверу маскировки, он перенаправляет трафик на панель и скрывает ее адрес. Маскировка требует домен.
|
С маскировкой клиенты подключаются к серверу маскировки, он перенаправляет трафик на панель и скрывает ее адрес. Маскировка требует домен.
|
||||||
|
|
||||||
Работа с записями идет через менеджеры и методы моделей, а не через `filter`/`create` напрямую:
|
Работа с записями идет через менеджеры и методы моделей, а не через `filter`/`create` напрямую:
|
||||||
|
|
||||||
- создание: `Point.objects.create_point(owner, panel, mask=None, *, domain, cloudflare, outbound_proxy)` создает точку вместе с серверами, имя и доступ к панели генерирует сама. `Server.objects.create_server(point, role, credentials)`. `Credentials` - адрес и пароль root, которые прислал пользователь
|
- создание: `Point.objects.create_point(owner, panel, mask=None, *, domain, outbound_proxy)` создает точку вместе с серверами, имя и доступ к панели генерирует сама. `Server.objects.create_server(point, role, credentials)`. `Credentials` - адрес и пароль root, которые прислал пользователь
|
||||||
- поиск: `Point.objects.owned_by(owner)`, дальше `find_by_name`, `find_by_pk`, `find_last`. У серверов `find_by_address` и `is_address_taken`, в том числе в пределах точки через `point.servers`
|
- поиск: `Point.objects.owned_by(owner)`, дальше `find_by_name`, `find_by_pk`, `find_last`. У серверов `find_by_address` и `is_address_taken`, в том числе в пределах точки через `point.servers`
|
||||||
- изменение: `point.set_status(status, error)`, `server.reset_fingerprint()`
|
- изменение: `point.set_status(status, error)`, `server.reset_fingerprint()`
|
||||||
- удаление: `point.delete()`, серверы удаляются вместе с точкой
|
- удаление: `point.delete()`, серверы удаляются вместе с точкой
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ DRAFT = 'draft'
|
|||||||
DRAFT_SERVER = 'draft.server'
|
DRAFT_SERVER = 'draft.server'
|
||||||
DRAFT_MASK = 'draft.mask'
|
DRAFT_MASK = 'draft.mask'
|
||||||
DRAFT_DOMAIN = 'draft.domain'
|
DRAFT_DOMAIN = 'draft.domain'
|
||||||
DRAFT_CLOUDFLARE = 'draft.cloudflare'
|
|
||||||
DRAFT_PROXY = 'draft.proxy'
|
DRAFT_PROXY = 'draft.proxy'
|
||||||
SELECT = 'select'
|
SELECT = 'select'
|
||||||
POINT = 'point'
|
POINT = 'point'
|
||||||
@@ -103,10 +102,6 @@ class MyPointInterface(Interface):
|
|||||||
def ask_domain(self, ctx):
|
def ask_domain(self, ctx):
|
||||||
self.ask(ctx, DRAFT_DOMAIN, texts.DOMAIN_PROMPT, [[texts.CANCEL, texts.DELETE]])
|
self.ask(ctx, DRAFT_DOMAIN, texts.DOMAIN_PROMPT, [[texts.CANCEL, texts.DELETE]])
|
||||||
|
|
||||||
@text(texts.CLOUDFLARE, state=DRAFT)
|
|
||||||
def ask_cloudflare(self, ctx):
|
|
||||||
self.ask(ctx, DRAFT_CLOUDFLARE, texts.CLOUDFLARE_PROMPT, [[texts.ENABLE, texts.DISABLE, texts.CANCEL]])
|
|
||||||
|
|
||||||
@text(texts.PROXY, state=DRAFT)
|
@text(texts.PROXY, state=DRAFT)
|
||||||
def ask_proxy(self, ctx):
|
def ask_proxy(self, ctx):
|
||||||
self.ask(ctx, DRAFT_PROXY, texts.PROXY_PROMPT, [[texts.CF_WARP, texts.CANCEL, texts.DELETE]])
|
self.ask(ctx, DRAFT_PROXY, texts.PROXY_PROMPT, [[texts.CF_WARP, texts.CANCEL, texts.DELETE]])
|
||||||
@@ -118,7 +113,6 @@ class MyPointInterface(Interface):
|
|||||||
@text(texts.CANCEL, state=DRAFT_SERVER)
|
@text(texts.CANCEL, state=DRAFT_SERVER)
|
||||||
@text(texts.CANCEL, state=DRAFT_MASK)
|
@text(texts.CANCEL, state=DRAFT_MASK)
|
||||||
@text(texts.CANCEL, state=DRAFT_DOMAIN)
|
@text(texts.CANCEL, state=DRAFT_DOMAIN)
|
||||||
@text(texts.CANCEL, state=DRAFT_CLOUDFLARE)
|
|
||||||
@text(texts.CANCEL, state=DRAFT_PROXY)
|
@text(texts.CANCEL, state=DRAFT_PROXY)
|
||||||
def back_to_draft(self, ctx):
|
def back_to_draft(self, ctx):
|
||||||
self.show_draft(ctx)
|
self.show_draft(ctx)
|
||||||
@@ -153,20 +147,6 @@ class MyPointInterface(Interface):
|
|||||||
ctx.data['draft']['domain'] = ''
|
ctx.data['draft']['domain'] = ''
|
||||||
self.show_draft(ctx)
|
self.show_draft(ctx)
|
||||||
|
|
||||||
@text(texts.ENABLE, state=DRAFT_CLOUDFLARE)
|
|
||||||
def enable_cloudflare(self, ctx):
|
|
||||||
ctx.data['draft']['cloudflare'] = True
|
|
||||||
self.show_draft(ctx)
|
|
||||||
|
|
||||||
@text(texts.DISABLE, state=DRAFT_CLOUDFLARE)
|
|
||||||
def disable_cloudflare(self, ctx):
|
|
||||||
ctx.data['draft']['cloudflare'] = False
|
|
||||||
self.show_draft(ctx)
|
|
||||||
|
|
||||||
@state(DRAFT_CLOUDFLARE)
|
|
||||||
def repeat_cloudflare(self, ctx):
|
|
||||||
self.ask_cloudflare(ctx)
|
|
||||||
|
|
||||||
@state(DRAFT_PROXY)
|
@state(DRAFT_PROXY)
|
||||||
def set_proxy(self, ctx):
|
def set_proxy(self, ctx):
|
||||||
proxy = ctx.text.strip()
|
proxy = ctx.text.strip()
|
||||||
@@ -192,14 +172,11 @@ class MyPointInterface(Interface):
|
|||||||
return ctx.reply(texts.DRAFT_INCOMPLETE)
|
return ctx.reply(texts.DRAFT_INCOMPLETE)
|
||||||
if draft.get('mask') and not draft.get('domain'):
|
if draft.get('mask') and not draft.get('domain'):
|
||||||
return ctx.reply(texts.MASK_WITHOUT_DOMAIN)
|
return ctx.reply(texts.MASK_WITHOUT_DOMAIN)
|
||||||
if draft.get('cloudflare') and not draft.get('domain'):
|
|
||||||
return ctx.reply(texts.CLOUDFLARE_WITHOUT_DOMAIN)
|
|
||||||
point = Point.objects.create_point(
|
point = Point.objects.create_point(
|
||||||
ctx.user,
|
ctx.user,
|
||||||
panel=Credentials(**draft['server']),
|
panel=Credentials(**draft['server']),
|
||||||
mask=Credentials(**draft['mask']) if draft.get('mask') else None,
|
mask=Credentials(**draft['mask']) if draft.get('mask') else None,
|
||||||
domain=draft.get('domain', ''),
|
domain=draft.get('domain', ''),
|
||||||
cloudflare=draft.get('cloudflare', False),
|
|
||||||
outbound_proxy=draft.get('proxy', ''),
|
outbound_proxy=draft.get('proxy', ''),
|
||||||
)
|
)
|
||||||
tasks.install_point.send(point.pk, ctx.chat.pk)
|
tasks.install_point.send(point.pk, ctx.chat.pk)
|
||||||
@@ -305,8 +282,7 @@ class MyPointInterface(Interface):
|
|||||||
|
|
||||||
@text(texts.POINT_DOMAIN, state=POINT)
|
@text(texts.POINT_DOMAIN, state=POINT)
|
||||||
@text(texts.POINT_PROXY, state=POINT)
|
@text(texts.POINT_PROXY, state=POINT)
|
||||||
@text(texts.POINT_CLOUDFLARE, state=POINT)
|
|
||||||
@text(texts.CLIENTS, state=POINT)
|
@text(texts.CLIENTS, state=POINT)
|
||||||
def not_implemented(self, ctx):
|
def not_implemented(self, ctx):
|
||||||
# TODO: настройки домена, прокси, cloudflare и клиенты через API панели 3x-ui
|
# TODO: настройки домена, прокси и клиенты через API панели 3x-ui
|
||||||
ctx.reply(texts.NOT_IMPLEMENTED)
|
ctx.reply(texts.NOT_IMPLEMENTED)
|
||||||
+3
-11
@@ -20,11 +20,8 @@ NO = 'Нет'
|
|||||||
SERVER = 'сервер'
|
SERVER = 'сервер'
|
||||||
MASK = 'маскировка'
|
MASK = 'маскировка'
|
||||||
DOMAIN = 'домен'
|
DOMAIN = 'домен'
|
||||||
CLOUDFLARE = 'cloudflare'
|
|
||||||
PROXY = 'прокси'
|
PROXY = 'прокси'
|
||||||
INSTALL = 'установить'
|
INSTALL = 'установить'
|
||||||
ENABLE = 'включить'
|
|
||||||
DISABLE = 'выключить'
|
|
||||||
CF_WARP = 'cf_warp'
|
CF_WARP = 'cf_warp'
|
||||||
|
|
||||||
# меню сервера
|
# меню сервера
|
||||||
@@ -33,14 +30,13 @@ RELEASE = 'Вернуть'
|
|||||||
REINSTALL = 'Переустановить'
|
REINSTALL = 'Переустановить'
|
||||||
POINT_DOMAIN = 'Домен'
|
POINT_DOMAIN = 'Домен'
|
||||||
POINT_PROXY = 'Прокси'
|
POINT_PROXY = 'Прокси'
|
||||||
POINT_CLOUDFLARE = 'Cloudflare'
|
|
||||||
CLIENTS = 'Клиенты'
|
CLIENTS = 'Клиенты'
|
||||||
USE_OLD = 'Использовать старый'
|
USE_OLD = 'Использовать старый'
|
||||||
|
|
||||||
MAIN_KEYBOARD = [[FAQ, ADD_SERVER, HELP]]
|
MAIN_KEYBOARD = [[FAQ, ADD_SERVER, HELP]]
|
||||||
MAIN_KEYBOARD_WITH_POINTS = [[FAQ, ADD_SERVER, HELP], [MANAGE]]
|
MAIN_KEYBOARD_WITH_POINTS = [[FAQ, ADD_SERVER, HELP], [MANAGE]]
|
||||||
DRAFT_KEYBOARD = [[DOMAIN, CLOUDFLARE, PROXY, MASK], [CANCEL, INSTALL, SERVER, HELP]]
|
DRAFT_KEYBOARD = [[DOMAIN, PROXY, MASK], [CANCEL, INSTALL, SERVER, HELP]]
|
||||||
POINT_KEYBOARD = [[RELEASE, REINSTALL], [POINT_DOMAIN, POINT_PROXY, POINT_CLOUDFLARE], [CLIENTS], [MAIN_MENU]]
|
POINT_KEYBOARD = [[RELEASE, REINSTALL], [POINT_DOMAIN, POINT_PROXY], [CLIENTS], [MAIN_MENU]]
|
||||||
CANCEL_KEYBOARD = [[CANCEL]]
|
CANCEL_KEYBOARD = [[CANCEL]]
|
||||||
|
|
||||||
EMPTY = '-'
|
EMPTY = '-'
|
||||||
@@ -69,7 +65,7 @@ HELP_TEXT = '''<b>Добавить сервер</b>
|
|||||||
1. "добавить сервер"
|
1. "добавить сервер"
|
||||||
2. "сервер" - пришлите <code>ip:пароль</code> сервера для панели
|
2. "сервер" - пришлите <code>ip:пароль</code> сервера для панели
|
||||||
3. по желанию "маскировка" - пришлите <code>ip:пароль</code> сервера маскировки, для нее нужен "домен"
|
3. по желанию "маскировка" - пришлите <code>ip:пароль</code> сервера маскировки, для нее нужен "домен"
|
||||||
4. по желанию "домен", "cloudflare", "прокси"
|
4. по желанию "домен", "прокси"
|
||||||
5. "установить" - установка идет в фоне, по окончании придет уведомление
|
5. "установить" - установка идет в фоне, по окончании придет уведомление
|
||||||
|
|
||||||
<b>Управлять сервером</b>
|
<b>Управлять сервером</b>
|
||||||
@@ -83,12 +79,10 @@ ADDRESS_TAKEN = 'Сервер {address} уже подключен.'
|
|||||||
ADDRESS_DUPLICATE = 'Панель и маскировка должны быть разными серверами.'
|
ADDRESS_DUPLICATE = 'Панель и маскировка должны быть разными серверами.'
|
||||||
DOMAIN_PROMPT = 'Пришли доменное имя. Доменное имя лучше подходит для маскировки вашей точки доступа.'
|
DOMAIN_PROMPT = 'Пришли доменное имя. Доменное имя лучше подходит для маскировки вашей точки доступа.'
|
||||||
DOMAIN_INVALID = 'Не похоже на доменное имя. Попробуй еще раз.'
|
DOMAIN_INVALID = 'Не похоже на доменное имя. Попробуй еще раз.'
|
||||||
CLOUDFLARE_PROMPT = 'Если вы спрятали домен за клаудом, то нужно включить опцию тут.'
|
|
||||||
PROXY_PROMPT = 'Можно указать свои в формате <code>protocol://username:password@host:port</code> или включить cf_warp.'
|
PROXY_PROMPT = 'Можно указать свои в формате <code>protocol://username:password@host:port</code> или включить cf_warp.'
|
||||||
PROXY_INVALID = 'Не похоже на <code>protocol://username:password@host:port</code>. Попробуй еще раз.'
|
PROXY_INVALID = 'Не похоже на <code>protocol://username:password@host:port</code>. Попробуй еще раз.'
|
||||||
DRAFT_INCOMPLETE = 'Нужен сервер для панели: "сервер".'
|
DRAFT_INCOMPLETE = 'Нужен сервер для панели: "сервер".'
|
||||||
MASK_WITHOUT_DOMAIN = 'Сервер маскировки работает только с доменом. Укажи домен или убери маскировку.'
|
MASK_WITHOUT_DOMAIN = 'Сервер маскировки работает только с доменом. Укажи домен или убери маскировку.'
|
||||||
CLOUDFLARE_WITHOUT_DOMAIN = 'Cloudflare работает только с доменом. Укажи домен или выключи cloudflare.'
|
|
||||||
INSTALL_STARTED = 'Запускаю установку сервера. Отправлю уведомление когда все будет готово.'
|
INSTALL_STARTED = 'Запускаю установку сервера. Отправлю уведомление когда все будет готово.'
|
||||||
|
|
||||||
SELECT_PROMPT = 'Пришлите server_name'
|
SELECT_PROMPT = 'Пришлите server_name'
|
||||||
@@ -119,7 +113,6 @@ def draft_card(draft: dict) -> str:
|
|||||||
f"Сервер: {value(draft.get('server', {}).get('address', ''))}",
|
f"Сервер: {value(draft.get('server', {}).get('address', ''))}",
|
||||||
f"Сервер маскировки: {value(draft.get('mask', {}).get('address', ''))}",
|
f"Сервер маскировки: {value(draft.get('mask', {}).get('address', ''))}",
|
||||||
f"Домен: {value(draft.get('domain', ''))}",
|
f"Домен: {value(draft.get('domain', ''))}",
|
||||||
f"Cloudflare: {'Да' if draft.get('cloudflare') else EMPTY}",
|
|
||||||
f"Прокси: {value(draft.get('proxy', ''))}",
|
f"Прокси: {value(draft.get('proxy', ''))}",
|
||||||
])
|
])
|
||||||
|
|
||||||
@@ -141,7 +134,6 @@ def point_card(point: Point) -> str:
|
|||||||
# TODO: онлайн/всего ключей из API панели
|
# TODO: онлайн/всего ключей из API панели
|
||||||
f'Ключи: {EMPTY}',
|
f'Ключи: {EMPTY}',
|
||||||
f'Домен: {value(point.domain)}',
|
f'Домен: {value(point.domain)}',
|
||||||
f"Cloudflare: {'Да' if point.cloudflare else EMPTY}",
|
|
||||||
f'Прокси: {value(point.outbound_proxy)}',
|
f'Прокси: {value(point.outbound_proxy)}',
|
||||||
]
|
]
|
||||||
if point.error:
|
if point.error:
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
# Generated by Django 6.1.1 on 2026-09-25 13:37
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('App', '0004_point_subscription_inbound'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='point',
|
||||||
|
name='cloudflare',
|
||||||
|
),
|
||||||
|
]
|
||||||
+1
-4
@@ -85,8 +85,7 @@ class PointQuerySet(models.QuerySet):
|
|||||||
|
|
||||||
class PointManager(models.Manager.from_queryset(PointQuerySet)):
|
class PointManager(models.Manager.from_queryset(PointQuerySet)):
|
||||||
def create_point(
|
def create_point(
|
||||||
self, owner, panel: Credentials, mask: Credentials | None = None, *, domain: str = '',
|
self, owner, panel: Credentials, mask: Credentials | None = None, *, domain: str = '', outbound_proxy: str = '',
|
||||||
cloudflare: bool = False, outbound_proxy: str = '',
|
|
||||||
) -> 'Point':
|
) -> 'Point':
|
||||||
"""Создает точку вместе с ее серверами. Вызывать через Point.objects.
|
"""Создает точку вместе с ее серверами. Вызывать через Point.objects.
|
||||||
|
|
||||||
@@ -98,7 +97,6 @@ class PointManager(models.Manager.from_queryset(PointQuerySet)):
|
|||||||
owner=owner,
|
owner=owner,
|
||||||
name=self._unique_name(),
|
name=self._unique_name(),
|
||||||
domain=domain,
|
domain=domain,
|
||||||
cloudflare=cloudflare,
|
|
||||||
outbound_proxy=outbound_proxy,
|
outbound_proxy=outbound_proxy,
|
||||||
panel_username=generate_username(),
|
panel_username=generate_username(),
|
||||||
panel_password=generate_password(),
|
panel_password=generate_password(),
|
||||||
@@ -141,7 +139,6 @@ class Point(models.Model):
|
|||||||
error = models.TextField(blank=True)
|
error = models.TextField(blank=True)
|
||||||
|
|
||||||
domain = models.CharField(max_length=253, blank=True)
|
domain = models.CharField(max_length=253, blank=True)
|
||||||
cloudflare = models.BooleanField(default=False, help_text='Домен спрятан за Cloudflare')
|
|
||||||
outbound_proxy = models.CharField(
|
outbound_proxy = models.CharField(
|
||||||
max_length=512, blank=True, help_text=f'protocol://user:password@host:port или {CF_WARP}',
|
max_length=512, blank=True, help_text=f'protocol://user:password@host:port или {CF_WARP}',
|
||||||
)
|
)
|
||||||
|
|||||||
+2
-2
@@ -60,8 +60,8 @@ def set_domain(point: Point, domain: str):
|
|||||||
|
|
||||||
Домен должен уже указывать на панель или на сервер маскировки.
|
Домен должен уже указывать на панель или на сервер маскировки.
|
||||||
"""
|
"""
|
||||||
if not domain and (point.mask or point.cloudflare):
|
if not domain and point.mask:
|
||||||
raise ValueError('маскировка и cloudflare работают только с доменом')
|
raise ValueError('маскировка работает только с доменом')
|
||||||
with _installing(point):
|
with _installing(point):
|
||||||
_check(point.panel, serverus.XuiPanel(point.panel.host()).issue_certificate(domain))
|
_check(point.panel, serverus.XuiPanel(point.panel.host()).issue_certificate(domain))
|
||||||
point.domain = domain
|
point.domain = domain
|
||||||
|
|||||||
+1
-11
@@ -72,19 +72,16 @@ class AddServerTests(BotTestCase):
|
|||||||
self.fill(texts.MASK, '10.0.0.2:mask-pw')
|
self.fill(texts.MASK, '10.0.0.2:mask-pw')
|
||||||
self.say(texts.DOMAIN)
|
self.say(texts.DOMAIN)
|
||||||
self.say('Example.COM.')
|
self.say('Example.COM.')
|
||||||
self.say(texts.CLOUDFLARE)
|
|
||||||
self.say(texts.ENABLE)
|
|
||||||
self.say(texts.PROXY)
|
self.say(texts.PROXY)
|
||||||
card = self.say(texts.CF_WARP)
|
card = self.say(texts.CF_WARP)
|
||||||
self.assertIn('Домен: example.com', card)
|
self.assertIn('Домен: example.com', card)
|
||||||
self.assertIn('Cloudflare: Да', card)
|
|
||||||
self.assertIn('Прокси: cf_warp', card)
|
self.assertIn('Прокси: cf_warp', card)
|
||||||
|
|
||||||
self.assertEqual(self.say(texts.INSTALL), texts.INSTALL_STARTED)
|
self.assertEqual(self.say(texts.INSTALL), texts.INSTALL_STARTED)
|
||||||
point = Point.objects.get()
|
point = Point.objects.get()
|
||||||
self.assertEqual((point.panel.address, point.panel.root_password), ('10.0.0.1', 'panel-pw'))
|
self.assertEqual((point.panel.address, point.panel.root_password), ('10.0.0.1', 'panel-pw'))
|
||||||
self.assertEqual((point.mask.address, point.mask.root_password), ('10.0.0.2', 'mask-pw'))
|
self.assertEqual((point.mask.address, point.mask.root_password), ('10.0.0.2', 'mask-pw'))
|
||||||
self.assertEqual((point.domain, point.cloudflare, point.outbound_proxy), ('example.com', True, 'cf_warp'))
|
self.assertEqual((point.domain, point.outbound_proxy), ('example.com', 'cf_warp'))
|
||||||
self.assertEqual(point.owner, TelegramUser.objects.get())
|
self.assertEqual(point.owner, TelegramUser.objects.get())
|
||||||
send.assert_called_once_with(point.pk, Chat.objects.get().pk)
|
send.assert_called_once_with(point.pk, Chat.objects.get().pk)
|
||||||
# сообщения с паролями удалены из чата
|
# сообщения с паролями удалены из чата
|
||||||
@@ -123,13 +120,6 @@ class AddServerTests(BotTestCase):
|
|||||||
self.assertEqual(self.say(texts.INSTALL), texts.INSTALL_STARTED)
|
self.assertEqual(self.say(texts.INSTALL), texts.INSTALL_STARTED)
|
||||||
self.assertIsNone(Point.objects.get().mask)
|
self.assertIsNone(Point.objects.get().mask)
|
||||||
|
|
||||||
def test_cloudflare_requires_domain(self, send):
|
|
||||||
self.say(texts.ADD_SERVER)
|
|
||||||
self.fill(texts.SERVER, '10.0.0.1:pw')
|
|
||||||
self.fill(texts.CLOUDFLARE, texts.ENABLE)
|
|
||||||
self.assertEqual(self.say(texts.INSTALL), texts.CLOUDFLARE_WITHOUT_DOMAIN)
|
|
||||||
send.assert_not_called()
|
|
||||||
|
|
||||||
def test_cancel_in_prompt_returns_to_draft(self, send):
|
def test_cancel_in_prompt_returns_to_draft(self, send):
|
||||||
self.say(texts.ADD_SERVER)
|
self.say(texts.ADD_SERVER)
|
||||||
self.fill(texts.SERVER, '10.0.0.1:pw')
|
self.fill(texts.SERVER, '10.0.0.1:pw')
|
||||||
|
|||||||
Reference in new issue
Block a user