Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .python-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
django_project
dz_django
Empty file added authapp/__init__.py
Empty file.
7 changes: 7 additions & 0 deletions authapp/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from django.contrib import admin
from authapp import models

@admin.register(models.CustomUser)
class CustomUserAdmin(admin.ModelAdmin):
list_display = ["id", "username", "email", "is_active", "date_joined"]
ordering = ["-date_joined"]
6 changes: 6 additions & 0 deletions authapp/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.apps import AppConfig


class AuthappConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'authapp'
56 changes: 56 additions & 0 deletions authapp/forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import os
from django import forms
from django.contrib.auth import get_user_model
from django.contrib.auth.forms import UserCreationForm, UsernameField
from django.core.exceptions import ValidationError
from django.utils.translation import gettext_lazy as _

class CustomUserCreationForm(UserCreationForm):
field_order = [
"username",
"password1",
"password2",
"email",
"first_name",
"last_name",
"age",
"avatar",
]

class Meta:
model = get_user_model()
fields = (
"username",
"email",
"first_name",
"last_name",
"age",
"avatar",
)
field_classes = {"username": UsernameField}

class CustomUserChangeForm(forms.ModelForm):
class Meta:
model = get_user_model()
fields = (
"username",
"email",
"first_name",
"last_name",
"age",
"avatar",
)
field_classes = {"username": UsernameField}

def clean_avatar(self):
arg_as_str = "avatar"
if arg_as_str in self.changed_data and self.instance.avatar:
if os.path.exists(self.instance.avatar.path):
os.remove(self.instance.avatar.path)
return self.cleaned_data.get(arg_as_str)

def clean_age(self):
data = self.cleaned_data.get("age")
if data < 10 or data > 100:
raise ValidationError(_("Please, enter a valid age!"))
return data
44 changes: 44 additions & 0 deletions authapp/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Generated by Django 4.0.4 on 2022-06-02 13:27

import authapp.models
import django.contrib.auth.models
import django.contrib.auth.validators
from django.db import migrations, models


class Migration(migrations.Migration):

initial = True

dependencies = [
('auth', '0012_alter_user_first_name_max_length'),
]

operations = [
migrations.CreateModel(
name='CustomUser',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('password', models.CharField(max_length=128, verbose_name='password')),
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.ASCIIUsernameValidator()], verbose_name='username')),
('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')),
('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),
('age', models.PositiveIntegerField(blank=True, null=True)),
('avatar', models.ImageField(blank=True, null=True, upload_to=authapp.models.users_avatars_path)),
('email', models.CharField(error_messages={'unique': 'A user with that email address already exists.'}, max_length=256, unique=True, verbose_name='email address')),
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
('date_joined', models.DateTimeField(auto_now_add=True, verbose_name='date joined')),
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')),
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')),
],
options={
'abstract': False,
},
managers=[
('objects', django.contrib.auth.models.UserManager()),
],
),
]
Empty file added authapp/migrations/__init__.py
Empty file.
79 changes: 79 additions & 0 deletions authapp/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
from pathlib import Path
from time import time
from django.contrib.auth.base_user import AbstractBaseUser
from django.contrib.auth.models import PermissionsMixin, UserManager
from django.contrib.auth.validators import ASCIIUsernameValidator
from django.core.mail import send_mail
from django.db import models
from django.utils.translation import gettext_lazy as _

def users_avatars_path(instance, filename):
num = int(time() * 1000)
suff = Path(filename).suffix
return "user_{0}/avatars/{1}".format(instance.username, f"pic_{num}{suff}")

class CustomUser(AbstractBaseUser, PermissionsMixin):
username_validator = ASCIIUsernameValidator()
username = models.CharField(
_("username"),
max_length=150,
unique=True,
help_text=_(
"Required. 150 characters or fewer. Letters, digits and @/./+/-/_only."),
validators=[username_validator],
error_messages={
"unique": _("A user with that username already exists."),
},
)
first_name = models.CharField(_("first name"), max_length=150, blank=True)
last_name = models.CharField(_("last name"), max_length=150, blank=True)
age = models.PositiveIntegerField(blank=True, null=True)
avatar = models.ImageField(
upload_to=users_avatars_path, blank=True, null=True
)
email = models.CharField(
_("email address"),
max_length=256,
unique=True,
error_messages={
"unique": _("A user with that email address already exists."),
},
)
is_staff = models.BooleanField(
_("staff status"),
default=False,
help_text=_(
"Designates whether the user can log into this admin site."
),
)
is_active = models.BooleanField(
_("active"),
default=True,
help_text=_(
"Designates whether this user should be treated as active. \
Unselect this instead of deleting accounts."
),
)
date_joined = models.DateTimeField(_("date joined"), auto_now_add=True)
objects = UserManager()
EMAIL_FIELD = "email"
USERNAME_FIELD = "username"
REQUIRED_FIELDS = ["email"]

class Meta:
verbose_name = _("user")
verbose_name_plural = _("users")

def clean(self):
super().clean()
self.email = self.__class__.objects.normalize_email(self.email)

def get_full_name(self):
full_name = "%s %s" % (self.first_name, self.last_name)
return full_name.strip()

def get_short_name(self):
return self.first_name

def email_user(self, subject, message, from_email=None, **kwargs):
send_mail(subject, message, from_email, [self.email], **kwargs)
33 changes: 33 additions & 0 deletions authapp/templates/admin/authapp/customers_form.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<div class="row justify-content-center my-2">
<div class="col-lg-6">
{% if user.is_anonymous %}
<h3>Регистрация нового пользователя</h3>
{% else %}
<h3>Редактировать профиль</h3>
<div class="row justify-content-center">
<div class="col-sm-7 col-md-5 col-lg-4">
{% if user.avatar %}
<img src="{{ user.avatar.url }}" alt="" width="100%">
{% else %}
<img src="{{ MEDIA_URL }}avatar_default.svg" alt="" width="100%">
{% endif %}
</div>
</div>
{% endif %}
<form method="post" class="mt-2" enctype="multipart/form-data">
{% csrf_token %}
{{ form|crispy }}
<button type="submit" class="btn btn-primary btn-block">
{% if user.is_anonymous %}
Зарегистрироваться
{% else %}
Сохранить
{% endif %}
</button>
</form>
</div>
</div>
{% endblock content %}
12 changes: 12 additions & 0 deletions authapp/templates/admin/base_site.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{% extends "includes/base.html" %}
{% load static %}
{% block title %}{% if subtitle %}{{ subtitle }} | {% endif %}{{ title }} | {{
site_title|default:_('Django site admin') }}{% endblock %}
{% block branding %}
<h1 id="site-name">
<a href="{% url 'admin:index' %}">
<img src="{% static 'img/logo.png' %}" alt="">
</a>
</h1>
{% endblock %}
{% block nav-global %}{% endblock %}
33 changes: 33 additions & 0 deletions authapp/templates/authapp/customuser_form.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{% extends 'includes/base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<div class="row justify-content-center my-2">
<div class="col-lg-6">
{% if user.is_anonymous %}
<h3>Регистрация нового пользователя</h3>
{% else %}
<h3>Редактировать профиль</h3>
<div class="row justify-content-center">
<div class="col-sm-7 col-md-5 col-lg-4">
{% if user.avatar %}
<img src="{{ user.avatar.url }}" alt="" width="100%">
{% else %}
<img src="{{ MEDIA_URL }}avatar_default.svg" alt="" width="100%">
{% endif %}
</div>
</div>
{% endif %}
<form method="post" class="mt-2" enctype="multipart/form-data">
{% csrf_token %}
{{ form|crispy }}
<button type="submit" class="btn btn-primary btn-block">
{% if user.is_anonymous %}
Зарегистрироваться
{% else %}
Сохранить
{% endif %}
</button>
</form>
</div>
</div>
{% endblock content %}
34 changes: 34 additions & 0 deletions authapp/templates/includes/messages.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<div class="position-absolute w-100" style="z-index: 1;">
<div aria-live="polite" aria-atomic="true" class="m-2">
<!-- Position it -->
<div class="d-flex align-items-end flex-column">
{% for message in messages %}
<!-- Then put toasts within -->
<div class="toast flex-fill w-100
{% if message.level == 30 %}
border-warning
{% endif %}
" role="alert" aria-live="assertive" aria-atomic="true" style="right: 0;">
<div class="toast-header">
<span class="mr-2"><i class="far fa-envelope"></i></span>
<strong class="mr-auto {% if message.level == 30 %}text-warning{% endif %}">
{{ message.tags|capfirst }} message</strong>
<small class="text-muted">just now</small>
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="toast-body">
{{ message }}
</div>
</div>
{% if message.level > 20 %}
<!-- If message will dissapere you will find message in console -->
<script>
console.log("{{ message }}");
</script>
{% endif %}
{% endfor %}
</div>
</div>
</div>
Loading