mirror of
				https://github.com/more-tech4-magnum-opus/backend.git
				synced 2025-10-31 07:47:32 +03:00 
			
		
		
		
	added event crud
This commit is contained in:
		
							parent
							
								
									dada351290
								
							
						
					
					
						commit
						7172920c07
					
				|  | @ -1,6 +1,17 @@ | ||||||
| from rest_framework import permissions | from rest_framework import permissions | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | class IsWorker(permissions.BasePermission): | ||||||
|  |     """ | ||||||
|  |     Checks if request user is worker(not hr or admin) | ||||||
|  |     """ | ||||||
|  | 
 | ||||||
|  |     def has_permission(self, request, view): | ||||||
|  |         if request.method in permissions.SAFE_METHODS: | ||||||
|  |             return True | ||||||
|  |         return not request.user.is_manager | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| class IsManager(permissions.BasePermission): | class IsManager(permissions.BasePermission): | ||||||
|     """ |     """ | ||||||
|     Checks if request user is an admin or hr |     Checks if request user is an admin or hr | ||||||
|  | @ -14,7 +25,7 @@ class IsManager(permissions.BasePermission): | ||||||
| 
 | 
 | ||||||
| class IsAdmin(permissions.BasePermission): | class IsAdmin(permissions.BasePermission): | ||||||
|     """ |     """ | ||||||
|     Checks if request user is an admin or hr |     Checks if request user is an admin | ||||||
|     """ |     """ | ||||||
| 
 | 
 | ||||||
|     def has_permission(self, request, view): |     def has_permission(self, request, view): | ||||||
|  |  | ||||||
|  | @ -1,6 +1,7 @@ | ||||||
| from django.urls import path, include | from django.urls import path, include | ||||||
| from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView | from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView | ||||||
| 
 | 
 | ||||||
|  | from events.api.views import ListCreateEventApi, RetireUpdateDeleteEventApi | ||||||
| from marketplace.api.views import ListCreateProductApi, RetireUpdateDestroyProductApi | from marketplace.api.views import ListCreateProductApi, RetireUpdateDestroyProductApi | ||||||
| from users.api.views import ( | from users.api.views import ( | ||||||
|     ListCreateUserApi, |     ListCreateUserApi, | ||||||
|  | @ -23,6 +24,19 @@ urlpatterns = [ | ||||||
|             ] |             ] | ||||||
|         ), |         ), | ||||||
|     ), |     ), | ||||||
|  |     path( | ||||||
|  |         "events/", | ||||||
|  |         include( | ||||||
|  |             [ | ||||||
|  |                 path("", ListCreateEventApi.as_view(), name="list_create_event"), | ||||||
|  |                 path( | ||||||
|  |                     "<str:slug>", | ||||||
|  |                     RetireUpdateDeleteEventApi.as_view(), | ||||||
|  |                     name="get_update_delete_event", | ||||||
|  |                 ), | ||||||
|  |             ] | ||||||
|  |         ), | ||||||
|  |     ), | ||||||
|     path( |     path( | ||||||
|         "marketplace/", |         "marketplace/", | ||||||
|         include( |         include( | ||||||
|  |  | ||||||
|  | @ -39,6 +39,7 @@ REST_FRAMEWORK = { | ||||||
|         "rest_framework_simplejwt.authentication.JWTAuthentication", |         "rest_framework_simplejwt.authentication.JWTAuthentication", | ||||||
|     ), |     ), | ||||||
|     "DEFAULT_PERMISSION_CLASSES": ("rest_framework.permissions.AllowAny",), |     "DEFAULT_PERMISSION_CLASSES": ("rest_framework.permissions.AllowAny",), | ||||||
|  |     "DATETIME_FORMAT": "%Y-%m-%dT%H:%M:%S.%fZ", | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| # STATIC | # STATIC | ||||||
|  |  | ||||||
							
								
								
									
										0
									
								
								app/events/api/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								app/events/api/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										32
									
								
								app/events/api/serializers.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								app/events/api/serializers.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,32 @@ | ||||||
|  | from rest_framework import serializers | ||||||
|  | 
 | ||||||
|  | from events.models import Event | ||||||
|  | from users.api.serializers import UserSerializer | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class EventSerializer(serializers.ModelSerializer): | ||||||
|  |     creator = UserSerializer(many=False, read_only=True) | ||||||
|  | 
 | ||||||
|  |     class Meta: | ||||||
|  |         model = Event | ||||||
|  |         fields = [ | ||||||
|  |             "name", | ||||||
|  |             "about", | ||||||
|  |             "slug", | ||||||
|  |             "creator", | ||||||
|  |             "starts", | ||||||
|  |             "image", | ||||||
|  |             "planning", | ||||||
|  |             "attended", | ||||||
|  |         ] | ||||||
|  |         extra_kwargs = { | ||||||
|  |             "slug": {"read_only": True}, | ||||||
|  |             "creator": {"read_only": True}, | ||||||
|  |             "planning": {"read_only": True}, | ||||||
|  |             "attended": {"read_only": True}, | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |     def create(self, validated_data): | ||||||
|  |         return Event.objects.create( | ||||||
|  |             **validated_data, creator=self.context["request"].user | ||||||
|  |         ) | ||||||
							
								
								
									
										34
									
								
								app/events/api/views.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								app/events/api/views.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,34 @@ | ||||||
|  | from datetime import datetime | ||||||
|  | 
 | ||||||
|  | import pytz | ||||||
|  | from rest_framework import generics | ||||||
|  | from rest_framework.generics import get_object_or_404 | ||||||
|  | from rest_framework.parsers import FormParser, MultiPartParser | ||||||
|  | from rest_framework.permissions import IsAuthenticated | ||||||
|  | 
 | ||||||
|  | from common.permissions import IsManager | ||||||
|  | from events.api.serializers import EventSerializer | ||||||
|  | from events.models import Event | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class ListCreateEventApi(generics.ListCreateAPIView): | ||||||
|  |     serializer_class = EventSerializer | ||||||
|  |     parser_classes = [FormParser, MultiPartParser] | ||||||
|  |     permission_classes = [IsAuthenticated, IsManager] | ||||||
|  |     queryset = Event.objects.filter( | ||||||
|  |         starts__gte=datetime.now(pytz.timezone("Europe/Moscow")) | ||||||
|  |     ) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class RetireUpdateDeleteEventApi(generics.RetrieveUpdateDestroyAPIView): | ||||||
|  |     def get_object(self): | ||||||
|  |         event = get_object_or_404( | ||||||
|  |             Event, | ||||||
|  |             slug=self.request.parser_context["kwargs"]["slug"], | ||||||
|  |         ) | ||||||
|  |         return event | ||||||
|  | 
 | ||||||
|  |     serializer_class = EventSerializer | ||||||
|  |     parser_classes = [FormParser, MultiPartParser] | ||||||
|  |     permission_classes = [IsAuthenticated, IsManager] | ||||||
|  |     queryset = Event.objects.all() | ||||||
|  | @ -2,5 +2,8 @@ from django.apps import AppConfig | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class EventsConfig(AppConfig): | class EventsConfig(AppConfig): | ||||||
|     default_auto_field = 'django.db.models.BigAutoField' |     default_auto_field = "django.db.models.BigAutoField" | ||||||
|     name = 'events' |     name = "events" | ||||||
|  | 
 | ||||||
|  |     def ready(self): | ||||||
|  |         import events.signals | ||||||
|  |  | ||||||
							
								
								
									
										45
									
								
								app/events/migrations/0001_initial.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								app/events/migrations/0001_initial.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,45 @@ | ||||||
|  | # Generated by Django 4.0.8 on 2022-10-08 15:44 | ||||||
|  | 
 | ||||||
|  | from django.conf import settings | ||||||
|  | from django.db import migrations, models | ||||||
|  | import django.db.models.deletion | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class Migration(migrations.Migration): | ||||||
|  | 
 | ||||||
|  |     initial = True | ||||||
|  | 
 | ||||||
|  |     dependencies = [ | ||||||
|  |         migrations.swappable_dependency(settings.AUTH_USER_MODEL), | ||||||
|  |     ] | ||||||
|  | 
 | ||||||
|  |     operations = [ | ||||||
|  |         migrations.CreateModel( | ||||||
|  |             name='Event', | ||||||
|  |             fields=[ | ||||||
|  |                 ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | ||||||
|  |                 ('name', models.CharField(max_length=100)), | ||||||
|  |                 ('slug', models.SlugField(max_length=8)), | ||||||
|  |                 ('about', models.TextField(blank=True)), | ||||||
|  |                 ('starts', models.DateTimeField()), | ||||||
|  |                 ('image', models.ImageField(blank=True, upload_to='uploads/')), | ||||||
|  |                 ('image_cropped', models.ImageField(blank=True, upload_to='cropped/')), | ||||||
|  |                 ('planning', models.IntegerField(default=0)), | ||||||
|  |                 ('attended', models.IntegerField(default=0)), | ||||||
|  |                 ('creator', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='events_created', to=settings.AUTH_USER_MODEL)), | ||||||
|  |             ], | ||||||
|  |             options={ | ||||||
|  |                 'ordering': ['-starts'], | ||||||
|  |             }, | ||||||
|  |         ), | ||||||
|  |         migrations.CreateModel( | ||||||
|  |             name='EventAttendance', | ||||||
|  |             fields=[ | ||||||
|  |                 ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | ||||||
|  |                 ('token', models.CharField(max_length=128, unique=True)), | ||||||
|  |                 ('attended', models.BooleanField(default=False)), | ||||||
|  |                 ('event', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='people', to='events.event')), | ||||||
|  |                 ('worker', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='events', to=settings.AUTH_USER_MODEL)), | ||||||
|  |             ], | ||||||
|  |         ), | ||||||
|  |     ] | ||||||
|  | @ -1,3 +1,36 @@ | ||||||
| from django.db import models | from django.db import models | ||||||
| 
 | 
 | ||||||
| # Create your models here. | from users.models import User | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class Event(models.Model): | ||||||
|  |     name = models.CharField(max_length=100) | ||||||
|  |     slug = models.SlugField(max_length=8) | ||||||
|  |     about = models.TextField(blank=True) | ||||||
|  | 
 | ||||||
|  |     creator = models.ForeignKey( | ||||||
|  |         User, related_name="events_created", on_delete=models.CASCADE | ||||||
|  |     ) | ||||||
|  |     starts = models.DateTimeField(blank=False) | ||||||
|  | 
 | ||||||
|  |     image = models.ImageField(upload_to="uploads/", blank=True) | ||||||
|  |     image_cropped = models.ImageField(upload_to="cropped/", blank=True) | ||||||
|  | 
 | ||||||
|  |     planning = models.IntegerField(default=0) | ||||||
|  |     attended = models.IntegerField(default=0) | ||||||
|  | 
 | ||||||
|  |     def __str__(self): | ||||||
|  |         return self.name | ||||||
|  | 
 | ||||||
|  |     class Meta: | ||||||
|  |         ordering = ["-starts"] | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class EventAttendance(models.Model): | ||||||
|  |     event = models.ForeignKey(Event, related_name="people", on_delete=models.CASCADE) | ||||||
|  |     worker = models.ForeignKey(User, related_name="events", on_delete=models.CASCADE) | ||||||
|  |     token = models.CharField(blank=False, unique=True, max_length=128) | ||||||
|  |     attended = models.BooleanField(default=False) | ||||||
|  | 
 | ||||||
|  |     def __str__(self): | ||||||
|  |         return f"{self.worker.name} attendance on {self.event.name}" | ||||||
|  |  | ||||||
							
								
								
									
										13
									
								
								app/events/services.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								app/events/services.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,13 @@ | ||||||
|  | from rest_framework.generics import get_object_or_404 | ||||||
|  | 
 | ||||||
|  | from events.models import EventAttendance | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | def submit_attendance(token: str): | ||||||
|  |     attendance = get_object_or_404(EventAttendance, token=token) | ||||||
|  |     if not attendance.attended: | ||||||
|  |         attendance.attended = True | ||||||
|  |         attendance.save() | ||||||
|  | 
 | ||||||
|  |         attendance.event.attended += 1 | ||||||
|  |         attendance.event.save() | ||||||
							
								
								
									
										41
									
								
								app/events/signals.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								app/events/signals.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,41 @@ | ||||||
|  | from django.core.files import File | ||||||
|  | from django.db.models.signals import pre_save, post_delete, post_save | ||||||
|  | from django.dispatch import receiver | ||||||
|  | 
 | ||||||
|  | from utils.file import crop_image | ||||||
|  | from utils.generators import generate_charset | ||||||
|  | from .models import EventAttendance, Event | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @receiver(pre_save, sender=EventAttendance) | ||||||
|  | def create_attendance(sender, instance, **kwargs): | ||||||
|  |     token = generate_charset(25) | ||||||
|  |     while EventAttendance.objects.filter(token=token).exists(): | ||||||
|  |         token = generate_charset(25) | ||||||
|  |     instance.token = token | ||||||
|  | 
 | ||||||
|  |     instance.event.planning += 1 | ||||||
|  |     instance.event.save(update_fileds=["planning"]) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @receiver(post_save, sender=Event) | ||||||
|  | def process_event(sender, instance, created, **kwargs): | ||||||
|  |     if created: | ||||||
|  |         slug = generate_charset(5) | ||||||
|  |         while Event.objects.filter(slug=slug).exists(): | ||||||
|  |             slug = generate_charset(5) | ||||||
|  |         instance.slug = slug | ||||||
|  |         instance.save(update_fields=["slug"]) | ||||||
|  | 
 | ||||||
|  |     if instance.image and kwargs["update_fields"] is None: | ||||||
|  |         instance.image_cropped = File( | ||||||
|  |             crop_image(instance.image.path, cut_to=(250, 250)), | ||||||
|  |             name=instance.image.path.split(".")[0].split("/")[-1] + ".png", | ||||||
|  |         ) | ||||||
|  |         instance.save(update_fields=["image_cropped"]) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | @receiver(post_delete, sender=EventAttendance) | ||||||
|  | def delete_attendance(sender, instance, **kwargs): | ||||||
|  |     instance.event.planning -= 1 | ||||||
|  |     instance.event.save(update_fileds=["planning"]) | ||||||
|  | @ -1,3 +0,0 @@ | ||||||
| from django.shortcuts import render |  | ||||||
| 
 |  | ||||||
| # Create your views here. |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user