diff options
-rw-r--r-- | bin/web_kbn.py | 64 | ||||
-rw-r--r-- | include/py/homekit/config/config.py | 10 | ||||
-rw-r--r-- | localwebsite/handlers/ModemHandler.php | 79 | ||||
-rw-r--r-- | requirements.txt | 1 | ||||
-rw-r--r-- | web/kbn_templates/index.j2 | 4 | ||||
-rw-r--r-- | web/kbn_templates/sms.j2 (renamed from localwebsite/templates-web/sms_page.twig) | 31 |
6 files changed, 87 insertions, 102 deletions
diff --git a/bin/web_kbn.py b/bin/web_kbn.py index 09fa9c6..c21269b 100644 --- a/bin/web_kbn.py +++ b/bin/web_kbn.py @@ -5,6 +5,7 @@ import aiohttp_jinja2 import json import re import inverterd +import phonenumbers import __py_include from io import StringIO @@ -27,6 +28,8 @@ class WebKbnConfig(AppConfigUnit): 'listen_addr': cls._addr_schema(required=True), 'assets_public_path': {'type': 'string'}, 'pump_addr': cls._addr_schema(required=True), + 'inverter_grafana_url': {'type': 'string'}, + 'sensors_grafana_url': {'type': 'string'}, } @@ -69,8 +72,12 @@ def get_head_static() -> str: return buf.getvalue() +def get_modem_client(modem_cfg: dict) -> E3372: + return E3372(modem_cfg['ip'], legacy_token_auth=modem_cfg['legacy_auth']) + + def get_modem_data(modem_cfg: dict, get_raw=False) -> Union[dict, tuple]: - cl = E3372(modem_cfg['ip'], legacy_token_auth=modem_cfg['legacy_auth']) + cl = get_modem_client(modem_cfg) signal = cl.device_signal status = cl.monitoring_status @@ -190,6 +197,8 @@ class WebSite(http.HTTPServer): self.get('/inverter.cgi', self.inverter) self.get('/inverter.ajx', self.inverter_ajx) self.get('/pump.cgi', self.pump) + self.get('/sms.cgi', self.sms) + self.post('/sms.cgi', self.sms_post) async def render_page(self, req: http.Request, @@ -208,8 +217,12 @@ class WebSite(http.HTTPServer): return response async def index(self, req: http.Request): + ctx = {} + for k in 'inverter', 'sensors': + ctx[f'{k}_grafana_url'] = config.app_config[f'{k}_grafana_url'] return await self.render_page(req, 'index', - title="Home web site") + title="Home web site", + context=ctx) async def modems(self, req: http.Request): return await self.render_page(req, 'modems', @@ -218,7 +231,7 @@ class WebSite(http.HTTPServer): async def modems_ajx(self, req: http.Request): modem = req.query.get('id', None) - if modem not in self._modems_config.getkeys(): + if modem not in self._modems_config.keys(): raise ValueError('invalid modem id') modem_cfg = self._modems_config.get(modem) @@ -234,7 +247,7 @@ class WebSite(http.HTTPServer): async def modems_verbose(self, req: http.Request): modem = req.query.get('id', None) - if modem not in self._modems_config.getkeys(): + if modem not in self._modems_config.keys(): raise ValueError('invalid modem id') modem_cfg = self._modems_config.get(modem) @@ -253,6 +266,49 @@ class WebSite(http.HTTPServer): title=f'Подробная информация о модеме "{modem_name}"', context=dict(data=data, modem_name=modem_name)) + async def sms(self, req: http.Request): + modem = req.query.get('id', list(self._modems_config.keys())[0]) + is_outbox = int(req.query.get('outbox', 0)) == 1 + error = req.query.get('error', None) + sent = int(req.query.get('sent', 0)) == 1 + + cl = get_modem_client(self._modems_config[modem]) + messages = cl.sms_list(1, 20, is_outbox) + return await self.render_page(req, 'sms', + title=f"SMS-сообщения ({'исходящие' if is_outbox else 'входящие'}, {modem})", + context=dict( + modems=self._modems_config, + selected_modem=modem, + is_outbox=is_outbox, + error=error, + is_sent=sent, + messages=messages + )) + + async def sms_post(self, req: http.Request): + modem = req.query.get('id', list(self._modems_config.keys())[0]) + is_outbox = int(req.query.get('outbox', 0)) == 1 + + fd = await req.post() + phone = fd.get('phone', None) + text = fd.get('text', None) + + return_url = f'/sms.cgi?id={modem}&outbox={int(is_outbox)}' + phone = re.sub('\s+', '', phone) + + if len(phone) > 4: + country = None + if not phone.startswith('+'): + country = 'RU' + number = phonenumbers.parse(phone, country) + if not phonenumbers.is_valid_number(number): + raise HTTPFound(f'{return_url}&error=Неверный+номер') + phone = phonenumbers.format_number(number, phonenumbers.PhoneNumberFormat.E164) + + cl = get_modem_client(self._modems_config[modem]) + cl.sms_send(phone, text) + raise HTTPFound(return_url) + async def inverter(self, req: http.Request): action = req.query.get('do', None) if action == 'set-osp': diff --git a/include/py/homekit/config/config.py b/include/py/homekit/config/config.py index eb2ad82..fec92a6 100644 --- a/include/py/homekit/config/config.py +++ b/include/py/homekit/config/config.py @@ -78,8 +78,14 @@ class BaseConfigUnit(ABC): raise KeyError(f'option {key} not found') - def getkeys(self): - return list(self._data.keys()) + def values(self): + return self._data.values() + + def keys(self): + return self._data.keys() + + def items(self): + return self._data.items() class ConfigUnit(BaseConfigUnit): diff --git a/localwebsite/handlers/ModemHandler.php b/localwebsite/handlers/ModemHandler.php index 8179620..94ad75b 100644 --- a/localwebsite/handlers/ModemHandler.php +++ b/localwebsite/handlers/ModemHandler.php @@ -95,85 +95,6 @@ class ModemHandler extends RequestHandler $this->tpl->render_page('routing_dhcp_page.twig'); } - public function GET_sms() { - global $config; - - list($selected, $is_outbox, $error, $sent) = $this->input('modem, b:outbox, error, b:sent'); - if (!$selected) - $selected = array_key_first($config['modems']); - - $cfg = $config['modems'][$selected]; - $e3372 = new E3372($cfg['ip'], $cfg['legacy_token_auth']); - $messages = $e3372->getSMSList(1, 20, $is_outbox); - - $this->tpl->set([ - 'modems_list' => array_keys($config['modems']), - 'modems' => $config['modems'], - 'selected_modem' => $selected, - 'messages' => $messages, - 'is_outbox' => $is_outbox, - 'error' => $error, - 'is_sent' => $sent - ]); - - $direction = $is_outbox ? 'исходящие' : 'входящие'; - $this->tpl->set_title('SMS-сообщения ('.$direction.', '.$selected.')'); - $this->tpl->render_page('sms_page.twig'); - } - - public function POST_sms() { - global $config; - - list($selected, $is_outbox, $phone, $text) = $this->input('modem, b:outbox, phone, text'); - if (!$selected) - $selected = array_key_first($config['modems']); - - $return_url = '/sms/?modem='.$selected; - if ($is_outbox) - $return_url .= '&outbox=1'; - - $go_back = function(?string $error = null) use ($return_url) { - if (!is_null($error)) - $return_url .= '&error='.urlencode($error); - else - $return_url .= '&sent=1'; - redirect($return_url); - }; - - $phone = preg_replace('/\s+/', '', $phone); - - // при отправке смс на короткие номера не надо использовать libphonenumber и вот это вот всё - if (strlen($phone) > 4) { - $country = null; - if (!startsWith($phone, '+')) - $country = 'RU'; - - $phoneUtil = PhoneNumberUtil::getInstance(); - try { - $number = $phoneUtil->parse($phone, $country); - } catch (NumberParseException $e) { - debugError(__METHOD__.': failed to parse number '.$phone.': '.$e->getMessage()); - $go_back('Неверный номер ('.$e->getMessage().')'); - return; - } - - if (!$phoneUtil->isValidNumber($number)) { - $go_back('Неверный номер'); - return; - } - - $phone = $phoneUtil->format($number, PhoneNumberFormat::E164); - } - - $cfg = $config['modems'][$selected]; - $e3372 = new E3372($cfg['ip'], $cfg['legacy_token_auth']); - - $result = $e3372->sendSMS($phone, $text); - debugLog($result); - - $go_back(); - } - protected static function getCurrentUpstream() { global $config; diff --git a/requirements.txt b/requirements.txt index 8fa67c3..c242f38 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,6 +14,7 @@ psutil~=5.9.1 aioshutil~=1.1 scikit-image==0.21.0 cerberus~=1.3.4 +phonenumbers~=8.13.28 # following can be installed from debian repositories # matplotlib~=3.5.0 diff --git a/web/kbn_templates/index.j2 b/web/kbn_templates/index.j2 index e3ab421..c356326 100644 --- a/web/kbn_templates/index.j2 +++ b/web/kbn_templates/index.j2 @@ -23,9 +23,9 @@ <h6 class="mt-4">Другое</h6> <ul class="list-group list-group-flush"> - <li class="list-group-item"><a href="/inverter.cgi">Инвертор</a> (<a href="{{ grafana_inverter_url }}">Grafana</a>)</li> + <li class="list-group-item"><a href="/inverter.cgi">Инвертор</a> (<a href="{{ inverter_grafana_url }}">Grafana</a>)</li> <li class="list-group-item"><a href="/pump.cgi">Насос</a></li> - <li class="list-group-item"><a href="/sensors.cgi">Датчики</a> (<a href="{{ grafana_sensors_url }}">Grafana</a>)</li> + <li class="list-group-item"><a href="/sensors.cgi">Датчики</a> (<a href="{{ sensors_grafana_url }}">Grafana</a>)</li> </ul> <h6 class="mt-4"><a href="/cams/"><b>Все камеры</b></a> (<a href="/cams/?high=1">HQ</a>)</h6> diff --git a/localwebsite/templates-web/sms_page.twig b/web/kbn_templates/sms.j2 index 112fa64..6de9d42 100644 --- a/localwebsite/templates-web/sms_page.twig +++ b/web/kbn_templates/sms.j2 @@ -1,14 +1,13 @@ -{% include 'bc.twig' with { - history: [ - {text: "SMS-сообщения" } - ] -} %} +{% extends "base.j2" %} + +{% block content %} +{{ breadcrumbs([{'text': 'SMS-сообщения'}]) }} <nav> <div class="nav nav-tabs" id="nav-tab"> - {% for modem in modems_list %} - {% if selected_modem != modem %}<a href="/sms/?modem={{ modem }}" class="text-decoration-none">{% endif %} - <button class="nav-link{% if modem == selected_modem %} active{% endif %}" type="button">{{ modems[modem].short_label }}</button> + {% for modem in modems.keys() %} + {% if selected_modem != modem %}<a href="/sms.cgi?id={{ modem }}" class="text-decoration-none">{% endif %} + <button class="nav-link{% if modem == selected_modem %} active{% endif %}" type="button">{{ modems.getshortname(modem) }}</button> {% if selected_modem != modem %}</a>{% endif %} {% endfor %} </div> @@ -20,14 +19,14 @@ <div class="alert alert-success" role="alert"> Сообщение отправлено. </div> -{% elseif error %} +{% elif error %} <div class="alert alert-danger" role="alert"> {{ error }} </div> {% endif %} <div> - <form method="post" action="/sms/"> + <form method="post" action="/sms.cgi"> <input type="hidden" name="modem" value="{{ selected_modem }}"> <div class="form-floating mb-3"> <input type="text" name="phone" class="form-control" id="inputPhone" placeholder="+7911xxxyyzz"> @@ -46,17 +45,19 @@ <h6 class="text-primary mt-4"> Последние {% if not is_outbox %} - <b>входящие</b> <span class="text-black-50">|</span> <a href="/sms/?modem={{ selected_modem }}&outbox=1">исходящие</a> + <b>входящие</b> <span class="text-black-50">|</span> <a href="/sms.cgi?id={{ selected_modem }}&outbox=1">исходящие</a> {% else %} - <a href="/sms/?modem={{ selected_modem }}">входящие</a> <span class="text-black-50">|</span> <b>исходящие</b> + <a href="/sms.cgi?id={{ selected_modem }}">входящие</a> <span class="text-black-50">|</span> <b>исходящие</b> {% endif %} </h6> {% for m in messages %} <div class="mt-3"> - <b>{{ m.phone }}</b> <span class="text-secondary">({{ m.date }})</span><br/> - {{ m.content }} + <b>{{ m.Phone }}</b> <span class="text-secondary">({{ m.Date }})</span><br/> + {{ m.Content }} </div> {% else %} <span class="text-secondary">Сообщений нет.</span> -{% endfor %}
\ No newline at end of file +{% endfor %} + +{% endblock %}
\ No newline at end of file |