diff --git a/Makefile b/Makefile index 5d65f08..94b235e 100644 --- a/Makefile +++ b/Makefile @@ -46,7 +46,7 @@ migrate: # Создание новых миграций на основе сформированных моделей. makemigrations: - cd $(PROJECT_DIR) && $(DJANGO_RUN) makemigrations --no-input + cd $(PROJECT_DIR) && $(DJANGO_RUN) makemigrations # Создание супер-юзера. diff --git a/poetry.lock b/poetry.lock index 0aa9d0f..694de7f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -400,6 +400,20 @@ files = [ asgiref = ">=3,<4" Django = ">=4.2,<5.0.0 || >5.0.0,<5.0.1 || >5.0.1,<5.0.2 || >5.0.2,<6" +[[package]] +name = "django-bootstrap5" +version = "24.2" +description = "Bootstrap 5 for Django" +optional = false +python-versions = ">=3.8" +files = [ + {file = "django_bootstrap5-24.2-py3-none-any.whl", hash = "sha256:6a5d83e9ff1952f7c07c54cebcb76c85f09787b8b57eeb4ec07554cd583acc64"}, + {file = "django_bootstrap5-24.2.tar.gz", hash = "sha256:a3cee2b3d45745210c5b898af2917f310f44df746269fe09a93be28a0adc2a4b"}, +] + +[package.dependencies] +Django = ">=4.2" + [[package]] name = "django-environ" version = "0.11.2" @@ -542,13 +556,13 @@ doc = ["Sphinx", "sphinx-rtd-theme", "sphinxcontrib-spelling"] [[package]] name = "faker" -version = "25.1.0" +version = "25.2.0" description = "Faker is a Python package that generates fake data for you." optional = false python-versions = ">=3.8" files = [ - {file = "Faker-25.1.0-py3-none-any.whl", hash = "sha256:24e28dce0b89683bb9e017e042b971c8c4909cff551b6d46f1e207674c7c2526"}, - {file = "Faker-25.1.0.tar.gz", hash = "sha256:2107618cf306bb188dcfea3e5cfd94aa92d65c7293a2437c1e96a99c83274755"}, + {file = "Faker-25.2.0-py3-none-any.whl", hash = "sha256:cfe97c4857c4c36ee32ea4aaabef884895992e209bae4cbd26807cf3e05c6918"}, + {file = "Faker-25.2.0.tar.gz", hash = "sha256:45b84f47ff1ef86e3d1a8d11583ca871ecf6730fad0660edadc02576583a2423"}, ] [package.dependencies] @@ -873,13 +887,13 @@ testing = ["pytest", "pytest-cov", "wheel"] [[package]] name = "platformdirs" -version = "4.2.1" +version = "4.2.2" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false python-versions = ">=3.8" files = [ - {file = "platformdirs-4.2.1-py3-none-any.whl", hash = "sha256:17d5a1161b3fd67b390023cb2d3b026bbd40abde6fdb052dfbd3a29c3ba22ee1"}, - {file = "platformdirs-4.2.1.tar.gz", hash = "sha256:031cd18d4ec63ec53e82dceaac0417d218a6863f7745dfcc9efe7793b7039bdf"}, + {file = "platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee"}, + {file = "platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"}, ] [package.extras] @@ -1392,13 +1406,13 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "virtualenv" -version = "20.26.1" +version = "20.26.2" description = "Virtual Python Environment builder" optional = false python-versions = ">=3.7" files = [ - {file = "virtualenv-20.26.1-py3-none-any.whl", hash = "sha256:7aa9982a728ae5892558bff6a2839c00b9ed145523ece2274fad6f414690ae75"}, - {file = "virtualenv-20.26.1.tar.gz", hash = "sha256:604bfdceaeece392802e6ae48e69cec49168b9c5f4a44e483963f9242eb0e78b"}, + {file = "virtualenv-20.26.2-py3-none-any.whl", hash = "sha256:a624db5e94f01ad993d476b9ee5346fdf7b9de43ccaee0e0197012dc838a0e9b"}, + {file = "virtualenv-20.26.2.tar.gz", hash = "sha256:82bf0f4eebbb78d36ddaee0283d43fe5736b53880b8a8cdcd37390a07ac3741c"}, ] [package.dependencies] @@ -1486,4 +1500,4 @@ test = ["pytest"] [metadata] lock-version = "2.0" python-versions = "^3.12" -content-hash = "2680eb177cd6ce57f552dfa33c027a3ea08165a26a09bc3378090173ff590354" +content-hash = "04f7f70f9a8c3a14b80f17bce92698b96331b5b3262b73cebd90bc9618616d62" diff --git a/pyproject.toml b/pyproject.toml index e841a24..36b0953 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,6 +14,7 @@ poetry-plugin-export = "^1.7.1" django-environ= "^0.11.2" django-asgi-lifespan = "^0.3.1" django-phonenumber-field = {extras = ["phonenumbers"], version = "^7.3.0"} +django-bootstrap5 = "^24.2" [tool.poetry.group.dev.dependencies] diff --git a/src/admin_user/migrations/0001_initial.py b/src/admin_user/migrations/0001_initial.py index 36b14c1..8a86036 100644 --- a/src/admin_user/migrations/0001_initial.py +++ b/src/admin_user/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.0.4 on 2024-05-11 21:07 +# Generated by Django 5.0.6 on 2024-05-13 09:47 import django.utils.timezone import phonenumber_field.modelfields diff --git a/src/bot/migrations/__init__.py b/src/bot/migrations/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/core/config/settings_base.py b/src/core/config/settings_base.py index 1cf6dbc..4e313bf 100644 --- a/src/core/config/settings_base.py +++ b/src/core/config/settings_base.py @@ -28,6 +28,7 @@ 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', + 'django_bootstrap5', ] LOCAL_APPS = [ @@ -53,6 +54,7 @@ ROOT_URLCONF = 'core.urls' + TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', diff --git a/src/core/urls.py b/src/core/urls.py index 87b1569..a2c1051 100644 --- a/src/core/urls.py +++ b/src/core/urls.py @@ -1,10 +1,15 @@ from django.contrib import admin -from django.urls import path +from django.urls import path, include + from core.views import send_greeting_email urlpatterns = [ path('admin/', admin.site.urls), + path('registration/', + include('potential_user.urls'), + name='registration', + ), # TODO: убрать после реализации функционала path('mail/', send_greeting_email, name='send-email'), ] diff --git a/src/potential_user/forms.py b/src/potential_user/forms.py new file mode 100644 index 0000000..2a66621 --- /dev/null +++ b/src/potential_user/forms.py @@ -0,0 +1,13 @@ +from django import forms + +from potential_user.models import ApplicationForm + + +class RegistrationForm(forms.ModelForm): + """Form to register a new user.""" + + class Meta: + """Form meta class.""" + + model = ApplicationForm + fields = {'name', 'surname', 'phone_number', 'city', } diff --git a/src/potential_user/migrations/0001_initial.py b/src/potential_user/migrations/0001_initial.py index 2c2be3f..334b6c6 100644 --- a/src/potential_user/migrations/0001_initial.py +++ b/src/potential_user/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.0.4 on 2024-05-10 18:48 +# Generated by Django 5.0.6 on 2024-05-16 08:59 import phonenumber_field.modelfields from django.db import migrations, models @@ -16,12 +16,12 @@ class Migration(migrations.Migration): name='ApplicationForm', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('telegram_id', models.IntegerField(unique=True, verbose_name='Telegram ID')), - ('role', models.CharField(choices=[('teacher', 'Преподаватель'), ('student', 'Учащийся')], max_length=20)), - ('name', models.CharField(max_length=20)), - ('surname', models.CharField(max_length=20)), - ('city', models.CharField(max_length=20)), - ('phone_number', phonenumber_field.modelfields.PhoneNumberField(max_length=128, region=None)), + ('telegram_id', models.PositiveBigIntegerField(help_text='Введите свой ID', unique=True, verbose_name='Telegram ID')), + ('role', models.CharField(choices=[('teacher', 'Преподаватель'), ('student', 'Учащийся')], max_length=20, verbose_name='Роль')), + ('name', models.CharField(help_text='Обязательное поле', max_length=20, verbose_name='Имя')), + ('surname', models.CharField(help_text='Обязательное поле', max_length=20, verbose_name='Фамилия')), + ('city', models.CharField(max_length=20, verbose_name='Город')), + ('phone_number', phonenumber_field.modelfields.PhoneNumberField(help_text='Формат +7XXXXXXXXXX', max_length=128, region=None, verbose_name='Номер телефона')), ('approved', models.BooleanField(default=False)), ], options={ diff --git a/src/potential_user/models.py b/src/potential_user/models.py index 3348b7d..80398c0 100644 --- a/src/potential_user/models.py +++ b/src/potential_user/models.py @@ -9,13 +9,34 @@ class ApplicationForm(models.Model): ('teacher', 'Преподаватель'), ('student', 'Учащийся'), ) - - telegram_id = models.IntegerField('Telegram ID', unique=True) - role = models.CharField(choices=ROLE_CHOICES, max_length=20) - name = models.CharField(max_length=20) - surname = models.CharField(max_length=20) - city = models.CharField(max_length=20) - phone_number = PhoneNumberField() + telegram_id = models.PositiveBigIntegerField( + 'Telegram ID', + unique=True, + help_text='Введите свой ID', + ) + role = models.CharField( + 'Роль', + choices=ROLE_CHOICES, + max_length=20, + ) + name = models.CharField( + 'Имя', + max_length=20, + help_text='Обязательное поле', + ) + surname = models.CharField( + 'Фамилия', + max_length=20, + help_text='Обязательное поле', + ) + city = models.CharField( + 'Город', + max_length=20, + ) + phone_number = PhoneNumberField( + 'Номер телефона', + help_text='Формат +7XXXXXXXXXX', + ) approved = models.BooleanField(default=False) class Meta: diff --git a/src/potential_user/urls.py b/src/potential_user/urls.py new file mode 100644 index 0000000..1eae64e --- /dev/null +++ b/src/potential_user/urls.py @@ -0,0 +1,11 @@ +from django.urls import path + +from potential_user.views import RegistrationCreateView + +app_name = 'registration' + +urlpatterns = [ + path('', + RegistrationCreateView.as_view(), + name='registration'), +] diff --git a/src/potential_user/utils.py b/src/potential_user/utils.py new file mode 100644 index 0000000..c079825 --- /dev/null +++ b/src/potential_user/utils.py @@ -0,0 +1,20 @@ +import random +import sys + +from potential_user.models import ApplicationForm + +#TODO Убрать после реализации хендлеров +def get_telegram_id() -> int: + """ + Получает телеграм id от бота. + + Сейчас исполняет роль заглушки. + """ + while True: + telegram_id = random.randint(0, sys.maxsize) + tg_id_in_db = ApplicationForm.objects.filter( + telegram_id=telegram_id, + ).exists() + if tg_id_in_db: + continue + return telegram_id diff --git a/src/potential_user/views.py b/src/potential_user/views.py new file mode 100644 index 0000000..c5b2b89 --- /dev/null +++ b/src/potential_user/views.py @@ -0,0 +1,24 @@ +from django.urls import reverse_lazy +from django.views.generic import CreateView + +from potential_user.forms import RegistrationForm +from potential_user.models import ApplicationForm +from potential_user.utils import get_telegram_id + + +class RegistrationCreateView(CreateView): + """Создает форму регистрации нового пользователя.""" + + model = ApplicationForm + form_class = RegistrationForm + template_name = 'registration/registration_form.html' + + # TODO убрать после реализации получения telegram_id + def form_valid(self, form): + """Присваивает telegram_id.""" + form.instance.telegram_id = get_telegram_id() + return super().form_valid(form) + + def get_success_url(self): + """Переадресовывет на главную страницу.""" + return reverse_lazy('registration:registration') diff --git a/src/schooling/migrations/__init__.py b/src/schooling/migrations/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/templates/registration/base.html b/src/templates/registration/base.html new file mode 100644 index 0000000..bda4354 --- /dev/null +++ b/src/templates/registration/base.html @@ -0,0 +1,15 @@ + + + + + Телеграм-бот для преподавателей и учеников + {% load django_bootstrap5 %} + {% bootstrap_css %} + + + {% include "registration/header.html" %} +
+ {% block content %}{% endblock %} +
+ + \ No newline at end of file diff --git a/src/templates/registration/footer.html b/src/templates/registration/footer.html new file mode 100644 index 0000000..be2b40f --- /dev/null +++ b/src/templates/registration/footer.html @@ -0,0 +1,4 @@ +{% load static %} + diff --git a/src/templates/registration/header.html b/src/templates/registration/header.html new file mode 100644 index 0000000..b5f60cc --- /dev/null +++ b/src/templates/registration/header.html @@ -0,0 +1,4 @@ +{% load static %} +
+

Телеграм-бот
для преподавателей и учеников

+
\ No newline at end of file diff --git a/src/templates/registration/registration_form.html b/src/templates/registration/registration_form.html new file mode 100644 index 0000000..ebe9823 --- /dev/null +++ b/src/templates/registration/registration_form.html @@ -0,0 +1,16 @@ +{% extends "registration/base.html" %} +{% load django_bootstrap5 %} +{% block content %} +
+
+ Регистрация пользователя +
+
+
+ {% csrf_token %} + {% bootstrap_form form %} + {% bootstrap_button button_type="submit" content="Регистрация" %} +
+
+
+{% endblock %}