Djoser opé, API et envoie de mail lors d'une nouvelle inscription via l'api OK

This commit is contained in:
Jonas Legion 2021-06-23 15:28:35 +02:00
parent 58e1500991
commit 52b413b3a6
30 changed files with 817 additions and 308 deletions

View File

@ -1,7 +1,16 @@
from django.contrib import admin from django.contrib import admin
from django.contrib.auth.models import Group
from django.contrib.admin import AdminSite from django.contrib.admin import AdminSite
from django.contrib.auth.admin import UserAdmin, GroupAdmin
from Customers.models import Client, Domain from Customers.models import Client, Domain
# Register your models here. from AuthBillet.models import TibilletUser, HumanUser, TermUser, SuperHumanUser
from django.utils.translation import gettext, gettext_lazy as _
# from boutique.models import Category, Product, Tag, VAT, Event, LandingPageContent, Billet
# from solo.admin import SingletonModelAdmin
class PublicAdminSite(AdminSite): class PublicAdminSite(AdminSite):
site_header = "TiBillet Public Admin" site_header = "TiBillet Public Admin"
@ -15,9 +24,99 @@ class PublicAdminSite(AdminSite):
public_admin_site = PublicAdminSite(name='public_admin') public_admin_site = PublicAdminSite(name='public_admin')
# USER
# -------------------------------------/
class UserAdminTibillet(UserAdmin):
list_display = (
'email',
'is_active',
'is_staff',
'is_superuser',
'client_source',
'achat',
'administre',
'espece',
)
list_filter = (
'email',
'is_active',
'client_source',
'espece',
)
fieldsets = (
(None, {'fields': ('username', 'password')}),
(_('Personal info'), {
'fields': (
'first_name',
'last_name',
'email',
'client_source',
'client_admin',
'client_achat',
'offre',
)}),
(_('Permissions'), {
'fields': (
'is_active',
'is_staff',
'is_superuser',
'groups',
'user_permissions',
),
}),
(_('Important dates'), {'fields': ('last_login', 'date_joined')}),
)
#
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': (
'email',
'password1',
'password2',
'is_active',
'client_source',
'client_achat',
'espece',
)}
),
)
search_fields = ('email',)
ordering = ('email',)
# def save_model(self, request, obj, form, change):
# obj.client_source = request.tenant
# obj.save()
#
# staff_group = Group.objects.get_or_create(name="staff")[0]
# obj.groups.add(staff_group)
# obj.client_achat.add(request.tenant)
#
# super(UserAdminTibillet, self).save_model(request, obj, form, change)
public_admin_site.register(TibilletUser, UserAdminTibillet)
class CustomGroupAdmin(GroupAdmin):
pass
public_admin_site.register(Group, CustomGroupAdmin)
# -------------------------------------/
# USER
# -------------------------------------/
class DomainInline(admin.TabularInline): class DomainInline(admin.TabularInline):
model = Domain model = Domain
class ClientAdmin(admin.ModelAdmin): class ClientAdmin(admin.ModelAdmin):
inlines = [DomainInline] inlines = [DomainInline]
list_display = ( list_display = (

View File

@ -1,8 +1,13 @@
from django.contrib import admin from django.contrib import admin
from django.contrib.admin import AdminSite from django.contrib.admin import AdminSite
from django.contrib.auth.models import Group
from solo.admin import SingletonModelAdmin from solo.admin import SingletonModelAdmin
from AuthBillet.models import HumanUser, SuperHumanUser, TermUser
from BaseBillet.models import Configuration, Event, OptionGenerale from BaseBillet.models import Configuration, Event, OptionGenerale
from django.contrib.auth.admin import UserAdmin
from Customers.models import Client
class StaffAdminSite(AdminSite): class StaffAdminSite(AdminSite):
@ -11,12 +16,86 @@ class StaffAdminSite(AdminSite):
site_url = '/' site_url = '/'
def has_permission(self, request): def has_permission(self, request):
return request.user.is_superuser """
Removed check for is_staff.
"""
try:
if request.tenant in request.user.client_admin.all():
return request.user.is_staff
elif request.user.client_source == Client.objects.get(schema_name="public"):
return request.user.is_superuser
else:
return False
except AttributeError:
# AttributeError: 'AnonymousUser' object has no attribute 'client_source'
return False
except Exception as e:
raise e
staff_admin_site = StaffAdminSite(name='staff_admin') staff_admin_site = StaffAdminSite(name='staff_admin')
# USER
# -------------------------------------/
class UserAdminTibillet(UserAdmin):
# list_display = ('email', 'client_source', 'achat')
list_display = ('email', 'is_active')
list_filter = ('email', 'is_active',)
fieldsets = (
(None, {'fields': ('email', 'password')}),
# ('Permissions', {'fields': ('is_staff', 'is_active')}),
)
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('email', 'password1', 'password2', 'is_active')}
),
)
search_fields = ('email',)
ordering = ('email',)
def save_model(self, request, obj, form, change):
if not obj.client_source:
obj.client_source = request.tenant
obj.username = obj.email
obj.save()
obj.client_achat.add(request.tenant)
class HumanUserAdmin(UserAdminTibillet):
pass
staff_admin_site.register(HumanUser, HumanUserAdmin)
class SuperHumanUserAdmin(UserAdminTibillet):
def save_model(self, request, obj, form, change):
super(SuperHumanUserAdmin, self).save_model(request, obj, form, change)
staff_group = Group.objects.get_or_create(name="staff")[0]
obj.groups.add(staff_group)
obj.client_achat.add(request.tenant)
obj.client_admin.add(request.tenant)
# execution du save de la classe orginale user admin ( heritage de l'hérité )
super(UserAdminTibillet, self).save_model(request, obj, form, change)
staff_admin_site.register(SuperHumanUser, SuperHumanUserAdmin)
class TermUserAdmin(UserAdminTibillet):
pass
staff_admin_site.register(TermUser, TermUserAdmin)
######################################################################## ########################################################################

View File

@ -0,0 +1,90 @@
from django.contrib.auth.tokens import default_token_generator
from rest_framework import serializers
from templated_mail.mail import BaseEmailMessage
from djoser import utils
from djoser.conf import settings
from BaseBillet.models import Configuration
class ActivationEmail(BaseEmailMessage):
template_name = "email/activation.html"
def get_context_data(self):
# ActivationEmail can be deleted
print("activation !")
context = super().get_context_data()
# print(f"context : {context}")
# import ipdb; ipdb.set_trace()
user = context.get("user")
context["site_name"] = self.request.tenant.name
context["domain"] = self.request.tenant.domain_url
context["uid"] = utils.encode_uid(user.pk)
context["token"] = default_token_generator.make_token(user)
context["url"] = settings.ACTIVATION_URL.format(**context)
print(f"context : {context}")
return context
def send(self, to, *args, **kwargs):
configuration = Configuration.get_solo()
if not configuration.email :
return serializers.ValidationError(_(f"Manque l'email de la structure. Merci de configurer votre instance."))
self.render()
self.to = to
self.cc = kwargs.pop('cc', [])
self.bcc = kwargs.pop('bcc', [])
self.reply_to = kwargs.pop('reply_to', [])
self.from_email = kwargs.pop(
'from_email', configuration.email
)
# import ipdb; ipdb.set_trace()
mail_send = super(BaseEmailMessage, self).send(*args, **kwargs)
print(f'mail_send to {self.to} from {self.from_email} : {mail_send}')
class ConfirmationEmail(BaseEmailMessage):
template_name = "email/confirmation.html"
class PasswordResetEmail(BaseEmailMessage):
template_name = "email/password_reset.html"
def get_context_data(self):
# PasswordResetEmail can be deleted
context = super().get_context_data()
user = context.get("user")
context["site_name"] = self.request.tenant.name
context["domain"] = self.request.tenant.domain_url
context["uid"] = utils.encode_uid(user.pk)
context["token"] = default_token_generator.make_token(user)
context["url"] = settings.PASSWORD_RESET_CONFIRM_URL.format(**context)
return context
class PasswordChangedConfirmationEmail(BaseEmailMessage):
template_name = "email/password_changed_confirmation.html"
class UsernameChangedConfirmationEmail(BaseEmailMessage):
template_name = "email/username_changed_confirmation.html"
class UsernameResetEmail(BaseEmailMessage):
template_name = "email/username_reset.html"
def get_context_data(self):
context = super().get_context_data()
user = context.get("user")
context["site_name"] = self.request.tenant.name
context["domain"] = self.request.tenant.domain_url
context["uid"] = utils.encode_uid(user.pk)
context["token"] = default_token_generator.make_token(user)
context["url"] = settings.USERNAME_RESET_CONFIRM_URL.format(**context)
return context

View File

@ -0,0 +1,83 @@
# Generated by Django 2.2 on 2021-06-23 09:09
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):
initial = True
dependencies = [
('auth', '0011_update_proxy_permissions'),
('Customers', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='TibilletUser',
fields=[
('id', models.AutoField(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')),
('first_name', models.CharField(blank=True, max_length=30, verbose_name='first name')),
('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),
('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(default=django.utils.timezone.now, verbose_name='date joined')),
('email', models.EmailField(max_length=254, unique=True, verbose_name='email')),
('username', models.CharField(blank=True, max_length=200, null=True)),
('espece', models.CharField(choices=[('TE', 'Terminal'), ('AN', 'Android'), ('HU', 'Humain')], default='HU', max_length=2)),
('offre', models.CharField(choices=[('PU', 'Public'), ('FR', 'Gratuit'), ('PR', 'Premium'), ('EN', 'Entreprise'), ('CU', 'Custom')], default='PU', max_length=2)),
('client_achat', models.ManyToManyField(blank=True, related_name='user_achats', to='Customers.Client')),
('client_admin', models.ManyToManyField(blank=True, related_name='user_admin', to='Customers.Client')),
('client_source', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='user_principal', to='Customers.Client', verbose_name='Inscription depuis')),
('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={
'verbose_name': 'user',
'verbose_name_plural': 'users',
'abstract': False,
},
),
migrations.CreateModel(
name='HumanUser',
fields=[
],
options={
'verbose_name': 'Utilisateur',
'proxy': True,
'indexes': [],
'constraints': [],
},
bases=('AuthBillet.tibilletuser',),
),
migrations.CreateModel(
name='SuperHumanUser',
fields=[
],
options={
'verbose_name': 'Administrateur',
'proxy': True,
'indexes': [],
'constraints': [],
},
bases=('AuthBillet.tibilletuser',),
),
migrations.CreateModel(
name='TermUser',
fields=[
],
options={
'verbose_name': 'Terminal',
'verbose_name_plural': 'Terminaux',
'proxy': True,
'indexes': [],
'constraints': [],
},
bases=('AuthBillet.tibilletuser',),
),
]

View File

@ -1,3 +1,222 @@
from django.contrib.auth.base_user import BaseUserManager, AbstractBaseUser
from django.db import models from django.db import models
from django.utils.translation import ugettext_lazy as _
import uuid
from django.contrib.auth.models import AbstractUser, Group, Permission
from Customers.models import Client
from django.db import connection
# Create your models here.
class TibilletManager(BaseUserManager):
def _create_user(self, email, password, **extra_fields):
# import ipdb; ipdb.set_trace()
if not email:
raise ValueError(_("email obligatoire"))
email = self.normalize_email(email)
user = self.model(username=email, email=email, **extra_fields)
user.set_password(password)
user.client_source = connection.tenant
user.save()
user.client_achat.add(connection.tenant)
return user
def create_user(self, email, password, **extra_fields):
extra_fields.setdefault('is_staff', False)
extra_fields.setdefault('is_superuser', False)
return self._create_user(email, password, **extra_fields)
def create_staffuser(self, email, password, **extra_fields):
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_superuser', False)
return self.set_permission_staff(self._create_user(email, password, **extra_fields))
def create_superuser(self, email, password, **extra_fields):
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_superuser', True)
return self._create_user(email, password, **extra_fields)
def set_permission_staff(self, user):
staff_group = Group.objects.get_or_create(name="staff")[0]
user.groups.add(staff_group)
class TibilletUser(AbstractUser):
#TODO regarder du coté du dashboard de jet, ça plante avec uuid !
# uuid_user = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False, unique=True, db_index=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = [] # removes email from REQUIRED_FIELDS
email = models.EmailField(_('email'), unique=True) # changes email to unique and blank to false
username = models.CharField(max_length=200, null=True, blank=True)
TYPE_TERM, TYPE_HUM, TYPE_ANDR = 'TE', 'HU', 'AN'
ESPECE_CHOICES = (
(TYPE_TERM, 'Terminal'),
(TYPE_ANDR, 'Android'),
(TYPE_HUM, 'Humain'),
)
espece = models.CharField(max_length=2,
choices=ESPECE_CHOICES,
default=TYPE_HUM)
PUBLIC, FREE, PREMIUM, ENTREPRISE, CUSTOM = 'PU', 'FR', 'PR', 'EN', 'CU'
OFFRE_CHOICES = (
(PUBLIC, 'Public'),
(FREE, 'Gratuit'),
(PREMIUM, 'Premium'),
(ENTREPRISE, 'Entreprise'),
(CUSTOM, 'Custom'),
)
offre = models.CharField(max_length=2,
choices=OFFRE_CHOICES,
default=PUBLIC)
# Inscription depuis :
client_source = models.ForeignKey(Client,
on_delete=models.SET_NULL,
null=True,
blank=True,
verbose_name=_("Inscription depuis"),
related_name="user_principal",
)
# ou as t il acheté ?
client_achat = models.ManyToManyField(Client,
related_name="user_achats", blank=True)
# sur quelle interface d'admin peut il aller ?
client_admin = models.ManyToManyField(Client,
related_name="user_admin", blank=True)
objects = TibilletManager()
def achat(self):
return " ".join([achat["schema_name"] for achat in self.client_achat.values("schema_name")])
def administre(self):
return " ".join([admin["schema_name"] for admin in self.client_admin.values("schema_name")])
def new_tenant_authorised(self):
# si l'user est déja staff ou root, c'est qu'il a déja une billetterie.
if self.offre in [self.PUBLIC, self.FREE, self.PREMIUM]:
if len(self.client_admin.all()) > 0:
# superuser peut toujours.
return self.is_superuser
else:
return True
elif self.offre == self.ENTREPRISE:
if len(self.client_admin.all()) > 4:
# superuser peut toujours.
return self.is_superuser
else:
return True
elif self.offre == self.CUSTOM:
return True
def set_staff(self, tenant):
self.client_admin.add(tenant)
self.is_staff = True
self.groups.add(Group.objects.get(name="staff"))
self.save()
def __str__(self):
return self.email
# ---------------------------------------------------------------------------------------------------------------------
class TermUserManager(TibilletManager):
def get_queryset(self):
return super().get_queryset().filter(espece=TibilletUser.TYPE_TERM,
client_source=connection.tenant,
)
class TermUser(TibilletUser):
class Meta:
proxy = True
verbose_name = "Terminal"
verbose_name_plural = "Terminaux"
objects = TermUserManager()
def save(self, *args, **kwargs):
# Si création :
if not self.pk:
self.espece = TibilletUser.TYPE_TERM
super().save(*args, **kwargs)
# ---------------------------------------------------------------------------------------------------------------------
class HumanUserManager(TibilletManager):
def get_queryset(self):
return super().get_queryset().filter(espece=TibilletUser.TYPE_HUM,
is_staff=False,
is_superuser=False,
client_achat__id__in=[connection.tenant.id, ],
)
# .distinct() ???
class HumanUser(TibilletUser):
class Meta:
proxy = True
verbose_name = "Utilisateur"
objects = HumanUserManager()
def save(self, *args, **kwargs):
# Si création :
if not self.pk:
self.espece = TibilletUser.TYPE_HUM
self.is_staff = False
self.is_superuser = False
super().save(*args, **kwargs)
# ---------------------------------------------------------------------------------------------------------------------
class SuperHumanUserManager(TibilletManager):
def get_queryset(self):
return super().get_queryset().filter(
espece=TibilletUser.TYPE_HUM,
is_staff=True,
is_superuser=False,
client_admin__id__in=[connection.tenant.id, ],
)
class SuperHumanUser(TibilletUser):
class Meta:
proxy = True
verbose_name = "Administrateur"
objects = SuperHumanUserManager()
def save(self, *args, **kwargs):
# import ipdb; ipdb.set_trace()
# Si création :
if not self.pk:
self.espece = TibilletUser.TYPE_HUM
self.is_staff = True
self.is_superuser = False
super().save(*args, **kwargs)
# ---------------------------------------------------------------------------------------------------------------------

View File

@ -0,0 +1,29 @@
{% load i18n %}
{% block subject %}
{% blocktrans %}Account activation on {{ site_name }}{% endblocktrans %}
{% endblock subject %}
{% block text_body %}
{% blocktrans %}You're receiving this email because you need to finish activation process on {{ site_name }}.{% endblocktrans %}
{% trans "Please go to the following page to activate account:" %}
{{ protocol }}://{{ domain }}/{{ url|safe }}
{% trans "Thanks for using our site!" %}
{% blocktrans %}The {{ site_name }} team{% endblocktrans %}
{% endblock text_body %}
{% block html_body %}
<p>{% blocktrans %}You're receiving this email because you need to finish activation process on {{ site_name }}.{% endblocktrans %}</p>
<p>{% trans "Please go to the following page to activate account:" %}</p>
<p><a href="{{ protocol }}://{{ domain }}/{{ url|safe }}">{{ protocol }}://{{ domain }}/{{ url|safe }}</a></p>
<p>{% trans "Thanks for using our site!" %}</p>
<p>{% blocktrans %}The {{ site_name }} team{% endblocktrans %}</p>
{% endblock html_body %}

View File

@ -0,0 +1,21 @@
{% load i18n %}
{% block subject %}
{% blocktrans %}{{ site_name }} - Your account has been successfully created and activated!{% endblocktrans %}
{% endblock %}
{% block text_body %}
{% trans "Your account has been created and is ready to use!" %}
{% trans "Thanks for using our site!" %}
{% blocktrans %}The {{ site_name }} team{% endblocktrans %}
{% endblock text_body %}
{% block html_body %}
<p>{% trans "Your account has been created and is ready to use!" %}</p>
<p>{% trans "Thanks for using our site!" %}</p>
<p>{% blocktrans %}The {{ site_name }} team{% endblocktrans %}</p>
{% endblock html_body %}

View File

@ -0,0 +1,21 @@
{% load i18n %}
{% block subject %}
{% blocktrans %}{{ site_name }} - Your password has been successfully changed!{% endblocktrans %}
{% endblock %}
{% block text_body %}
{% trans "Your password has been changed!" %}
{% trans "Thanks for using our site!" %}
{% blocktrans %}The {{ site_name }} team{% endblocktrans %}
{% endblock text_body %}
{% block html_body %}
<p>{% trans "Your password has been changed!" %}</p>
<p>{% trans "Thanks for using our site!" %}</p>
<p>{% blocktrans %}The {{ site_name }} team{% endblocktrans %}</p>
{% endblock html_body %}

View File

@ -0,0 +1,29 @@
{% load i18n %}
{% block subject %}
{% blocktrans %}Password reset on {{ site_name }}{% endblocktrans %}
{% endblock subject %}
{% block text_body %}
{% blocktrans %}You're receiving this email because you requested a password reset for your user account at {{ site_name }}.{% endblocktrans %}
{% trans "Please go to the following page and choose a new password:" %}
{{ protocol }}://{{ domain }}/{{ url }}
{% trans "Your username, in case you've forgotten:" %} {{ user.get_username }}
{% trans "Thanks for using our site!" %}
{% blocktrans %}The {{ site_name }} team{% endblocktrans %}
{% endblock text_body %}
{% block html_body %}
<p>{% blocktrans %}You're receiving this email because you requested a password reset for your user account at {{ site_name }}.{% endblocktrans %}</p>
<p>{% trans "Please go to the following page and choose a new password:" %}</p>
<a href="{{ protocol }}://{{ domain }}/{{ url }}">{{ protocol }}://{{ domain }}/{{ url }}</a>
<p>{% trans "Your username, in case you've forgotten:" %} <b>{{ user.get_username }}</b></p>
<p>{% trans "Thanks for using our site!" %}</p>
<p>{% blocktrans %}The {{ site_name }} team{% endblocktrans %}</p>
{% endblock html_body %}

View File

@ -0,0 +1,21 @@
{% load i18n %}
{% block subject %}
{% blocktrans %}{{ site_name }} - Your username has been successfully changed!{% endblocktrans %}
{% endblock %}
{% block text_body %}
{% trans "Your username has been changed!" %}
{% trans "Thanks for using our site!" %}
{% blocktrans %}The {{ site_name }} team{% endblocktrans %}
{% endblock text_body %}
{% block html_body %}
<p>{% trans "Your username has been changed!" %}</p>
<p>{% trans "Thanks for using our site!" %}</p>
<p>{% blocktrans %}The {{ site_name }} team{% endblocktrans %}</p>
{% endblock html_body %}

View File

@ -0,0 +1,29 @@
{% load i18n %}
{% block subject %}
{% blocktrans %}Username reset on {{ site_name }}{% endblocktrans %}
{% endblock subject %}
{% block text_body %}
{% blocktrans %}You're receiving this email because you requested a username reset for your user account at {{ site_name }}.{% endblocktrans %}
{% trans "Please go to the following page and choose a new username:" %}
{{ protocol }}://{{ domain }}/{{ url }}
{% trans "Your username, in case you've forgotten:" %} {{ user.get_username }}
{% trans "Thanks for using our site!" %}
{% blocktrans %}The {{ site_name }} team{% endblocktrans %}
{% endblock text_body %}
{% block html_body %}
<p>{% blocktrans %}You're receiving this email because you requested a username reset for your user account at {{ site_name }}.{% endblocktrans %}</p>
<p>{% trans "Please go to the following page and choose a new username:" %}</p>
<a href="{{ protocol }}://{{ domain }}/{{ url }}">{{ protocol }}://{{ domain }}/{{ url }}</a>
<p>{% trans "Your username, in case you've forgotten:" %} <b>{{ user.get_username }}</b></p>
<p>{% trans "Thanks for using our site!" %}</p>
<p>{% blocktrans %}The {{ site_name }} team{% endblocktrans %}</p>
{% endblock html_body %}

View File

@ -1,6 +1,9 @@
# Generated by Django 2.2 on 2021-06-21 14:58 # Generated by Django 2.2 on 2021-06-23 09:09
from django.db import migrations, models from django.db import migrations, models
import django.db.models.deletion
import stdimage.models
import stdimage.validators
class Migration(migrations.Migration): class Migration(migrations.Migration):
@ -11,12 +14,63 @@ class Migration(migrations.Migration):
] ]
operations = [ operations = [
migrations.CreateModel(
name='Event',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=200)),
('short_description', models.CharField(max_length=250)),
('long_description', models.TextField(blank=True, null=True)),
('datetime', models.DateTimeField()),
('img', stdimage.models.StdImageField(blank=True, null=True, upload_to='images/', validators=[stdimage.validators.MaxSizeValidator(1920, 1920)])),
('reservations', models.PositiveSmallIntegerField(default=0)),
],
options={
'verbose_name': 'Evenement',
'verbose_name_plural': 'Evenements',
'ordering': ('datetime',),
},
),
migrations.CreateModel(
name='OptionGenerale',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=30)),
('poids', models.PositiveSmallIntegerField(default=0, verbose_name='Poids')),
],
options={
'verbose_name': 'Options Generales',
'verbose_name_plural': 'Options Generales',
'ordering': ('poids',),
},
),
migrations.CreateModel(
name='reservation',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('status', models.CharField(choices=[('NAN', 'Annulée'), ('NOV', 'Email non validé'), ('VAL', 'Validée'), ('PAY', 'Payée')], default='NOV', max_length=3, verbose_name='Status de la réservation')),
('qty', models.IntegerField()),
('event', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='reservation', to='BaseBillet.Event')),
],
),
migrations.CreateModel( migrations.CreateModel(
name='Configuration', name='Configuration',
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('organisation', models.CharField(max_length=50)), ('organisation', models.CharField(max_length=50)),
('short_description', models.CharField(max_length=250)), ('short_description', models.CharField(max_length=250)),
('adresse', models.CharField(max_length=250)),
('phone', models.CharField(max_length=20)),
('email', models.EmailField(max_length=254)),
('twitter', models.URLField(blank=True, null=True)),
('facebook', models.URLField(blank=True, null=True)),
('instagram', models.URLField(blank=True, null=True)),
('img', stdimage.models.StdImageField(blank=True, null=True, upload_to='images/')),
('mollie_api_key', models.CharField(blank=True, max_length=50, null=True)),
('reservation_par_user_max', models.PositiveSmallIntegerField(default=6)),
('jauge_max', models.PositiveSmallIntegerField(default=50)),
('option_generale_checkbox', models.ManyToManyField(blank=True, related_name='checkbox', to='BaseBillet.OptionGenerale')),
('option_generale_radio', models.ManyToManyField(blank=True, related_name='radiobutton', to='BaseBillet.OptionGenerale')),
], ],
options={ options={
'abstract': False, 'abstract': False,

View File

@ -1,28 +0,0 @@
# Generated by Django 2.2 on 2021-06-21 15:26
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('BaseBillet', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='configuration',
name='facebook',
field=models.URLField(blank=True, null=True),
),
migrations.AddField(
model_name='configuration',
name='instagram',
field=models.URLField(blank=True, null=True),
),
migrations.AddField(
model_name='configuration',
name='twitter',
field=models.URLField(blank=True, null=True),
),
]

View File

@ -1,23 +0,0 @@
# Generated by Django 2.2 on 2021-06-21 15:36
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('BaseBillet', '0002_auto_20210621_1926'),
]
operations = [
migrations.CreateModel(
name='Event',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=200)),
('short_description', models.CharField(max_length=250)),
('long_description', models.TextField(blank=True, null=True)),
('datetime', models.DateTimeField()),
],
),
]

View File

@ -1,35 +0,0 @@
# Generated by Django 2.2 on 2021-06-21 16:59
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('BaseBillet', '0003_event'),
]
operations = [
migrations.AlterModelOptions(
name='event',
options={'ordering': ('datetime',), 'verbose_name': 'Evenement', 'verbose_name_plural': 'Evenements'},
),
migrations.AddField(
model_name='configuration',
name='adresse',
field=models.CharField(default='route de la joie', max_length=250),
preserve_default=False,
),
migrations.AddField(
model_name='configuration',
name='email',
field=models.EmailField(default='demo@demo.demo', max_length=254),
preserve_default=False,
),
migrations.AddField(
model_name='configuration',
name='phone',
field=models.CharField(default='-262 6 121212', max_length=20),
preserve_default=False,
),
]

View File

@ -1,25 +0,0 @@
# Generated by Django 2.2 on 2021-06-21 17:19
from django.db import migrations
import stdimage.models
import stdimage.validators
class Migration(migrations.Migration):
dependencies = [
('BaseBillet', '0004_auto_20210621_2059'),
]
operations = [
migrations.AddField(
model_name='configuration',
name='img',
field=stdimage.models.StdImageField(blank=True, null=True, upload_to='images/', validators=[stdimage.validators.MaxSizeValidator(1920, 1920)]),
),
migrations.AddField(
model_name='event',
name='img',
field=stdimage.models.StdImageField(blank=True, null=True, upload_to='images/', validators=[stdimage.validators.MaxSizeValidator(1920, 1920)]),
),
]

View File

@ -1,23 +0,0 @@
# Generated by Django 2.2 on 2021-06-22 06:53
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('BaseBillet', '0005_auto_20210621_2119'),
]
operations = [
migrations.AddField(
model_name='configuration',
name='mollie_api_key',
field=models.CharField(blank=True, max_length=50, null=True),
),
migrations.AddField(
model_name='configuration',
name='reservation_max',
field=models.PositiveSmallIntegerField(default=6),
),
]

View File

@ -1,24 +0,0 @@
# Generated by Django 2.2 on 2021-06-22 07:03
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('BaseBillet', '0006_auto_20210622_1053'),
]
operations = [
migrations.RenameField(
model_name='configuration',
old_name='reservation_max',
new_name='reservation_par_user_max',
),
migrations.AddField(
model_name='configuration',
name='jauge_max',
field=models.PositiveSmallIntegerField(default=50),
preserve_default=False,
),
]

View File

@ -1,18 +0,0 @@
# Generated by Django 2.2 on 2021-06-22 07:05
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('BaseBillet', '0007_auto_20210622_1103'),
]
operations = [
migrations.AddField(
model_name='event',
name='reservations',
field=models.PositiveSmallIntegerField(default=6),
),
]

View File

@ -1,35 +0,0 @@
# Generated by Django 2.2 on 2021-06-22 07:39
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('BaseBillet', '0008_event_reservations'),
]
operations = [
migrations.CreateModel(
name='OptionGenerale',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=30)),
],
),
migrations.AlterField(
model_name='event',
name='reservations',
field=models.PositiveSmallIntegerField(default=0),
),
migrations.AddField(
model_name='configuration',
name='option_generale_checkbox',
field=models.ManyToManyField(blank=True, related_name='checkbox', to='BaseBillet.OptionGenerale'),
),
migrations.AddField(
model_name='configuration',
name='option_generale_radio',
field=models.ManyToManyField(blank=True, related_name='radiobutton', to='BaseBillet.OptionGenerale'),
),
]

View File

@ -1,22 +0,0 @@
# Generated by Django 2.2 on 2021-06-22 07:49
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('BaseBillet', '0009_auto_20210622_1139'),
]
operations = [
migrations.AlterModelOptions(
name='optiongenerale',
options={'ordering': ('poids',), 'verbose_name': 'Options Generales', 'verbose_name_plural': 'Options Generales'},
),
migrations.AddField(
model_name='optiongenerale',
name='poids',
field=models.PositiveSmallIntegerField(default=0, verbose_name='Poids'),
),
]

View File

@ -1,23 +0,0 @@
# Generated by Django 2.2 on 2021-06-22 09:22
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('BaseBillet', '0010_auto_20210622_1149'),
]
operations = [
migrations.CreateModel(
name='reservation',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('status', models.CharField(choices=[('NAN', 'Annulée'), ('NOV', 'Email non validé'), ('VAL', 'Validée'), ('PAY', 'Payée')], default='NOV', max_length=3, verbose_name='Status de la réservation')),
('qty', models.IntegerField()),
('event', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='reservation', to='BaseBillet.Event')),
],
),
]

View File

@ -1,18 +0,0 @@
# Generated by Django 2.2 on 2021-06-23 06:21
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('BaseBillet', '0011_reservation'),
]
operations = [
migrations.AlterField(
model_name='configuration',
name='jauge_max',
field=models.PositiveSmallIntegerField(default=50),
),
]

View File

@ -1,19 +0,0 @@
# Generated by Django 2.2 on 2021-06-23 06:25
from django.db import migrations
import stdimage.models
class Migration(migrations.Migration):
dependencies = [
('BaseBillet', '0012_auto_20210623_1021'),
]
operations = [
migrations.AlterField(
model_name='configuration',
name='img',
field=stdimage.models.StdImageField(blank=True, null=True, upload_to='images/'),
),
]

View File

@ -53,7 +53,8 @@ class Configuration(SingletonModel):
'med': (480, 480), 'med': (480, 480),
'thumbnail': (150, 90), 'thumbnail': (150, 90),
}, },
delete_orphans=True delete_orphans=True,
verbose_name='Background'
) )
mollie_api_key = models.CharField(max_length=50, mollie_api_key = models.CharField(max_length=50,

View File

@ -39,12 +39,12 @@
<!-- Post --> <!-- Post -->
<section class="post"> <section class="post">
<header class="major"> <header class="major">
<span class="date">{{ event.datetime | date:"d F Y"}}<br/>{{ event.datetime | time }}</span> <span class="date">{{ event.datetime | date:"d F Y" }}<br/>{{ event.datetime | time }}</span>
<h1>{{ event.name }}</h1> <h1>{{ event.name }}</h1>
<p>{{ event.short_description }}</p> <p>{{ event.short_description }}</p>
</header> </header>
<div class="image main"><img src="/media/{{ event.img.fhd }}" alt=""/></div> <div class="image main"><img src="/media/{{ event.img.fhd }}" alt=""/></div>
<p>{{ event.long_description | linebreaks}}</p> <p>{{ event.long_description | linebreaks }}</p>
</section> </section>
@ -79,7 +79,8 @@
<!-- Break --> <!-- Break -->
{% for option_radio in configuration.option_generale_radio.all %} {% for option_radio in configuration.option_generale_radio.all %}
<div class="col-4 col-12-small"> <div class="col-4 col-12-small">
<input type="radio" id="{{ option_radio.name }}" name="radio_generale" value="{{ option_radio.pk }}"> <input type="radio" id="{{ option_radio.name }}" name="radio_generale"
value="{{ option_radio.pk }}">
<label for="{{ option_radio.name }}">{{ option_radio.name }}</label> <label for="{{ option_radio.name }}">{{ option_radio.name }}</label>
</div> </div>
{% endfor %} {% endfor %}
@ -87,7 +88,8 @@
{% for option_checkbox in configuration.option_generale_checkbox.all %} {% for option_checkbox in configuration.option_generale_checkbox.all %}
<div class="col-6 col-12-small"> <div class="col-6 col-12-small">
<input type="checkbox" id="{{ option_checkbox.name }}" name="{{ option_checkbox.name }}" value="{{ option_checkbox.pk }}"> <input type="checkbox" id="{{ option_checkbox.name }}" name="{{ option_checkbox.name }}"
value="{{ option_checkbox.pk }}">
<label for="{{ option_checkbox.name }}">{{ option_checkbox.name }}</label> <label for="{{ option_checkbox.name }}">{{ option_checkbox.name }}</label>
</div> </div>
@ -104,7 +106,7 @@
<li><input type="reset" value="Reset"/></li> <li><input type="reset" value="Reset"/></li>
</ul> </ul>
</div> </div>
</div> </brdiv>
</form> </form>
<hr/> <hr/>

View File

@ -1,4 +1,4 @@
# Generated by Django 2.2 on 2021-06-10 12:04 # Generated by Django 2.2 on 2021-06-23 09:09
from django.db import migrations, models from django.db import migrations, models
import django.db.models.deletion import django.db.models.deletion

View File

@ -1,14 +1,19 @@
from django.utils import timezone
from django.db import models from django.db import models
from django_tenants.models import TenantMixin, DomainMixin from django_tenants.models import TenantMixin, DomainMixin
class Client(TenantMixin): class Client(TenantMixin):
name = models.CharField(max_length=100) name = models.CharField(max_length=100, unique=True, db_index=True)
paid_until = models.DateField() paid_until = models.DateField(default=timezone.now)
on_trial = models.BooleanField() on_trial = models.BooleanField(default=True)
created_on = models.DateField(auto_now_add=True) created_on = models.DateField(auto_now_add=True)
# default true, schema will be automatically created and synced when it is saved # default true, schema will be automatically created and synced when it is saved
auto_create_schema = True auto_create_schema = True
def __str__(self):
return self.name
class Domain(DomainMixin): class Domain(DomainMixin):
pass pass

View File

@ -79,6 +79,7 @@ TENANT_DOMAIN_MODEL = "Customers.Domain" # app.Model
ROOT_URLCONF = 'TiBillet.urls_tenants' ROOT_URLCONF = 'TiBillet.urls_tenants'
PUBLIC_SCHEMA_URLCONF = 'TiBillet.urls_public' PUBLIC_SCHEMA_URLCONF = 'TiBillet.urls_public'
SITE_ID = 1 SITE_ID = 1
AUTH_USER_MODEL = 'AuthBillet.TibilletUser'
MIDDLEWARE = [ MIDDLEWARE = [
@ -131,7 +132,6 @@ DATABASE_ROUTERS = (
# Password validation # Password validation
# https://docs.djangoproject.com/en/3.1/ref/settings/#auth-password-validators # https://docs.djangoproject.com/en/3.1/ref/settings/#auth-password-validators
# AUTH_USER_MODEL = 'AuthBillet.TibilletUser'
AUTH_PASSWORD_VALIDATORS = [ AUTH_PASSWORD_VALIDATORS = [
{ {
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
@ -158,6 +158,25 @@ REST_FRAMEWORK = {
SIMPLE_JWT = { SIMPLE_JWT = {
'AUTH_HEADER_TYPES': ('JWT',), 'AUTH_HEADER_TYPES': ('JWT',),
} }
DJOSER = {
"SEND_ACTIVATION_EMAIL": True,
"PASSWORD_CHANGED_EMAIL_CONFIRMATION": True,
"PASSWORD_RESET_CONFIRM_URL": "password/reset/confirm/{uid}/{token}",
"USERNAME_RESET_CONFIRM_URL": "username/reset/confirm/{uid}/{token}",
# "ACTIVATION_URL": "activate/{uid}/{token}",
"ACTIVATION_URL": "activate/{uid}/{token}",
# "SOCIAL_AUTH_ALLOWED_REDIRECT_URIS": ["http://manap.django-local.org:8002/"],
'EMAIL': {
'activation': 'AuthBillet.email.ActivationEmail',
'confirmation': 'AuthBillet.email.ConfirmationEmail',
'password_reset': 'AuthBillet.email.PasswordResetEmail',
'password_changed_confirmation': 'AuthBillet.email.PasswordChangedConfirmationEmail',
'username_changed_confirmation': 'AuthBillet.email.UsernameChangedConfirmationEmail',
'username_reset': 'AuthBillet.email.UsernameResetEmail',
},
}
# Internationalization # Internationalization
# https://docs.djangoproject.com/en/3.1/topics/i18n/ # https://docs.djangoproject.com/en/3.1/topics/i18n/

View File

@ -27,6 +27,7 @@ urlpatterns = [
re_path(r'^auth/', include('djoser.urls')), re_path(r'^auth/', include('djoser.urls')),
re_path(r'^auth/', include('djoser.urls.authtoken')), re_path(r'^auth/', include('djoser.urls.authtoken')),
re_path(r'^auth/', include('djoser.urls.jwt')),
path('', include('BaseBillet.urls')), path('', include('BaseBillet.urls')),