Compare commits
10 Commits
8cbbd15829
...
1a52626440
Author | SHA1 | Date | |
---|---|---|---|
![]() |
1a52626440 | ||
![]() |
d8b1af4cda | ||
![]() |
aacbe7e013 | ||
![]() |
9d8a1bdf6b | ||
![]() |
a8c156e25d | ||
![]() |
5975923cbb | ||
![]() |
3de98e01b3 | ||
![]() |
e8c8cb393f | ||
![]() |
65042dcebc | ||
![]() |
04c204fc57 |
13
README.md
13
README.md
@ -1,5 +1,14 @@
|
|||||||
## Тестовое задание rosmorport
|
## Тестовое задание rosmorport
|
||||||
|
|
||||||
* [Задание](target.md) (таким, как оно было выдано, авторская орфография и пунктуация).
|
Тестовое задание на соискание вакансии `Frontend-разработчик` в ФГУП РосМорФлот.
|
||||||
* Пакеты virtualenv: [dev (home win)](requare_dev_w_home.txt) / [prod (ubuntu)](requare_dev_prod.txt).
|
|
||||||
|
* [Тестовое задание](target.md) (таким, как оно было выдано, авторская орфография и пунктуация).
|
||||||
|
* [Мой ответ](my_anwer.txt) (спустя два дня)
|
||||||
|
* [Ответ РосМорФлот](feedback.txt) (спустя четыре дня, в ответ на просьбу обратной связи... судя по логам
|
||||||
|
заходил один раз сразу по получения решения).
|
||||||
|
|
||||||
|
Мое мнение о тестовом задании: в задании нет никаких рекомендаций, ограничений и запретов на
|
||||||
|
какие-либо _выбранные технологии_... Зачем задании столько требований по Backend, если вакансия
|
||||||
|
`Frontend-разработчик` -- загадка. И, похоже, дополнительно нужен навык чтения мыслей на расстоянии.
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
# ТЕСТОВОЕ ЗАДАНИЕ РОСМОРПОРТ
|
# ТЕСТОВОЕ ЗАДАНИЕ РОСМОРПОРТ
|
||||||
# == Конфикурационный файл pets-clone--nginx.conf ==
|
# == Конфикурационный файл pet-clones--nginx.conf ==
|
||||||
|
|
||||||
# Описываем апстрим-потоки которые должен подключить Nginx
|
# Описываем апстрим-потоки которые должен подключить Nginx
|
||||||
# Для каждого сайта надо настроить свой поток, со своим уникальным именем.
|
# Для каждого сайта надо настроить свой поток, со своим уникальным именем.
|
||||||
@ -7,79 +7,64 @@
|
|||||||
|
|
||||||
upstream pet-clone {
|
upstream pet-clone {
|
||||||
# расположение файла Unix-сокет для взаимодействие с uwsgi
|
# расположение файла Unix-сокет для взаимодействие с uwsgi
|
||||||
server unix:///home/web/clone.cocorico.ru/socket/clone_pets.sock;
|
server unix:///home/web/pet-clones.cocorico.ru/socket/clone_pets.sock;
|
||||||
# также можно использовать веб-сокет (порт) для взаимодействие с uwsgi. Но это медленнее
|
|
||||||
# server 127.0.0.1:8021; # для взаимодействия с uwsgi через веб-порт 8021
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# конфигурируем сервер
|
# конфигурируем сервер
|
||||||
server {
|
server {
|
||||||
server_name clone.cocorico.ru; # доменное имя сайта
|
server_name pet-clones.cocorico.ru; # доменное имя сайта
|
||||||
listen 443 ssl; # managed by Certbot
|
listen 443 ssl; # managed by Certbot
|
||||||
|
|
||||||
ssl_certificate /etc/letsencrypt/live/clone.cocorico.ru/fullchain.pem; # managed by Certbot
|
ssl_certificate /etc/letsencrypt/live/pet-clones.cocorico.ru/fullchain.pem; # managed by Certbot
|
||||||
ssl_certificate_key /etc/letsencrypt/live/clone.cocorico.ru/privkey.pem; # managed by Certbot
|
ssl_certificate_key /etc/letsencrypt/live/pet-clones.cocorico.ru/privkey.pem; # managed by Certbot
|
||||||
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
|
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
|
||||||
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
|
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
|
||||||
|
|
||||||
ssl_protocols TLSv1 TLSv1.1;
|
|
||||||
# ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';
|
# ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';
|
||||||
resolver 217.16.16.15 217.16.20.15 217.16.22.15 217.16.16.31 77.88.8.8 valid=10s;
|
|
||||||
ssl_session_cache builtin:1000 shared:SSL:25m;
|
ssl_session_cache builtin:1000 shared:SSL:25m;
|
||||||
keepalive_requests 200;
|
|
||||||
keepalive_timeout 75s;
|
keepalive_timeout 75s;
|
||||||
|
|
||||||
charset utf-8; # кодировка по умолчанию
|
charset utf-8; # кодировка по умолчанию
|
||||||
|
|
||||||
access_log /home/web/clone.cocorico.ru/logs/clone-pets-access.log; # логи с доступом
|
access_log /home/web/pet-clones.cocorico.ru/logs/clone-pets-access.log; # логи с доступом
|
||||||
error_log /home/web/clone.cocorico.ru/logs/clone-pets-error.log; # логи с ошибками
|
error_log /home/web/pet-clones.cocorico.ru/logs/clone-pets-error.log; # логи с ошибками
|
||||||
|
|
||||||
client_max_body_size 100M; # максимальный объем файла для загрузки на сайт (max upload size)
|
client_max_body_size 100M; # максимальный объем файла для загрузки на сайт (max upload size)
|
||||||
|
|
||||||
error_page 404 /404.html;
|
error_page 404 /404.html;
|
||||||
error_page 500 /500.html;
|
error_page 500 /500.html;
|
||||||
|
|
||||||
location /media { alias /home/web/clone.cocorico.ru/public/media; } # Расположение media-файлов Django
|
location /media { alias /home/web/pet-clones.cocorico.ru/public/media; } # Расположение media-файлов Django
|
||||||
location /static { alias /home/web/clone.cocorico.ru/public/static; } # Расположение static-файлов Django
|
location /static { alias /home/web/pet-clones.cocorico.ru/public/static; } # Расположение static-файлов Django
|
||||||
|
|
||||||
location /robots.txt { root /home/web/clone.cocorico.ru/public; } # Расположение robots.txt
|
location /robots.txt { root /home/web/pet-clones.cocorico.ru/public; } # Расположение robots.txt
|
||||||
location /favicon.ico { root /home/web/clone.cocorico.ru/public/static/img; } # Расположение favicon.ico
|
location /favicon.ico { root /home/web/pet-clones.cocorico.ru/public/static/img; } # Расположение favicon.ico
|
||||||
location /favicon.png { root /home/web/clone.cocorico.ru/public/static/img; } # Расположение favicon
|
location /favicon.png { root /home/web/pet-clones.cocorico.ru/public/static/img; } # Расположение favicon
|
||||||
location = /404.html {
|
location = /404.html {
|
||||||
root /home/web/clone.cocorico.ru/rosmorport_tsts/templates-django/404.html;
|
root /home/web/pet-clones.cocorico.ru/rosmorport_tsts/templates-django/404.html;
|
||||||
internal;
|
internal;
|
||||||
}
|
}
|
||||||
location = /500.html {
|
location = /500.html {
|
||||||
root /home/web/clone.cocorico.ru/rosmorport_tsts/templates-django/500.html;
|
root /home/web/pet-clones.cocorico.ru/rosmorport_tsts/templates-django/500.html;
|
||||||
internal;
|
internal;
|
||||||
}
|
}
|
||||||
location ~ \.(xml|html|htm|txt|svg)$ {
|
location ~ \.(xml|html|htm|txt|svg)$ {
|
||||||
root /home/web/clone.cocorico.ru/public; # Расположение статичных *.xml, *.html и *.txt
|
root /home/web/pet-clones.cocorico.ru/public; # Расположение статичных *.xml, *.html и *.txt
|
||||||
}
|
}
|
||||||
|
|
||||||
location / {
|
location / {
|
||||||
# uwsgi_pass pet-clone; # upstream обрабатывающий обращений
|
uwsgi_pass pet-clone; # upstream обрабатывающий обращений
|
||||||
# # uwsgi_pass 127.0.0.1:8001; # upstream обрабатывающий обращений
|
include uwsgi_params; # конфигурационный файл uwsgi;
|
||||||
# include uwsgi_params; # конфигурационный файл uwsgi;
|
uwsgi_read_timeout 1800; # вдруг некоторые запросы очень долго обрабатываются?
|
||||||
# uwsgi_read_timeout 1800; # вдруг некоторые запросы очень долго обрабатываются?
|
uwsgi_send_timeout 200; # на всякий случай время записи в сокет тоже побольше...
|
||||||
# uwsgi_send_timeout 200; # на всякий случай время записи в сокет тоже побольше...
|
|
||||||
proxy_pass http://127.0.0.1:8080;
|
|
||||||
proxy_set_header Host $host;
|
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
server {
|
server {
|
||||||
if ($host = clone.cocorico.ru) {
|
if ($host = pet-clones.cocorico.ru) {
|
||||||
return 301 https://$host$request_uri;
|
return 301 https://$host$request_uri;
|
||||||
} # managed by Certbot
|
} # managed by Certbot
|
||||||
|
server_name pet-clones.cocorico.ru;
|
||||||
|
|
||||||
listen 80;
|
listen 80;
|
||||||
server_name clone.cocorico.ru;
|
|
||||||
return 404; # managed by Certbot
|
return 404; # managed by Certbot
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
@ -1,64 +1,66 @@
|
|||||||
# === Конфикурационный файл uwsgi pets-clone--uwsgi.ini ===
|
# === Конфигурационный файл uwsgi pets-clone--uwsgi.ini ===
|
||||||
|
# ░▒▓████▓▒░▒▓█████▓▒░▒▓█▓▒░ ▒▓██████▓▒░ ВНИМАНИЕ ДЛЯ ТЕХ КТО ДЕПЛОИТ ИЗ ПОД MICROSOFT WINDOWS!!
|
||||||
|
# ░▒▓█▓▒▒▓█▓▒▒▓█▓▒▒▓█▓▒▒▓█▓▒░ ▒▓█▓▒░ ОКОНЧАНИЯ СТРОК ДОЛЖНЫ БЫТЬ В ФОРМАТЕ UNIX (LF) а не CR+LR (как в Win)
|
||||||
|
#-░▒▓█▓▒░----▒▓█████▓▒-▒▓█▓▒░---▒▓████▓▒░----------------------------------------------------------------
|
||||||
|
# ░▒▓█▓▒▒▓█▓▒▒▓█▓▒▒▓█▓▒▒▓█▓▒░ ▒▓█▓▒░ Заметка: CR - carriage return (\r, возврат каретки, ВК)
|
||||||
|
# ░▒▓████▓▒░▒▓█▓▒▒▓█▓▒▒▓█████▓▒▒▓█▓▒░ LF - line feed (\n, перевод строки, ПС)
|
||||||
|
|
||||||
[uwsgi]
|
[uwsgi]
|
||||||
|
|
||||||
# НАСТРОЙКИ ДЛЯ DJANGO
|
# НАСТРОЙКИ ДЛЯ DJANGO
|
||||||
# Корневая папка проекта (полный путь)
|
# Корневая папка проекта (полный путь)
|
||||||
chdir: /home/web/clone.cocorico.ru/rosmorport_tsts
|
chdir = /home/web/pet-clones.cocorico.ru/rosmorport_tsts
|
||||||
# Django wsgi файл rosmorport_tsts/wsgi.py записываем так:
|
module = rosmorport_tsts.wsgi
|
||||||
module: rosmorport_tsts.wsgi
|
|
||||||
# полный путь к виртуальному окружению
|
# полный путь к виртуальному окружению
|
||||||
home: /home/web/clone.cocorico.ru/env
|
home = /home/web/pet-clones.cocorico.ru/env
|
||||||
# полный путь к файлу сокета
|
# полный путь к файлу сокета
|
||||||
# route: ^/websocket 127.0.0.1:8021
|
socket = /home/web/pet-clones.cocorico.ru/socket/clone_pets.sock
|
||||||
socket: unix:///home/web/clone.cocorico.ru/socket/clone_pets.sock
|
|
||||||
# Исходящие сообщения в лог
|
|
||||||
daemonize: /home/web/clone.cocorico.ru/logs/clone-pets-uwsgi.log
|
|
||||||
|
|
||||||
# ЗАГАДОЧНЫЕ НАСТРОЙКИ, ПО ИДЕЕ ОНИ НУЖНЫ, НО И БЕЗ НИХ ВСЁ РАБОТАЕТ
|
# ЗАГАДОЧНЫЕ НАСТРОЙКИ, ПО ИДЕЕ ОНИ НУЖНЫ, НО И БЕЗ НИХ ВСЁ РАБОТАЕТ
|
||||||
# расположение wsgi.py
|
# расположение wsgi.py
|
||||||
# wsgi-file: /home/web/clone.cocorico.ru/rosmorport_tsts/rosmorport_tsts/wsgi.py
|
wsgi-file = /home/web/pet-clones.cocorico.ru/rosmorport_tsts/rosmorport_tsts/wsgi.py
|
||||||
# расположение виртуального окружения (как оно работает если этот параметр не указан, не ясно)
|
# расположение виртуального окружения (как оно работает если этот параметр не указан, не ясно)
|
||||||
virtualenv: /home/web/clone.cocorico.ru/env
|
virtualenv = /home/web/pet-clones.cocorico.ru/env
|
||||||
# имя файла при изменении которого происходит авторестарт приложения
|
# имя файла при изменении которого происходит авторестарт приложения
|
||||||
# (когда этого параметра нет, то гичего не авторестартится, но с ним все рестартится.
|
# (когда этого параметра нет, то гичего не авторестартится, но с ним все рестартится.
|
||||||
# Cтоит изменить любой Python-исходник проекта, как изменения сразу вступают в силу.
|
# Cтоит изменить любой Python-исходник проекта, как изменения сразу вступают в силу.
|
||||||
touch-reload: /home/web/clone.cocorico.ru/logs/touchreload.txt
|
touch-reload = /home/web/pet-clones.cocorico.ru/logs/touchreload.txt
|
||||||
py-autoreload: 5
|
py-autoreload = 5
|
||||||
|
|
||||||
|
#
|
||||||
# НАСТРОЙКИ ОБЩИЕ
|
# НАСТРОЙКИ ОБЩИЕ
|
||||||
# быть master-процессом
|
# быть master-процессом
|
||||||
master: true
|
master = true
|
||||||
# максимальное количество процессов
|
# максимальное количество процессов
|
||||||
processes: 1
|
processes = 2
|
||||||
# если uWSGI устнаовлен как сервис через apt-get то нужно установить еще плугин:
|
# если uWSGI устнаовлен как сервис через apt-get то нужно установить еще плугин:
|
||||||
# sudo apt-get install uwsgi-plugin-python3
|
# sudo apt-get install uwsgi-plugin-python
|
||||||
# и добавить в этот конфиг: plugin: python3
|
# и добавить в этот конфиг: plugin = python
|
||||||
plugin: python3
|
plugin = python3
|
||||||
# права доступа к файлу сокета. По умолчанию должно хватать 664. Но каких-то прав не хватает, поэтому 666.
|
# права доступа к файлу сокета. По умолчанию должно хватать 664. Но каких-то прав не хватает, поэтому 666.
|
||||||
chmod-socket: 777
|
chmod-socket = 666
|
||||||
# очищать окружение от служебных файлов uwsgi по завершению
|
# очищать окружение от служебных файлов uwsgi по завершению
|
||||||
vacuum: true
|
vacuum = true
|
||||||
# количество секунд после которых подвисший процес будет перезапущен
|
# количество секунд после которых подвисший процес будет перезапущен
|
||||||
# Так как некоторе скрипты требуют изрядно времени (особенно полная переиндексация) то ставим значение побольще
|
# Так как некоторе скрипты требуют изрядно времени (особенно полная переиндексация) то ставим значение побольще
|
||||||
harakiri: 2600
|
harakiri = 2600
|
||||||
# В общем случае, при некотых значениях harakiri логах uWSGI может вываливаться предупреждение:
|
# В общем случае, при некотых значениях harakiri логах uWSGI может вываливаться предупреждение:
|
||||||
# WARNING: you have enabled harakiri without post buffering. Slow upload could be rejected on post-unbuffered webservers
|
# WARNING: you have enabled harakiri without post buffering. Slow upload could be rejected on post-unbuffered webservers
|
||||||
# можно оставить harakiri закоментированным, но нам нужно 900 и на него не ругается. Ругается на 30.
|
# можно оставить harakiri закоментированным, но нам нужно 900 и на него не ругается. Ругается на 30.
|
||||||
|
|
||||||
# разрешаем многопоточность
|
# разрешаем многопоточность
|
||||||
enable-threads: true
|
enable-threads = true
|
||||||
vacuum: true
|
vacuum = true
|
||||||
thunder-lock: true
|
thunder-lock = true
|
||||||
max-requests: 500
|
max-requests = 500
|
||||||
|
|
||||||
# пользователь и группа пользователей от имени которых запускать uWSGI
|
# пользователь и группа пользователей от имени которых запускать uWSGI
|
||||||
# указываем www-data: к этой группе относится nginх, и ранее мы включили в эту группу нашего [user]
|
# указываем www-data: к этой группе относится nginz, и ранее мы включили в эту группу нашего [user]
|
||||||
# uid : nginx
|
# uid = nginx
|
||||||
# gid : nginx
|
# gid = nginx
|
||||||
# uid : www-data
|
# uid = root
|
||||||
# gid : www-data
|
# gid = root
|
||||||
uid: web
|
uid = web
|
||||||
gid: web
|
gid = web
|
||||||
|
|
||||||
|
print = ---------------- Запущен uWSGI для pet-clones.cocorico.ru ---------------
|
||||||
print: ---------------- Запущен uWSGI ----------------
|
|
3
feedback.txt
Normal file
3
feedback.txt
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
Мы ознакомились с результатом выполнения тестового задания и отметили творческий подход,
|
||||||
|
однако выбранные технологии и качество программной реализации не соответствуют нашим
|
||||||
|
стандартам.
|
13
my_anwer.txt
Normal file
13
my_anwer.txt
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
Добрый день ....
|
||||||
|
|
||||||
|
Не успел сделать прокрутку в tbody ... закопался в деплоем (попался на RFLF гWSGI-конфига) :(
|
||||||
|
|
||||||
|
В целом, в задании, мне кажется, иногда путают высоту и ширину (в блоке шириной 75px даже слово
|
||||||
|
из 8 букв не уместить, тем более меню которые надо выравнивать странно). Так что делал как посчитал
|
||||||
|
разумным. Прошу извинить.
|
||||||
|
|
||||||
|
Проект: https://pet-clones.cocorico.ru/
|
||||||
|
Гит: https://git.cube2.ru/erjemin/2024-test-rosmorport
|
||||||
|
|
||||||
|
login: admin
|
||||||
|
pwd: 1234
|
49
rosmorport_tsts/rosmorport_tsts/_my_secret__sample.py
Normal file
49
rosmorport_tsts/rosmorport_tsts/_my_secret__sample.py
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# ВСЕ СЕКРЕТНЫЕ НАСТРОЙКИ ПРОЕКТА ДЛЯ РАЗВЕРТЫВАНИЯ НА ПРОДАКШЕНЕ (турция)
|
||||||
|
"""
|
||||||
|
В этот файл вынесены все секретные настройки, чтобы не светить их в settings.py
|
||||||
|
Например, при размещении в публичный репозиториях.
|
||||||
|
"""
|
||||||
|
|
||||||
|
MY_DEBUG = False
|
||||||
|
|
||||||
|
# Хосты на которых может работать приложение
|
||||||
|
MY_ALLOWED_HOSTS = [
|
||||||
|
'127.0.0.1',
|
||||||
|
'localhost',
|
||||||
|
'pet-clones.cocorico.ru', # prod
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
# Ключ Django
|
||||||
|
MY_SECRET_KEY = 'django-insecure-sample---secrets-must-be-kept-secret-SSxk75QmR6w37zu5okbthaNDCMQtPQ7kn7wYQcGPKENq'
|
||||||
|
|
||||||
|
# Настройки для сообщений об ошибках когда все упало и т.п.
|
||||||
|
MY_ADMINS = (
|
||||||
|
('S.Erjemin', 'erjemin@gmail.com'),
|
||||||
|
)
|
||||||
|
|
||||||
|
#########################################
|
||||||
|
# настройки для почтового сервера
|
||||||
|
MY_EMAIL = 'admin@you.site'
|
||||||
|
MY_EMAIL_FROM = 'admin@you.site'
|
||||||
|
MY_EMAIL_HOST = 'smtp.mail.ru' # host
|
||||||
|
MY_EMAIL_HOST_USER = 'admin@you.site' # login
|
||||||
|
MY_EMAIL_HOST_PASSWORD = 'secrets-must-be-kept-secret' # password
|
||||||
|
MY_EMAIL_PORT = 2525 # port
|
||||||
|
MY_EMAIL_USE_TLS = True
|
||||||
|
|
||||||
|
# Настройки подключения к БД MySQL
|
||||||
|
MY_DATABASE_HOST = 'localhost' # db-host
|
||||||
|
MY_DATABASE_NAME = 'db-name' # db-name
|
||||||
|
MY_DATABASE_PORT = '3306'
|
||||||
|
MY_DATABASE_USER = 'db-user'
|
||||||
|
MY_DATABASE_PASSWORD = 'secrets-must-be-kept-secret'
|
||||||
|
|
||||||
|
MY_TOUCH_RELOAD = '/home/web/you.site/logs/touchreload.txt'
|
||||||
|
|
||||||
|
MY_MEDIA_ROOT = '/home/web/you.site/public/media'
|
||||||
|
|
||||||
|
MY_STATIC_ROOT = '/home/web/you.site/public/static/'
|
||||||
|
|
||||||
|
MY_SITEMAP_ROOT = '/home/web/you.site/public'
|
@ -11,19 +11,19 @@ class TbPetsClones(models.Model):
|
|||||||
"""Модель для хранения клонов питомцев"""
|
"""Модель для хранения клонов питомцев"""
|
||||||
class PetType(models.IntegerChoices):
|
class PetType(models.IntegerChoices):
|
||||||
"""Тип питомца"""
|
"""Тип питомца"""
|
||||||
DOG = 1, "Собачка"
|
DOG = 1, "🐕 Собачка"
|
||||||
CAT = 2, "Кошечка"
|
CAT = 2, "🐈 Кошечка"
|
||||||
BIR = 3, "Птичка"
|
BIR = 3, "🦜 Птичка"
|
||||||
FIS = 6, "Рыбка"
|
ROD = 4, "🐟 Рыбка"
|
||||||
ROD = 4, "Грызун"
|
REP = 5, "🦎 Рептилия"
|
||||||
REP = 5, "Рептилия"
|
FIS = 6, "🐜 Насекомое"
|
||||||
OTH = 0, "Неизвестная зверушка"
|
OTH = 0, "👾 Неизвестная зверушка"
|
||||||
|
|
||||||
class PetSex(models.IntegerChoices):
|
class PetSex(models.IntegerChoices):
|
||||||
"""Пол питомца"""
|
"""Пол питомца"""
|
||||||
MA = 1, "Мужской"
|
MA = 1, "♂ Мужской"
|
||||||
FE = 2, "Женский"
|
FE = 2, "♀ Женский"
|
||||||
UN = 0, "Неизвестно"
|
UN = 0, "⸰ Неизвестно"
|
||||||
|
|
||||||
iPetType = models.SmallIntegerField(
|
iPetType = models.SmallIntegerField(
|
||||||
default=PetType.OTH,
|
default=PetType.OTH,
|
||||||
|
@ -23,7 +23,7 @@ if socket.gethostname() == 'erjemin-home':
|
|||||||
elif socket.gethostname() in ['m1.N1', 'm1.local', ]:
|
elif socket.gethostname() in ['m1.N1', 'm1.local', ]:
|
||||||
# домашний комп (MacOS)
|
# домашний комп (MacOS)
|
||||||
from rosmorport_tsts.my_secret_dev_home_mac import *
|
from rosmorport_tsts.my_secret_dev_home_mac import *
|
||||||
elif socket.gethostname() in ['orangepi5', 'srv05962228.ultasrv.net']:
|
else:
|
||||||
# продакшн (боевой) сервер
|
# продакшн (боевой) сервер
|
||||||
from rosmorport_tsts.my_secret_prod import *
|
from rosmorport_tsts.my_secret_prod import *
|
||||||
|
|
||||||
|
@ -24,8 +24,16 @@
|
|||||||
{% for PET in PETS %}<tr>
|
{% for PET in PETS %}<tr>
|
||||||
<td>{{ PET.szPetSerNum }}</td>
|
<td>{{ PET.szPetSerNum }}</td>
|
||||||
<td>{% if PET.szPetName %}{{ PET.szPetName }}{% else %}—{% endif %}</td>
|
<td>{% if PET.szPetName %}{{ PET.szPetName }}{% else %}—{% endif %}</td>
|
||||||
<td>{{ PET.iPetType }}</td>
|
<td>{% if PET.iPetType == 0 %}<i class="fa-solid fa-ghost"></i>{% elif PET.iPetType == 1 %}
|
||||||
<td>{{ PET.iPetSex }}</td>
|
<i class="fa-solid fa-dog"></i>{% elif PET.iPetType == 2 %}
|
||||||
|
<i class="fa-solid fa-cat"></i>{% elif PET.iPetType == 3 %}
|
||||||
|
<i class="fa-solid fa-dove"></i>{% elif PET.iPetType == 4 %}
|
||||||
|
<i class="fa-solid fa-fish"></i>{% elif PET.iPetType == 5 %}
|
||||||
|
<i class="fa-solid fa-frog"></i>{% elif PET.iPetType == 6 %}
|
||||||
|
<i class="fa-solid fa-locust"></i>{% endif %}</td>
|
||||||
|
<td>{% if PET.iPetSex == 0 %}<i class="fa-solid fa-genderless"></i>{% elif PET.iPetSex == 1 %}
|
||||||
|
<i class="fa-solid fa-mars"></i>{% elif PET.iPetSex == 2 %}
|
||||||
|
<i class="fa-solid fa-venus"></i>{% endif %}</td>
|
||||||
<td>{% if PET.bPetIsReg %}<i class="fa-solid fa-circle-check"></i>{% endif %}</td>
|
<td>{% if PET.bPetIsReg %}<i class="fa-solid fa-circle-check"></i>{% endif %}</td>
|
||||||
<td>{% if not PET.bPetIsAlive %}<i class="fa-solid fa-skull-crossbones"></i>{% endif %}</td>
|
<td>{% if not PET.bPetIsAlive %}<i class="fa-solid fa-skull-crossbones"></i>{% endif %}</td>
|
||||||
<td>{% if PET.szPetOwner %}{{ PET.szPetOwner }}{% else %}—{% endif %}</td>
|
<td>{% if PET.szPetOwner %}{{ PET.szPetOwner }}{% else %}—{% endif %}</td>
|
||||||
|
@ -39,8 +39,16 @@
|
|||||||
{% for PET in PETS %}<tr class="t{{ PET.iPetType }} s{{ PET.iPetSex }}">
|
{% for PET in PETS %}<tr class="t{{ PET.iPetType }} s{{ PET.iPetSex }}">
|
||||||
<td>{{ PET.szPetSerNum }}</td>
|
<td>{{ PET.szPetSerNum }}</td>
|
||||||
<td>{% if PET.szPetName %}{{ PET.szPetName }}{% else %}—{% endif %}</td>
|
<td>{% if PET.szPetName %}{{ PET.szPetName }}{% else %}—{% endif %}</td>
|
||||||
<td>{{ PET.iPetType }}</td>
|
<td>{% if PET.iPetType == 0 %}<i class="fa-solid fa-ghost"></i>{% elif PET.iPetType == 1 %}
|
||||||
<td>{{ PET.iPetSex }}</td>
|
<i class="fa-solid fa-dog"></i>{% elif PET.iPetType == 2 %}
|
||||||
|
<i class="fa-solid fa-cat"></i>{% elif PET.iPetType == 3 %}
|
||||||
|
<i class="fa-solid fa-dove"></i>{% elif PET.iPetType == 4 %}
|
||||||
|
<i class="fa-solid fa-fish"></i>{% elif PET.iPetType == 5 %}
|
||||||
|
<i class="fa-solid fa-frog"></i>{% elif PET.iPetType == 6 %}
|
||||||
|
<i class="fa-solid fa-locust"></i>{% endif %}</td>
|
||||||
|
<td>{% if PET.iPetSex == 0 %}<i class="fa-solid fa-genderless"></i>{% elif PET.iPetSex == 1 %}
|
||||||
|
<i class="fa-solid fa-mars"></i>{% elif PET.iPetSex == 2 %}
|
||||||
|
<i class="fa-solid fa-venus"></i>{% endif %}</td>
|
||||||
<td>{% if PET.bPetIsReg %}<i class="fa-solid fa-circle-check"></i>{% endif %}</td>
|
<td>{% if PET.bPetIsReg %}<i class="fa-solid fa-circle-check"></i>{% endif %}</td>
|
||||||
<td>{% if not PET.bPetIsAlive %}<i class="fa-solid fa-skull-crossbones"></i>{% endif %}</td>
|
<td>{% if not PET.bPetIsAlive %}<i class="fa-solid fa-skull-crossbones"></i>{% endif %}</td>
|
||||||
<td>{% if PET.szPetOwner %}{{ PET.szPetOwner }}{% else %}—{% endif %}</td>
|
<td>{% if PET.szPetOwner %}{{ PET.szPetOwner }}{% else %}—{% endif %}</td>
|
||||||
@ -82,27 +90,12 @@
|
|||||||
|
|
||||||
{% block JS_1 %}<script type="text/javascript">
|
{% block JS_1 %}<script type="text/javascript">
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
$('#type').change(function(){
|
$('#type,#sex').change(function(){
|
||||||
let t = $(this).find("option:selected").attr('value');
|
|
||||||
let s = $('#sex').find("option:selected").attr('value');
|
|
||||||
if (t === 'tA')
|
|
||||||
$('tbody > tr').show();
|
|
||||||
else {
|
|
||||||
$('tbody > tr').hide();
|
|
||||||
$('tbody > tr.' + t).show();
|
|
||||||
}
|
|
||||||
if(s !== 'sA') $('tbody > tr:not(.' + s +')').hide();
|
|
||||||
});
|
|
||||||
$('#sex').change(function(){
|
|
||||||
let s = $(this).find("option:selected").attr('value');
|
|
||||||
let t = $('#type').find("option:selected").attr('value');
|
let t = $('#type').find("option:selected").attr('value');
|
||||||
if (s === 'sA')
|
let s = $('#sex').find("option:selected").attr('value');
|
||||||
$('tbody > tr').show();
|
$('tbody > tr').show();
|
||||||
else {
|
if(t !== 'tA') $('tbody > tr:not(.'+t+')').hide();
|
||||||
$('tbody > tr').hide();
|
if(s !== 'sA') $('tbody > tr:not(.'+s+')').hide();
|
||||||
$('tbody > tr.' + s).show();
|
|
||||||
}
|
|
||||||
if(s !== 'tA') $('tbody > tr:not(.' + t + ')').hide();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>{% endblock %}
|
</script>{% endblock %}
|
@ -1,14 +1,14 @@
|
|||||||
Необходимо реализовать интерфейс веб-приложения (сайта), который состоит из 3 областей:
|
Необходимо реализовать интерфейс веб-приложения (сайта), который состоит из 3 областей:
|
||||||
- Информационная область.
|
- Информационная область.
|
||||||
Представлена в виде полосы в верхней части экрана, ширина должна быть фиксированная 75 пикс. В этой области слева располагается название веб-приложения («Тестовое задание Frontend»), размер шрифта 11pt, вертикальное выравнивание по центру, горизонтальное по левому краю. Слева кнопка «Вход», выравнивание аналогичное названию но по правому краю. При нажатии на неё появляется всплывающее окно с формой ввода логина и пароля (обязательные поля) и кнопкой «Войти». При попытке войти должен производиться запрос к серверу, на сервере происходит авторизация средствами Django (или иного фреймворка, пользователь должен существовать в БД фреймворка). В случае успешной авторизации страница приложения перезагружается, иначе появляется сообщение что авторизоваться не удалось с пояснением причины (пользователя не существует, пароль не верный, ошибка подключения, иная ошибка).
|
Представлена в виде полосы в верхней части экрана, ширина должна быть фиксированная 75 пикс. В этой области слева располагается название веб-приложения («Тестовое задание Frontend»), размер шрифта 11pt, вертикальное выравнивание по центру, горизонтальное по левому краю. Слева кнопка «Вход», выравнивание аналогичное названию но по правому краю. При нажатии на неё появляется всплывающее окно с формой ввода логина и пароля (обязательные поля) и кнопкой «Войти». При попытке войти должен производиться запрос к серверу, на сервере происходит авторизация средствами Django (или иного фреймворка, пользователь должен существовать в БД фреймворка). В случае успешной авторизации страница приложения перезагружается, иначе появляется сообщение что авторизоваться не удалось с пояснением причины (пользователя не существует, пароль не верный, ошибка подключения, иная ошибка).
|
||||||
В случае если пользователь авторизован кнопка «Войти» заменяется на «Выйти», рядом отображается имя пользователя (слева от кнопки), при её нажатии будет отправлен запрос на сервер завершающий сессию пользователя, страница должна быть перезагружена.
|
В случае если пользователь авторизован кнопка «Войти» заменяется на «Выйти», рядом отображается имя пользователя (слева от кнопки), при её нажатии будет отправлен запрос на сервер завершающий сессию пользователя, страница должна быть перезагружена.
|
||||||
- Область меню.
|
- Область меню.
|
||||||
Представлена в виде полосы шириной 75 пикс., цвет отличается от информационной области, размер шрифта 11pt. Выравнивание объектов внутри горизонтально по левому краю, вертикально по центру, внутри расположены пункты меню: «Ввод данных», «Отчёты», «Информация». При наведении курсора на пункт меню вертикально вниз выпадают соответствующие подпункты: «Ввод данных» - «Форма ввода»; «Отчёты» - «Отчёт 1», «Отчёт 2»; «Информация» - «О приложении». Если пользователь не авторизован, то в первых двух пунктах меню вместо подпунктов будет отображено «Необходима авторизация».
|
Представлена в виде полосы шириной 75 пикс., цвет отличается от информационной области, размер шрифта 11pt. Выравнивание объектов внутри горизонтально по левому краю, вертикально по центру, внутри расположены пункты меню: «Ввод данных», «Отчёты», «Информация». При наведении курсора на пункт меню вертикально вниз выпадают соответствующие подпункты: «Ввод данных» - «Форма ввода»; «Отчёты» - «Отчёт 1», «Отчёт 2»; «Информация» - «О приложении». Если пользователь не авторизован, то в первых двух пунктах меню вместо подпунктов будет отображено «Необходима авторизация».
|
||||||
- Рабочая область.
|
- Рабочая область.
|
||||||
Остальное свободное место на странице. Информационная область и область меню должны оставаться видимыми на странице даже если содержимое рабочей области больше отведённого под неё места.
|
Остальное свободное место на странице. Информационная область и область меню должны оставаться видимыми на странице даже если содержимое рабочей области больше отведённого под неё места.
|
||||||
|
|
||||||
При нажатии на подпункты меню должен отправляться запрос на сервер, а сервер возвращать содержимое (вёрстку) в зависимости от выбранного пункта, этим содержимым будет заменено содержимое рабочей области.
|
При нажатии на подпункты меню должен отправляться запрос на сервер, а сервер возвращать содержимое (вёрстку) в зависимости от выбранного пункта, этим содержимым будет заменено содержимое рабочей области.
|
||||||
При нажатии на подпункт «Форма ввода» в рабочей области должна появиться форма ввода документа на усмотрение тестируемого, но которая должна содержать как минимум 7 полей, среди них поля с «галочками» (checkbox) и выпадающие списки. Должна существовать возможность сохранить все введённые данные в базу данных. Должны присутствовать обязательные и необязательные поля, в интерфейсе их необходимо пометить соответствующим образом.
|
При нажатии на подпункт «Форма ввода» в рабочей области должна появиться форма ввода документа на усмотрение тестируемого, но которая должна содержать как минимум 7 полей, среди них поля с «галочками» (checkbox) и выпадающие списки. Должна существовать возможность сохранить все введённые данные в базу данных. Должны присутствовать обязательные и необязательные поля, в интерфейсе их необходимо пометить соответствующим образом.
|
||||||
При нажатии на подпункт «Отчёт 1» необходимо вывести таблицу, в которой будет представлены все внесённые в базу записи через интерфейс «Форма ввода». У таблицы должна присутствовать «шапка», которая должна отображаться всегда вне зависимости от объёма данных в отчёте (оставаться на виду при прокрутке отчёта вниз). Под таблицей необходимо предусмотреть строку справочной информации, в которой будет отображено количество записей в отчёте и время выполнения запроса к базе данных и обработки данных (не от клиента к серверу и обратно).
|
При нажатии на подпункт «Отчёт 1» необходимо вывести таблицу, в которой будет представлены все внесённые в базу записи через интерфейс «Форма ввода». У таблицы должна присутствовать «шапка», которая должна отображаться всегда вне зависимости от объёма данных в отчёте (оставаться на виду при прокрутке отчёта вниз). Под таблицей необходимо предусмотреть строку справочной информации, в которой будет отображено количество записей в отчёте и время выполнения запроса к базе данных и обработки данных (не от клиента к серверу и обратно).
|
||||||
При нажатии на подпункт «Отчёт 2» будет отображён аналогичный «Отчёту 1» отчёт, но с возможностью фильтрации по полям (1+) на выбор тестируемого. Техническая реализация фильтра – на усмотрение тестируемого (обработка на клиенте, запрос к серверу с параметрами, или иное).
|
При нажатии на подпункт «Отчёт 2» будет отображён аналогичный «Отчёту 1» отчёт, но с возможностью фильтрации по полям (1+) на выбор тестируемого. Техническая реализация фильтра – на усмотрение тестируемого (обработка на клиенте, запрос к серверу с параметрами, или иное).
|
||||||
При нажатии на подпункт «О приложении» будет отображено всплывающее окно с содержимым на выбор тестируемого.
|
При нажатии на подпункт «О приложении» будет отображено всплывающее окно с содержимым на выбор тестируемого.
|
Loading…
Reference in New Issue
Block a user