diff --git a/.gitignore b/.gitignore index d7a9f45..9aba3c7 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,8 @@ __pycache__/ *.py[cod] *$py.class +../.DS_Store +.DS_Store # C extensions *.so diff --git a/README.md b/README.md index a69c9b0..0e8c8b8 100644 --- a/README.md +++ b/README.md @@ -1 +1,4 @@ -# Event_N-J \ No newline at end of file +# Event_N-J + +przy próbie powtórnego uruchomienia linka ma wystąpić błąd 404 + diff --git a/db_input.txt b/db_input.txt new file mode 100644 index 0000000..5be5fde --- /dev/null +++ b/db_input.txt @@ -0,0 +1,10 @@ + +python3 manage.py shell +from events.models import Participant, Event, Organizer, Status_Participant, Photo + +o1 = Organizer.objects.create(name="organizer1", description="description_organizer_1", mail="organizer1@.o2.pl") +o1.save() --> save +o2 = Organizer.objects.create(name="organizer2", description="description_organizer_2", mail="organizer2@.o2.pl") +o3 = Organizer.objects.create(name="organizer3", description="description_organizer_3", mail="organizer3@.o2.pl") +o4 = Organizer.objects.create(name="organizer4", description="description_organizer_4", mail="organizer4@.o2.pl") + diff --git a/eventnj/config/settings.py b/eventnj/config/settings.py index e1e0c0d..9521621 100644 --- a/eventnj/config/settings.py +++ b/eventnj/config/settings.py @@ -15,7 +15,6 @@ # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent - # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/ @@ -25,8 +24,7 @@ # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True -ALLOWED_HOSTS = [] - +ALLOWED_HOSTS = ["127.0.0.1"] # Application definition @@ -37,6 +35,7 @@ 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', + 'events', ] MIDDLEWARE = [ @@ -54,7 +53,7 @@ TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [], + 'DIRS': [BASE_DIR / 'templates'], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ @@ -69,7 +68,6 @@ WSGI_APPLICATION = 'config.wsgi.application' - # Database # https://docs.djangoproject.com/en/3.2/ref/settings/#databases @@ -80,6 +78,15 @@ } } +# DATABASES = { +# 'default': { +# 'ENGINE': 'django.db.backends.postgresql', +# 'NAME': 'eventnj', +# 'USER': 'postgres', +# 'PASSWORD': '', +# 'HOST': 'localhost' +# } +# } # Password validation # https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators @@ -99,7 +106,6 @@ }, ] - # Internationalization # https://docs.djangoproject.com/en/3.2/topics/i18n/ @@ -113,7 +119,6 @@ USE_TZ = True - # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/3.2/howto/static-files/ @@ -123,3 +128,11 @@ # https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' + +MEDIA_URL = '/media/' +MEDIA_ROOT = BASE_DIR / "media" + +EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' + +# zmiana tymczasowa +HOST = '127.0.0.1:8000' diff --git a/eventnj/config/urls.py b/eventnj/config/urls.py index 5ed47e1..580a989 100644 --- a/eventnj/config/urls.py +++ b/eventnj/config/urls.py @@ -16,6 +16,23 @@ from django.contrib import admin from django.urls import path +from events.views import ( + DashboardView, + # EventDetailsView, + SendMailView, + EventDetailsView_, + ParticipantAddView2, + AuthenticateParticipantView +) + urlpatterns = [ path('admin/', admin.site.urls), + path('', DashboardView.as_view(), name="dashboard"), + path('event-details//', EventDetailsView_.as_view(), name="event-details"), + # path('add-participant/', ParticipantAddView.as_view(), name="add-participant"), + path('add-participant//', ParticipantAddView2.as_view(), name="add-participant"), + + # https://docs.djangoproject.com/en/4.0/topics/http/urls/#path-converters + path('authenticate-participant//', AuthenticateParticipantView.as_view(), name="authenticate-participant"), + path('send-mail//', SendMailView.as_view(), name='send-mail'), ] diff --git a/eventnj/events/forms.py b/eventnj/events/forms.py new file mode 100644 index 0000000..5a015e9 --- /dev/null +++ b/eventnj/events/forms.py @@ -0,0 +1,18 @@ +from django import forms +from django.core.exceptions import ValidationError +from django.forms import widgets, ModelForm + + + +class AddParticipantForm(forms.Form): + name = forms.CharField(label="Imię ", max_length=255) + mail = forms.CharField(label="email ", max_length=255) + + # defaultowo required jest false + accept_rodo = forms.BooleanField() + + # https://www.youtube.com/watch?v=pFMrOpDs4QQ + # accept_rodo = forms.BooleanField(label='accept rodo', help_text='zaakceptuj warunki rodo') + +# modelForm +# https://youtu.be/EX6Tt-ZW0so \ No newline at end of file diff --git a/eventnj/events/management/commands/create_event.py b/eventnj/events/management/commands/create_event.py new file mode 100644 index 0000000..9ca41e6 --- /dev/null +++ b/eventnj/events/management/commands/create_event.py @@ -0,0 +1,69 @@ +from django.core.management.base import BaseCommand +from django.utils import timezone + +from events.models import Event, Organizer +from datetime import datetime +from random import choice, randint + + +# from django.conf import settings +# from django.utils.timezone import make_aware + + +class Command(BaseCommand): + help = "wypełnij organizer danymi -- python manage.py create_event 1" + + def add_arguments(self, parser): + parser.add_argument('total', type=int, help='Indicates the number of organizers to be created') + + def handle(self, *args, **options): + total = options['total'] + + len_events = len(Event.objects.all()) + + # sprawdzaj jaki postfix ma ostatni rekord + # ostatni = Event.objects.all()[len_events - 1:len_events].get().id + + if len_events != 0: + ostatni = Event.objects.last().id + else: + ostatni = 0 + + # postfix kolejnej wartości + # https://docs.python.org/3.9/library/string.html + # postfix = "{:0>5}".format(str(ostatni + 1)) + + formatedDate = datetime.now(tz=timezone.utc) + + # myDate = datetime(2013, 11, 20, 20, 8, 7, 127325, tzinfo=pytz.UTC) + + # formatedDate = myDate #.strftime("%Y-%m-%d %H:%M:%S") + CONST_RANDINT_RESERVE = 25 + CONST_RANDINT = 50 + CONST_PRICE = 25 + + print("create_event") + + for i in range(total): + postfix = str("{:0>5}".format(str(ostatni + 1 + i))) + # print(postfix) + Event.objects.create( + title="event_" + postfix, + description="description_" + postfix, + limit_participant_reserve=CONST_RANDINT_RESERVE + randint(1, 3) * 10, + limit_participant=CONST_RANDINT + randint(1, 6) * 10, + start=formatedDate, + end=formatedDate, + start_registration=formatedDate, + end_registration=formatedDate, + country="country_" + postfix, + city="city_" + postfix, + street="street_" + postfix, + postcode=postfix, + room="room_" + postfix, + price=CONST_PRICE + randint(1, 10) * 5, + is_online=False, + online_link="link_" + postfix, + ) + + self.stdout.write(self.style.SUCCESS(f"dopisane {total} rekordów")) diff --git a/eventnj/events/management/commands/create_organizer.py b/eventnj/events/management/commands/create_organizer.py new file mode 100644 index 0000000..5d65126 --- /dev/null +++ b/eventnj/events/management/commands/create_organizer.py @@ -0,0 +1,39 @@ +from django.core.management.base import BaseCommand +# from events.management.commands.create_db import create_organizer + +from events.models import Organizer + + +class Command(BaseCommand): + help = "wypełnij organizer danymi -- python manage.py create_organizer 5" + + def add_arguments(self, parser): + parser.add_argument('total', type=int, help='Indicates the number of organizers to be created') + + def handle(self, *args, **options): + total = options['total'] + + len_organizers = len(Organizer.objects.all()) + + # sprawdzaj jaki postfix ma ostatni rekord + # ostatni = Organizer.objects.all()[len_organizers - 1:len_organizers].get().id + if len_organizers != 0: + ostatni = Organizer.objects.last().id + else: + ostatni = 0 + + # postfix kolejnej wartości + # https://docs.python.org/3.9/library/string.html + # postfix = "{:0>5}".format(str(ostatni + 1)) + + print("create_organizer") + for i in range(total): + postfix = str("{:0>5}".format(str(ostatni + 1 + i))) + # print(postfix) + Organizer.objects.create( + name="organizer_" + postfix, + description="description_" + postfix, + mail="o_" + postfix + "@o.pl" + ) + + self.stdout.write(self.style.SUCCESS(f"dopisane {total} rekordów")) diff --git a/eventnj/events/management/commands/create_participant.py b/eventnj/events/management/commands/create_participant.py new file mode 100644 index 0000000..3029ad8 --- /dev/null +++ b/eventnj/events/management/commands/create_participant.py @@ -0,0 +1,47 @@ +from django.core.management.base import BaseCommand +from django.utils import timezone +from datetime import datetime +from events.models import Participant, Event + + +class Command(BaseCommand): + help = "wypełnij participant danymi 5 uczestników przypisz do eventu o pk=3 " \ + "-- python manage.py create_participant 5 3" + + + def add_arguments(self, parser): + # parser.add_argument('total', type=int, help='Indicates the number of participants to be created') + parser.add_argument('total', action="extend", nargs=2, type=int, help="Indicates the number of participants to be created for id event") + + def handle(self, *args, **options): + total = options['total'] + + len_participants = len(Participant.objects.all()) + # print(len_participants) + + # sprawdzaj jaki postfix ma ostatni rekord + if len_participants != 0: + ostatni = Participant.objects.last().id + else: + ostatni = 0 + + # postfix kolejnej wartości + # https://docs.python.org/3.9/library/string.html + # postfix = "{:0>5}".format(str(ostatni + 1)) + + formatedDate = datetime.now(tz=timezone.utc) + + print("create_participant") + + for i in range(total[0]): + postfix = str("{:0>5}".format(str(ostatni + 1 + i))) + # print(i + 1) + Participant.objects.create( + name="participant_" + postfix, + mail="p_" + postfix + "@p.pl", + date_change_status=formatedDate, + created=formatedDate, + event=Event.objects.get(pk=total[1]) + ) + + self.stdout.write(self.style.SUCCESS(f"dopisane {total[0]} rekordów")) diff --git a/eventnj/events/management/commands/create_photo.py b/eventnj/events/management/commands/create_photo.py new file mode 100644 index 0000000..97371df --- /dev/null +++ b/eventnj/events/management/commands/create_photo.py @@ -0,0 +1,46 @@ +from django.core.management.base import BaseCommand +# from events.management.commands.create_db import create_organizer + +from events.models import Photo, Event + + +class Command(BaseCommand): + help = "wypełnij organizer danymi -- python manage.py create_photo n photos, id event" + + def add_arguments(self, parser): + + # parser.add_argument('total', type=int , help='Indicates the number of photos to be created') + parser.add_argument('total', action="extend", nargs=2, type=int, help="number of photos, event id") + + + def handle(self, *args, **options): + total = options['total'] + + + len_photos = len(Photo.objects.all()) + + # sprawdzaj jaki postfix ma ostatni rekord + + if len_photos != 0: + ostatni = Photo.objects.last().id + else: + ostatni = 0 + + # postfix kolejnej wartości + # https://docs.python.org/3.9/library/string.html + # postfix = "{:0>5}".format(str(ostatni + 1)) + # print(f"total: {total}") + + print("create_photo") + + for i in range(total[0]): + postfix = str("{:0>5}".format(str(ostatni + 1 + i))) + # print(postfix) + + Photo.objects.create( + name="name_" + postfix, + image="image_" + postfix, + event=Event.objects.get(pk=total[1]) + ) + + self.stdout.write(self.style.SUCCESS(f"dopisane {total[0]} rekordy, event {total[1]}")) diff --git a/eventnj/events/management/commands/create_reo.py b/eventnj/events/management/commands/create_reo.py new file mode 100644 index 0000000..fd93d0d --- /dev/null +++ b/eventnj/events/management/commands/create_reo.py @@ -0,0 +1,156 @@ +# Create Relation Event Organizer + + +from django.core.management.base import BaseCommand +from django.utils import timezone + +from events.models import Event, Organizer + +from datetime import datetime +from random import choice, randint + + +# from django.conf import settings +# from django.utils.timezone import make_aware + + +class Command(BaseCommand): + help = "wypełnij organizer danymi -- python manage.py create_reo [e | o | e1] 1 1" + + def add_arguments(self, parser): + + parser.add_argument('choice', choices=['e', 'o', 'e1']) + parser.add_argument('total', action="extend", nargs=2, type=int, help="total") + + def handle(self, *args, **options): + opt_total = options['total'] + + opt_choice = options['choice'] + + # print(f'options: {options}') + + # if opt_choice == 'e': + # print('event') + # elif opt_choice == 'o': + # print('organizer') + + + + # var_flag = options['flag'] + # + # var_e = var_event[0] + # var_o = var_event[1] + + # return + # print(f'var_flag: {var_flag}') + # print(f'options: {options}') + len_events = len(Event.objects.all()) + len_organizers = len(Organizer.objects.all()) + m = 0 + n = 0 + print("create_reo") + + if opt_choice == 'e': + # dla losowych eventów m wybierz losowo n organizatorów + # e m n + m = opt_total[0] + n = opt_total[1] + result = set_change(opt_total, len_events, len_organizers) + + if result[0] == False: + self.stdout.write(self.style.ERROR(result[1])) + else: + pass + # self.stdout.write(self.style.SUCCESS(result[1])) + + elif opt_choice == 'o': + # dla losowych organizatorów n wybierz m losowych eventów + # o n m + m = opt_total[1] + n = opt_total[0] + + result = set_change(opt_total, len_organizers, len_events) + + if result[0] == False: + self.stdout.write(self.style.ERROR(result[1])) + else: + pass + # self.stdout.write(self.style.SUCCESS(result[1])) + + elif opt_choice == 'e1': + # dla eventu m wybierz organizatora n + # e1 m n + m = opt_total[0] + n = opt_total[1] + result = set_change(opt_total, len_events, len_organizers) + + if result[0] == False: + self.stdout.write(self.style.ERROR(result[1])) + else: + pass + # self.stdout.write(self.style.SUCCESS(result[1])) + + events = Event.objects.get(pk=m) + organizer = Organizer.objects.get(pk=n) + events.organizers.add(organizer) + + self.stdout.write(self.style.SUCCESS(f"dopisane {1} rekordów")) + + return + # print(n, m) + counter = 0 + # return + + for i_e in range(1, m + 1): + # print(i_e) + events = Event.objects.get(pk=i_e) + # jeśli nie ma pk to powinno się go pominąć + for i_o in range(1, n + 1): + # events.models.Organizer.DoesNotExist: Organizer matching query does not exist. + # https://stackoverflow.com/questions/17813919/django-error-matching-query-does-not-exist + try: + organizer = Organizer.objects.get(pk=i_o) + counter += 1 + except Organizer.DoesNotExist: + organizer = None + + events.organizers.add(organizer) + + + # print(i_o) + + # return + # https://docs.djangoproject.com/en/4.0/topics/db/examples/many_to_many/ + + + + # dla listy eventów wybierz listę organizatorów + # -e [e] [o] + + # dla listy organozatorów wybierz listę eventów + # -o [o] [e] + + # dla wybranego eventu wybierz organizatora + # -E id id + # dla wybranego organizatora wybierz event + # -O id id + + # sprawdzaj jaki postfix ma ostatni rekord + # ostatni = Event.objects.last().id + + self.stdout.write(self.style.SUCCESS(f"dopisane {counter} rekordów")) + + +def set_change(var_flag, len_m, len_n): + # sprawdzaj czy liczba argumentów się zgadza + + m = int(var_flag[0]) + n = int(var_flag[1]) + + if m > len_m: + return [False, f"wartość event jest zbyt duża nie powinna przekraczać {len_m} rekordów"] + + if n > len_n: + return [False, f"wartość organizer jest zbyt duża nie powinna przekraczać {len_n} rekordów"] + + return [True, f"OK"] diff --git a/eventnj/events/migrations/0001_initial.py b/eventnj/events/migrations/0001_initial.py new file mode 100644 index 0000000..fd3d3cb --- /dev/null +++ b/eventnj/events/migrations/0001_initial.py @@ -0,0 +1,81 @@ +# Generated by Django 3.2.8 on 2022-02-20 18:35 + +from django.db import migrations, models +import django.db.models.deletion +import uuid + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Event', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(max_length=255)), + ('description', models.TextField()), + ('limit_participant_reserve', models.IntegerField()), + ('limit_participant', models.IntegerField()), + ('start', models.DateTimeField()), + ('end', models.DateTimeField()), + ('start_registration', models.DateTimeField()), + ('end_registration', models.DateTimeField()), + ('status', models.IntegerField(choices=[(1, 'Pending'), (2, 'Published'), (3, 'Archive')], default=1)), + ('country', models.CharField(max_length=64)), + ('city', models.CharField(max_length=64)), + ('street', models.CharField(max_length=64)), + ('postcode', models.CharField(max_length=12)), + ('room', models.CharField(blank=True, max_length=64)), + ('price', models.DecimalField(decimal_places=2, max_digits=6)), + ('is_online', models.BooleanField(default=False)), + ('online_link', models.URLField(blank=True)), + ('created', models.DateTimeField(auto_now_add=True)), + ], + ), + migrations.CreateModel( + name='Organizer', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=255)), + ('description', models.CharField(blank=True, max_length=2000)), + ('mail', models.EmailField(max_length=255)), + ], + ), + migrations.CreateModel( + name='Photo', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=255)), + ('image', models.ImageField(upload_to='photos')), + ('date', models.DateTimeField(auto_now_add=True)), + ('event', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='photos', to='events.event')), + ], + ), + migrations.CreateModel( + name='Participant', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=255)), + ('mail', models.CharField(max_length=255)), + ('status', models.IntegerField(choices=[(1, 'Is_New'), (2, 'Is_Active_Mail'), (3, 'Is_Deactivate_Mail'), (4, 'Is_Active_Event'), (5, 'Is_Deactivate_Event')], default=1)), + ('date_change_status', models.DateTimeField(blank=True, null=True)), + ('is_reserved', models.BooleanField(default=False)), + ('authentication_code', models.UUIDField(default=uuid.uuid4, editable=False, unique=True)), + ('confirmation_code', models.UUIDField(default=uuid.uuid4, editable=False, unique=True)), + ('non_confirmation_code', models.UUIDField(default=uuid.uuid4, editable=False, unique=True)), + ('identification_code', models.UUIDField(default=uuid.uuid4, editable=False, unique=True)), + ('created', models.DateTimeField(auto_now_add=True)), + ('event', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='participants', to='events.event')), + ], + ), + migrations.AddField( + model_name='event', + name='organizers', + field=models.ManyToManyField(related_name='events', to='events.Organizer'), + ), + ] diff --git a/eventnj/events/models.py b/eventnj/events/models.py index 71a8362..d795345 100644 --- a/eventnj/events/models.py +++ b/eventnj/events/models.py @@ -1,3 +1,115 @@ from django.db import models +import uuid +# from config.settings import HOST +from django.conf import settings +from django.core.mail import EmailMultiAlternatives +from django.template.loader import render_to_string + + +SE_PENDING = 1 +SE_PUBLISHED = 2 +SE_ARCHIVE = 3 + +STATUS_EVENT = ( + (SE_PENDING, "Pending"), + (SE_PUBLISHED, "Published"), + (SE_ARCHIVE, "Archive") +) + +SP_IS_NEW = 1 +SP_IS_ACTIVE_MAIL = 2 +SP_IS_DEACTIVATE_MAIL = 3 +SP_IS_ACTIVE_EVENT = 4 +SP_IS_DEACTIVATE_EVENT = 5 + +STATUS_PARTICIPANT = ( + (SP_IS_NEW, "Is_New"), + (SP_IS_ACTIVE_MAIL, "Is_Active_Mail"), + (SP_IS_DEACTIVATE_MAIL, "Is_Deactivate_Mail"), + (SP_IS_ACTIVE_EVENT, "Is_Active_Event"), + (SP_IS_DEACTIVATE_EVENT, "Is_Deactivate_Event"), +) # Create your models here. + +class Participant(models.Model): + name = models.CharField(max_length=255) + mail = models.CharField(max_length=255) + # status_id = models.ForeignKey("Status_participant", related_name="participant", on_delete=models.CASCADE) + status = models.IntegerField(choices=STATUS_PARTICIPANT, default=SP_IS_NEW) + date_change_status = models.DateTimeField(null=True, blank=True) + is_reserved = models.BooleanField(default=False) + # authentication_code = models.UUIDField(default=uuid.uuid4, editable=False) + authentication_code = models.UUIDField(editable=False, default=uuid.uuid4, unique=True) + confirmation_code = models.UUIDField(editable=False, default=uuid.uuid4, unique=True) + non_confirmation_code = models.UUIDField(editable=False, default=uuid.uuid4, unique=True) + identification_code = models.UUIDField(editable=False, default=uuid.uuid4, unique=True) + created = models.DateTimeField(auto_now_add=True) + event = models.ForeignKey("Event", related_name="participants", on_delete=models.CASCADE) + + def invite_by_email(self): + text_content = f'We would like to invite you to {self.event.title}. ' + html_content = f'

We would like to invite you to {self.event.title} message.

' + str_link = f'http://{settings.HOST}/authenticate-participant/{self.authentication_code}' + msg = EmailMultiAlternatives( + f'Invitation to event: {self.event.title}, link: {str_link}', + text_content, + 'from@example.com', + [self.mail] + ) + + html_content = render_to_string('events/test.html', {'event': self.event, 'str_link': str_link}) + msg.attach_alternative(html_content, "text/html") + return msg.send() + + +class Event(models.Model): + title = models.CharField(max_length=255) + description = models.TextField() + organizers = models.ManyToManyField("Organizer", related_name="events") + limit_participant_reserve = models.IntegerField() + limit_participant = models.IntegerField() + start = models.DateTimeField() + end = models.DateTimeField() + start_registration = models.DateTimeField() + end_registration = models.DateTimeField() + status = models.IntegerField(choices=STATUS_EVENT, default=SE_PENDING) + country = models.CharField(max_length=64) + city = models.CharField(max_length=64) + street = models.CharField(max_length=64) + postcode = models.CharField(max_length=12) + room = models.CharField(max_length=64, blank=True) + price = models.DecimalField(max_digits=6, decimal_places=2) + is_online = models.BooleanField(default=False) + online_link = models.URLField(max_length=200, blank=True) + created = models.DateTimeField(auto_now_add=True) + +class Organizer(models.Model): + name = models.CharField(max_length=255) + description = models.CharField(max_length=2000, blank=True) + mail = models.EmailField(max_length=255) +# TODO: widget do pola mail + +# class Status_Participant(models.Model): +# status = models.IntegerField(choices=STATUS_PARTICIPANT) +# date = models.DateTimeField(auto_now_add=True) + +class Photo(models.Model): + event = models.ForeignKey("Event", related_name="photos", on_delete=models.CASCADE) + name = models.CharField(max_length=255) + image = models.ImageField(upload_to="photos") + # TODO podaj sciezke + date = models.DateTimeField(auto_now_add=True) + + + + + + + + + + + + + diff --git a/eventnj/events/templates/events/addParticipant_view.html b/eventnj/events/templates/events/addParticipant_view.html new file mode 100644 index 0000000..6fb4a9d --- /dev/null +++ b/eventnj/events/templates/events/addParticipant_view.html @@ -0,0 +1,15 @@ +{% extends 'base.html' %} + +{% block content %} +
+ {% csrf_token %} + + {{ form.as_p}}
+ + +
+
+
+ + << Powrot do listy Eventów +{% endblock %} \ No newline at end of file diff --git a/eventnj/events/templates/events/authenticateParticipant_view.html b/eventnj/events/templates/events/authenticateParticipant_view.html new file mode 100644 index 0000000..33eab9c --- /dev/null +++ b/eventnj/events/templates/events/authenticateParticipant_view.html @@ -0,0 +1,24 @@ +{% extends 'base.html' %} + + +{% block content %} + + {% if msg %} + +

+ {{ msg }} +

+ + {% else %} + +

{{ participant.name }}

+

został dopisany do Eventu: {{ participant.event.title }}

+ + {% endif %} + + + +
+
+ << Powrot do listy Eventów +{% endblock %} diff --git a/eventnj/events/templates/events/dashboard.html b/eventnj/events/templates/events/dashboard.html new file mode 100644 index 0000000..087780c --- /dev/null +++ b/eventnj/events/templates/events/dashboard.html @@ -0,0 +1,16 @@ +{% extends 'base.html' %} + +{% block content %} + + {% if message %} +

{{ message }}

+ {% endif %} + + List of Events: + +{% endblock %} \ No newline at end of file diff --git a/eventnj/events/templates/events/event_details_view.html b/eventnj/events/templates/events/event_details_view.html new file mode 100644 index 0000000..5de7351 --- /dev/null +++ b/eventnj/events/templates/events/event_details_view.html @@ -0,0 +1,22 @@ +{% extends 'base.html' %} + +{% block content %} + {% if message %} +

{{ message }}

+ {% endif %} + +

Event


+ nazwa: {{ event.title }}
+ cena: {{ event.price }} zł
+ opis: {{ event.description }}
+ +
+
+ + + Dodaj mnie do eventu >> +
+
+ << Powrot do listy Eventów + +{% endblock %} \ No newline at end of file diff --git a/eventnj/events/templates/events/info_send_mail.html b/eventnj/events/templates/events/info_send_mail.html new file mode 100644 index 0000000..782ea3a --- /dev/null +++ b/eventnj/events/templates/events/info_send_mail.html @@ -0,0 +1,24 @@ +{% extends 'base.html' %} + +{% block content %} + {% if message %} +

{{ message }}

+ {% endif %} + +

Event


+ nazwa: {{ event.title }}
+ cena: {{ event.price }} zł
+ opis: {{ event.description }}
+ +
+
+

+ Właśnie przesłaliśmy do Ciebie email
+ w którym znajdziesz potwierdzenie swojej autentyczności. +

+ +
+
+ << Powrot do listy Eventów + +{% endblock %} \ No newline at end of file diff --git a/eventnj/events/templates/events/test.html b/eventnj/events/templates/events/test.html new file mode 100644 index 0000000..b81c070 --- /dev/null +++ b/eventnj/events/templates/events/test.html @@ -0,0 +1,13 @@ +{% extends 'base.html' %} + +{% block content %} + + + + +

Invitation to event: {{ event.title }},
link: {{ str_link }}

> + + + + +{% endblock %} \ No newline at end of file diff --git a/eventnj/events/views.py b/eventnj/events/views.py index 91ea44a..f07210a 100644 --- a/eventnj/events/views.py +++ b/eventnj/events/views.py @@ -1,3 +1,253 @@ -from django.shortcuts import render +from django.http import Http404 +from django.shortcuts import render, get_object_or_404, redirect +from django.urls import reverse_lazy +from django.utils import timezone +from django.views import View +from django.views.generic import FormView +from django.views.generic.detail import DetailView + +from .forms import AddParticipantForm +from .models import Event, Participant +from .models import ( + SP_IS_NEW, + SP_IS_ACTIVE_MAIL, +) + # Create your views here. + +class DashboardView(View): + template_name = "events/dashboard.html" + + def get(self, request, *args, **kwargs): + events = Event.objects.all().order_by("start") + ctx = { + "events": events, + } + return render(request, self.template_name, ctx) + + +# class EventDetailsView_(DetailView): +# model = Event +# template_name = 'event_details_view.html' +# +# def dispatch(self, request, *args, **kwargs): +# +# # try: +# print(kwargs) +# # breakpoint() +# +# obj = super().dispatch(request, *args, **kwargs) +# # print(obj) +# # except Event.DoesNotExist: +# # raise Http404('dupa, nie ma Eventu') +# +# return obj +# # def get_context_data(self, **kwargs): +# # # breakpoint() +# # print(self.object) +# # context = super().get_context_data(**kwargs) +# # +# # return context +# # def get_object(self, queryset=None): +# # # breakpoint() +# # # if queryset is None: +# # # queryset = self.get_queryset() +# # +# # +# # try: +# # obj = super().get_object() +# # except Event.DoesNotExist: +# # +# # raise Http404('dupa nie ma Eventu') +# # +# # return obj + + +class EventDetailsView_(DetailView): + model = Event + template_name = 'events/event_details_view.html' + + # template_name = 'event_details_view.html' + + # def dispatch(self, request, *args, **kwargs): + # # event_slug = self.kwargs.get("slug") + # self.event = get_object_or_404(Event) + # return super().dispatch(request, *args, **kwargs) + + # def get_context_data(self, **kwargs): + # context = super().get_context_data(**kwargs) + # return context + + +# class EventDetailsView(View): +# """Funkcja wyswietlajaca opis jednego Eventu""" +# template_name = 'events/event_details_view.html' +# +# # test stworzyc pizze kotra ma sie zwrocic +# def get(self, request, *args, **kwargs): +# event_id = kwargs['pk'] +# # breakpoint() +# event = get_object_or_404(Event, pk=event_id) +# +# ctx = { +# 'event': event, +# } +# return render(request, self.template_name, ctx) + +class SendMailView(DetailView): + template_name = 'events/info_send_mail.html' + model = Event + + +# https://ccbv.co.uk/projects/Django/3.2/django.views.generic.edit/FormView/ + +class ParticipantAddView2(FormView): + """Dodaj jedneuczestnika do eventu""" + form_class = AddParticipantForm + + # https://www.fullstackpython.com/django-urls-reverse-lazy-examples.html + # success_url = reverse('dashboard') + # success_url = reverse_lazy('send-mail') + template_name = 'events/addParticipant_view.html' + + def form_valid(self, form): + # This method is called when valid form data has been POSTed. + event_id = self.kwargs['pk'] + event = get_object_or_404(Event, pk=event_id) + + name = form.cleaned_data.get('name') + mail = form.cleaned_data.get('mail') + + # modelForm + # event którego nie ma + + ''' uczestnik jeste nie jest określony + czy należy do listy dodatkowej czy rezerwowej + przypisanie po zamknięciu rezerwacji + ''' + participant = Participant() + participant.name = name + participant.mail = mail + participant.date_change_status = timezone.now() + participant.event = event + participant.status = SP_IS_NEW + participant.save() + participant.invite_by_email() + return super().form_valid(form) + + # https://stackoverflow.com/questions/46184193/how-to-reverse-lazy-to-a-view-url-with-variable + def get_success_url(self): + eventid = self.kwargs['pk'] + + # self.success_url) # success_url may be lazy + return reverse_lazy('send-mail', kwargs={'pk': eventid}) + + +# https://docs.djangoproject.com/en/3.2/ref/class-based-views/ +class ParticipantAddView(View): + template_name = 'events/addParticipant_view.html' + + def get(self, request, *args, **kwargs): + form = AddParticipantForm() + + # event_id = kwargs['pk'] + + # event = get_object_or_404(Event, pk=event_id) + + return render(request, self.template_name, {'form': form}) + + def post(self, request, *args, **kwargs): + form = AddParticipantForm(request.POST) + event_id = kwargs['pk'] + event = get_object_or_404(Event, pk=event_id) + + if form.is_valid(): + name = form.cleaned_data.get('name') + mail = form.cleaned_data.get('mail') + + formatedDate = datetime.now(tz=timezone.utc) + + participant = Participant() + participant.name = name + participant.mail = mail + participant.date_change_status = formatedDate + # participant.created = formatedDate + participant.event = event + participant.save() + + # tu nie możemy przesłać kontekstu + # wracamy do listy eventów + # return redirect('student', student_id=student.id) # -> przekieruj na stronę + # return redirect('dashboard') # -> przekieruj na stronę + return redirect('send-mail') # -> przekieruj na stronę + + return render(request, self.template_name, {'form': form}) # tu możemy przekazać kontekst + + +class AuthenticateParticipantView(DetailView): + template_name = 'events/authenticateParticipant_view.html' + model = Participant + # query_pk_and_slug = False + # query_pk_and_slug = "authenticate_code" + slug_field = 'authentication_code' + slug_url_kwarg = 'authenticate_code' + + def get(self, request, *args, **kwargs): + # authenticate_code + authenticate_code = kwargs['authenticate_code'] + + # https://gist.github.com/ShawnMilo/7777304 + # uuid.UUID('302a4299-736e-4ef3-84fc-a9f400e84b24').version + # czy authenticate_code jest uuid + print(f"---- sprawdzaj UUID") + + # try: + # val = UUID(authenticate_code) + # except ValueError: + # msg = f"{authenticate_code} is not uuid" + # print(msg) + # ctx = { + # "msg": msg, + # } + # return render(request, self.template_name, ctx) + + print(f"kwargs -->: {kwargs}") + + participant = get_object_or_404(Participant, authentication_code=authenticate_code) + print(f"---- sprawdzaj status") + + # sprawdzaj czy już wcześniej nastąpiła zmiana statusu + if participant.status == SP_IS_ACTIVE_MAIL: + # tu musi nastąpić błąd 404 + raise Http404('Question does not exists') + # msg = f"próba ponownego aktywowania maila" + # print(msg) + # ctx = { + # "msg": msg, + # } + # return render(request, self.template_name, ctx) + + print(f"---- zmień status") + # zmień status + participant.status = SP_IS_ACTIVE_MAIL + participant.date_change_status = timezone.now() + + print(f"---- zachowaj zmiany") + participant.save() + # setStatus() + # zmiana rezerwacji + + ctx = { + "participant": participant + } + + return render(request, self.template_name, ctx) + + # def post(self, request, *args, **kwargs): + # + # authenticate_code = kwargs['aauthentication_code'] + # participant = get_object_or_404(Participant, authentication_code=authenticate_code) + # + # ctx = {} + # return render(request, self.template_name, ctx) # tu możemy przekazać kontekst diff --git a/eventnj/script_eventnj.sh b/eventnj/script_eventnj.sh new file mode 100755 index 0000000..e7d2650 --- /dev/null +++ b/eventnj/script_eventnj.sh @@ -0,0 +1,34 @@ +# aby plik był wykonywalny +# chmod +x script_eventnj.sh + +# uruchamianie skryptu +#./script_eventnj.sh +# ----------------------------------------------- + + +#migracja +python manage.py migrate + + +# utwórz 5 eventów +python manage.py create_event 5 + +# utwórz 2 eventy +python manage.py create_event 2 + +# utwórz 5 organizatorów +python manage.py create_organizer 5 + +# utwórz relację między 5 kolejnymi eventami i 5 kolejnymi organizatorami +# tworzy hurtowo - jest to nieracjonalne +python manage.py create_reo e 5 5 + +# tworzy relację między eventem o pk=6 i organizatorem o pk=2 +# tworzy pojedynczo - jest większa kotrola +python manage.py create_reo e1 6 2 + +# utwórz 1 uczestnika i przypisz do eventu o pk=5 +python manage.py create_participant 1 5 + +# utwórz 3 zdjęcia i przypisz do eventu o pk=2 +python manage.py create_photo 3 2 diff --git a/eventnj/templates/404.html b/eventnj/templates/404.html new file mode 100644 index 0000000..b088aea --- /dev/null +++ b/eventnj/templates/404.html @@ -0,0 +1,12 @@ + + + + + Title + + +

+ Error 404 +

+ + \ No newline at end of file diff --git a/eventnj/templates/base.html b/eventnj/templates/base.html new file mode 100644 index 0000000..2265efd --- /dev/null +++ b/eventnj/templates/base.html @@ -0,0 +1,17 @@ + + + + + Title + + + {% block content %} + Hi! + {% endblock %} + +
+ {% block footer %} + {% endblock %} +
+ + \ No newline at end of file diff --git a/poetry.lock b/poetry.lock index b466805..ce438c5 100644 --- a/poetry.lock +++ b/poetry.lock @@ -38,6 +38,14 @@ python-versions = ">=3.6" python-dateutil = ">=2.4" text-unidecode = "1.3" +[[package]] +name = "pillow" +version = "9.0.1" +description = "Python Imaging Library (Fork)" +category = "main" +optional = false +python-versions = ">=3.7" + [[package]] name = "python-dateutil" version = "2.8.2" @@ -84,7 +92,7 @@ python-versions = "*" [metadata] lock-version = "1.1" python-versions = "3.9" -content-hash = "980fb7ff89fcfdfbb6abd81b16c0766e9cc3818ae7d74067ee77d5db2c4fb172" +content-hash = "36ee5a5e6906db5637b38dd9f5a604f0058badb1485435e4ab16bae6cf27a2ee" [metadata.files] asgiref = [ @@ -99,6 +107,40 @@ faker = [ {file = "Faker-11.3.0-py3-none-any.whl", hash = "sha256:61f97034cea252b8426d81810afab2f3c27b584f2b4313400a0cc83a9b013ded"}, {file = "Faker-11.3.0.tar.gz", hash = "sha256:adbe567e64da6a1097feacab699000e1ad16e17a6592a8f0ae1ee0b7fbf19887"}, ] +pillow = [ + {file = "Pillow-9.0.1-cp310-cp310-macosx_10_10_universal2.whl", hash = "sha256:9bfdb82cdfeccec50aad441afc332faf8606dfa5e8efd18a6692b5d6e79f00fd"}, + {file = "Pillow-9.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5100b45a4638e3c00e4d2320d3193bdabb2d75e79793af7c3eb139e4f569f16f"}, + {file = "Pillow-9.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:528a2a692c65dd5cafc130de286030af251d2ee0483a5bf50c9348aefe834e8a"}, + {file = "Pillow-9.0.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0f29d831e2151e0b7b39981756d201f7108d3d215896212ffe2e992d06bfe049"}, + {file = "Pillow-9.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:855c583f268edde09474b081e3ddcd5cf3b20c12f26e0d434e1386cc5d318e7a"}, + {file = "Pillow-9.0.1-cp310-cp310-win32.whl", hash = "sha256:d9d7942b624b04b895cb95af03a23407f17646815495ce4547f0e60e0b06f58e"}, + {file = "Pillow-9.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:81c4b81611e3a3cb30e59b0cf05b888c675f97e3adb2c8672c3154047980726b"}, + {file = "Pillow-9.0.1-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:413ce0bbf9fc6278b2d63309dfeefe452835e1c78398efb431bab0672fe9274e"}, + {file = "Pillow-9.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:80fe64a6deb6fcfdf7b8386f2cf216d329be6f2781f7d90304351811fb591360"}, + {file = "Pillow-9.0.1-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cef9c85ccbe9bee00909758936ea841ef12035296c748aaceee535969e27d31b"}, + {file = "Pillow-9.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d19397351f73a88904ad1aee421e800fe4bbcd1aeee6435fb62d0a05ccd1030"}, + {file = "Pillow-9.0.1-cp37-cp37m-win32.whl", hash = "sha256:d21237d0cd37acded35154e29aec853e945950321dd2ffd1a7d86fe686814669"}, + {file = "Pillow-9.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:ede5af4a2702444a832a800b8eb7f0a7a1c0eed55b644642e049c98d589e5092"}, + {file = "Pillow-9.0.1-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:b5b3f092fe345c03bca1e0b687dfbb39364b21ebb8ba90e3fa707374b7915204"}, + {file = "Pillow-9.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:335ace1a22325395c4ea88e00ba3dc89ca029bd66bd5a3c382d53e44f0ccd77e"}, + {file = "Pillow-9.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db6d9fac65bd08cea7f3540b899977c6dee9edad959fa4eaf305940d9cbd861c"}, + {file = "Pillow-9.0.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f154d173286a5d1863637a7dcd8c3437bb557520b01bddb0be0258dcb72696b5"}, + {file = "Pillow-9.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14d4b1341ac07ae07eb2cc682f459bec932a380c3b122f5540432d8977e64eae"}, + {file = "Pillow-9.0.1-cp38-cp38-win32.whl", hash = "sha256:effb7749713d5317478bb3acb3f81d9d7c7f86726d41c1facca068a04cf5bb4c"}, + {file = "Pillow-9.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:7f7609a718b177bf171ac93cea9fd2ddc0e03e84d8fa4e887bdfc39671d46b00"}, + {file = "Pillow-9.0.1-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:80ca33961ced9c63358056bd08403ff866512038883e74f3a4bf88ad3eb66838"}, + {file = "Pillow-9.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1c3c33ac69cf059bbb9d1a71eeaba76781b450bc307e2291f8a4764d779a6b28"}, + {file = "Pillow-9.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:12875d118f21cf35604176872447cdb57b07126750a33748bac15e77f90f1f9c"}, + {file = "Pillow-9.0.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:514ceac913076feefbeaf89771fd6febde78b0c4c1b23aaeab082c41c694e81b"}, + {file = "Pillow-9.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3c5c79ab7dfce6d88f1ba639b77e77a17ea33a01b07b99840d6ed08031cb2a7"}, + {file = "Pillow-9.0.1-cp39-cp39-win32.whl", hash = "sha256:718856856ba31f14f13ba885ff13874be7fefc53984d2832458f12c38205f7f7"}, + {file = "Pillow-9.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:f25ed6e28ddf50de7e7ea99d7a976d6a9c415f03adcaac9c41ff6ff41b6d86ac"}, + {file = "Pillow-9.0.1-pp37-pypy37_pp73-macosx_10_10_x86_64.whl", hash = "sha256:011233e0c42a4a7836498e98c1acf5e744c96a67dd5032a6f666cc1fb97eab97"}, + {file = "Pillow-9.0.1-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:253e8a302a96df6927310a9d44e6103055e8fb96a6822f8b7f514bb7ef77de56"}, + {file = "Pillow-9.0.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6295f6763749b89c994fcb6d8a7f7ce03c3992e695f89f00b741b4580b199b7e"}, + {file = "Pillow-9.0.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:a9f44cd7e162ac6191491d7249cceb02b8116b0f7e847ee33f739d7cb1ea1f70"}, + {file = "Pillow-9.0.1.tar.gz", hash = "sha256:6c8bc8238a7dfdaf7a75f5ec5a663f4173f8c367e5a39f87e720495e1eed75fa"}, +] python-dateutil = [ {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, diff --git a/pyproject.toml b/pyproject.toml index 041c126..e35fcbf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,6 +7,7 @@ authors = ["Your Name "] [tool.poetry.dependencies] python = "3.9" Django = "3.2.8" +Pillow = "^9.0.1" [tool.poetry.dev-dependencies] Faker = "^11.3.0"