added full event logic, fixed clan creation, minor changes

This commit is contained in:
Alexander Karpov 2022-10-09 00:42:30 +03:00
parent 8beee17e31
commit 12f81dbf3f
12 changed files with 218 additions and 53 deletions

View File

@ -1,18 +1,26 @@
from django.urls import path, include
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView
from events.api.views import ListCreateEventApi, RetireUpdateDeleteEventApi
from marketplace.api.views import ListCreateProductApi, RetireUpdateDestroyProductApi
from events.api.views import (
ListCreateEventApi,
RetrieveUpdateDeleteEventApi,
ListPlannedEvents,
RetrieveSubmitDeleteEventAttendance,
ListAttendedWorkersApi,
SubmitWorkerAttendedEvent,
)
from marketplace.api.views import ListCreateProductApi, RetrieveUpdateDestroyProductApi
from users.api.views import (
ListCreateUserApi,
RetireUpdateDeleteUserApi,
RetrieveUpdateDeleteUserApi,
ListCreateDepartmentApi,
RetireUpdateDeleteDepartmentApi,
RetrieveUpdateDeleteDepartmentApi,
ListCreateStreamApi,
RetireUpdateDeleteStreamApi,
RetrieveUpdateDeleteStreamApi,
ListCreateCommandApi,
RetireUpdateDeleteCommandApi,
RetrieveUpdateDeleteCommandApi,
CreateSeasonApi,
ListClansApiView,
)
urlpatterns = [
@ -32,9 +40,29 @@ urlpatterns = [
path("", ListCreateEventApi.as_view(), name="list_create_event"),
path(
"<str:slug>",
RetireUpdateDeleteEventApi.as_view(),
RetrieveUpdateDeleteEventApi.as_view(),
name="get_update_delete_event",
),
path(
"attendance/",
ListPlannedEvents.as_view(),
name="list_event_attendance",
),
path(
"attendance/<str:slug>/list/",
ListAttendedWorkersApi.as_view(),
name="list_event_attendance",
),
path(
"attendance/<str:slug>/submit/",
SubmitWorkerAttendedEvent.as_view(),
name="submit_event_attendance",
),
path(
"attendance/<str:slug>",
RetrieveSubmitDeleteEventAttendance.as_view(),
name="get_submit_delete_event_attendance",
),
]
),
),
@ -49,7 +77,7 @@ urlpatterns = [
),
path(
"product/<str:slug>",
RetireUpdateDestroyProductApi.as_view(),
RetrieveUpdateDestroyProductApi.as_view(),
name="get_update_destroy_product",
),
]
@ -62,7 +90,7 @@ urlpatterns = [
path("", ListCreateUserApi.as_view(), name="list_create_user"),
path(
"<str:username>",
RetireUpdateDeleteUserApi.as_view(),
RetrieveUpdateDeleteUserApi.as_view(),
name="get_update_delete_user",
),
path(
@ -77,7 +105,7 @@ urlpatterns = [
),
path(
"department/<int:pk>",
RetireUpdateDeleteDepartmentApi.as_view(),
RetrieveUpdateDeleteDepartmentApi.as_view(),
name="get_update_delete_department",
),
path(
@ -87,7 +115,7 @@ urlpatterns = [
),
path(
"stream/<int:pk>",
RetireUpdateDeleteStreamApi.as_view(),
RetrieveUpdateDeleteStreamApi.as_view(),
name="get_update_delete_stream",
),
path(
@ -97,7 +125,7 @@ urlpatterns = [
),
path(
"command/<int:pk>",
RetireUpdateDeleteCommandApi.as_view(),
RetrieveUpdateDeleteCommandApi.as_view(),
name="get_update_delete_command",
),
]
@ -105,6 +133,11 @@ urlpatterns = [
),
path(
"season/",
include([path("", CreateSeasonApi.as_view(), name="create new season")]),
include(
[
path("", CreateSeasonApi.as_view(), name="create new season"),
path("clans/", ListClansApiView.as_view()),
]
),
),
]

View File

@ -62,7 +62,7 @@ DJANGO_APPS = [
]
THIRD_PARTY_APPS = ["rest_framework", "corsheaders", "django_celery_beat", "drf_yasg"]
LOCAL_APPS = ["users", "marketplace", "events"]
LOCAL_APPS = ["users", "marketplace", "events", "blockchain"]
# https://docs.djangoproject.com/en/dev/ref/settings/#installed-apps
INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + LOCAL_APPS

View File

@ -1,7 +1,9 @@
from rest_framework import serializers
from rest_framework.generics import get_object_or_404
from events.models import Event
from events.models import Event, EventAttendance
from users.api.serializers import UserSerializer
from users.models import User
class EventSerializer(serializers.ModelSerializer):
@ -30,3 +32,45 @@ class EventSerializer(serializers.ModelSerializer):
return Event.objects.create(
**validated_data, creator=self.context["request"].user
)
class EventAttendanceSerializer(serializers.ModelSerializer):
class Meta:
model = EventAttendance
fields = ["id", "event_slug", "worker_username", "attended"]
extra_kwargs = {
"id": {"read_only": True},
"event_slug": {"read_only": True},
"worker_username": {"read_only": True},
"attended": {"read_only": True},
}
def create(self, validated_data):
return EventAttendance.objects.get_or_create(
worker=self.context["request"].user,
event=get_object_or_404(
Event, slug=self.context["request"].parser_context["kwargs"]["slug"]
),
)[0]
class SubmitUserAttendedSerializer(serializers.Serializer):
username = serializers.CharField(max_length=200)
def create(self, validated_data):
event = get_object_or_404(
Event, slug=self.context["request"].parser_context["kwargs"]["slug"]
)
ea = EventAttendance.objects.get_or_create(
event=event,
worker=get_object_or_404(User, username=validated_data["username"]),
)[0]
if not ea.attended:
ea.attended = True
ea.save()
ea.event.attended += 1
ea.event.save()
return ea
def update(self, instance, validated_data):
pass

View File

@ -2,13 +2,19 @@ from datetime import datetime
import pytz
from rest_framework import generics
from rest_framework.exceptions import NotFound
from rest_framework.generics import get_object_or_404
from rest_framework.parsers import FormParser, MultiPartParser
from rest_framework.permissions import IsAuthenticated
from rest_framework.views import APIView
from common.permissions import IsManager
from events.api.serializers import EventSerializer
from events.models import Event
from common.permissions import IsManager, IsWorker
from events.api.serializers import (
EventSerializer,
EventAttendanceSerializer,
SubmitUserAttendedSerializer,
)
from events.models import Event, EventAttendance
class ListCreateEventApi(generics.ListCreateAPIView):
@ -20,7 +26,7 @@ class ListCreateEventApi(generics.ListCreateAPIView):
)
class RetireUpdateDeleteEventApi(generics.RetrieveUpdateDestroyAPIView):
class RetrieveUpdateDeleteEventApi(generics.RetrieveUpdateDestroyAPIView):
def get_object(self):
event = get_object_or_404(
Event,
@ -32,3 +38,51 @@ class RetireUpdateDeleteEventApi(generics.RetrieveUpdateDestroyAPIView):
parser_classes = [FormParser, MultiPartParser]
permission_classes = [IsAuthenticated, IsManager]
queryset = Event.objects.all()
class RetrieveSubmitDeleteEventAttendance(
generics.CreateAPIView, generics.RetrieveDestroyAPIView
):
"""Gets/Submits/Deletes that user is planing to go on event. Only works for worker"""
def get_object(self):
event = get_object_or_404(
Event,
slug=self.request.parser_context["kwargs"]["slug"],
)
if EventAttendance.objects.filter(
event=event, worker=self.request.user
).exists():
return EventAttendance.objects.get(event=event, worker=self.request.user)
raise NotFound
serializer_class = EventAttendanceSerializer
permission_classes = [IsAuthenticated, IsWorker]
class ListPlannedEvents(generics.ListAPIView):
"""Lists events that worker is planning to attend. Only works for worker"""
def get_queryset(self):
return self.request.user.events.filter(
attended=False,
event__starts__gte=datetime.now(pytz.timezone("Europe/Moscow")),
)
serializer_class = EventAttendanceSerializer
permission_classes = [IsAuthenticated, IsWorker]
class ListAttendedWorkersApi(generics.ListAPIView):
def get_queryset(self):
return EventAttendance.objects.filter(
event__slug=self.request.parser_context["kwargs"]["slug"]
)
serializer_class = EventAttendanceSerializer
permission_classes = [IsAuthenticated, IsManager]
class SubmitWorkerAttendedEvent(generics.CreateAPIView):
serializer_class = SubmitUserAttendedSerializer
permission_classes = [IsAuthenticated, IsManager]

View File

@ -32,5 +32,20 @@ class EventAttendance(models.Model):
token = models.CharField(blank=False, unique=True, max_length=128)
attended = models.BooleanField(default=False)
@property
def event_slug(self):
return self.event.slug
@property
def worker_username(self):
return self.worker.username
def username(self):
return self.worker_username
def __str__(self):
return f"{self.worker.name} attendance on {self.event.name}"
class Meta:
ordering = ["event__starts"]
unique_together = ["event", "worker"]

View File

@ -7,15 +7,16 @@ 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():
@receiver(post_save, sender=EventAttendance)
def create_attendance(sender, instance, created, **kwargs):
if created:
token = generate_charset(25)
instance.token = token
while EventAttendance.objects.filter(token=token).exists():
token = generate_charset(25)
instance.token = token
instance.event.planning += 1
instance.event.save(update_fileds=["planning"])
instance.event.planning += 1
instance.event.save(update_fields=["planning", "token"])
@receiver(post_save, sender=Event)
@ -38,4 +39,4 @@ def process_event(sender, instance, created, **kwargs):
@receiver(post_delete, sender=EventAttendance)
def delete_attendance(sender, instance, **kwargs):
instance.event.planning -= 1
instance.event.save(update_fileds=["planning"])
instance.event.save(update_fields=["planning"])

View File

@ -15,7 +15,7 @@ class ListCreateProductApi(generics.ListCreateAPIView):
queryset = Product.objects.all()
class RetireUpdateDestroyProductApi(generics.RetrieveUpdateDestroyAPIView):
class RetrieveUpdateDestroyProductApi(generics.RetrieveUpdateDestroyAPIView):
serializer_class = ProductSerializer
parser_classes = [FormParser, MultiPartParser]
permission_classes = [IsAuthenticated, IsManager]

View File

@ -1,6 +1,6 @@
from rest_framework import serializers
from ..services import create_season
from users.models import User
from users.models import User, Clan
from users.models import User, Department, Stream, Command
@ -18,10 +18,12 @@ class UserSerializer(serializers.ModelSerializer):
"wallet_public_key",
"command",
"department",
"clan_name",
]
extra_kwargs = {
"password": {"write_only": True},
"wallet_public_key": {"read_only": True},
"clan_name": {"read_only": True},
"department": {"read_only": True},
}
@ -34,9 +36,10 @@ class UserSerializer(serializers.ModelSerializer):
class CreateSeasonSerializer(serializers.Serializer):
created = serializers.BooleanField(read_only=True)
def create(self, *args, **kwargs):
create_season()
return {'created': True}
return {"created": True}
class CommandSerializer(serializers.ModelSerializer):
@ -75,3 +78,11 @@ class DepartmentSerializer(serializers.ModelSerializer):
"id": {"read_only": True},
"streams": {"read_only": True},
}
class ClanSerializer(serializers.ModelSerializer):
users = UserSerializer(many=True)
class Meta:
model = Clan
fields = ["name", "users"]

View File

@ -3,14 +3,15 @@ from rest_framework.generics import get_object_or_404
from rest_framework.permissions import IsAuthenticated
from common.permissions import IsAdmin
from users.api.serializers import CreateSeasonSerializer
from users.api.serializers import (
UserSerializer,
DepartmentSerializer,
StreamSerializer,
CommandSerializer,
CreateSeasonSerializer,
ClanSerializer,
)
from users.models import User, Department, Stream, Command
from users.models import User, Department, Stream, Command, Clan
class ListCreateUserApi(generics.ListCreateAPIView):
@ -24,7 +25,7 @@ class CreateSeasonApi(generics.CreateAPIView):
# permission_classes = [IsAuthenticated, IsAdmin]
class RetireUpdateDeleteUserApi(generics.RetrieveUpdateDestroyAPIView):
class RetrieveUpdateDeleteUserApi(generics.RetrieveUpdateDestroyAPIView):
def get_object(self):
user = get_object_or_404(
User,
@ -43,7 +44,7 @@ class ListCreateDepartmentApi(generics.ListCreateAPIView):
queryset = Department.objects.all()
class RetireUpdateDeleteDepartmentApi(generics.RetrieveUpdateDestroyAPIView):
class RetrieveUpdateDeleteDepartmentApi(generics.RetrieveUpdateDestroyAPIView):
lookup_field = "pk"
serializer_class = DepartmentSerializer
permission_classes = [IsAuthenticated, IsAdmin]
@ -55,7 +56,7 @@ class ListCreateStreamApi(ListCreateDepartmentApi):
queryset = Stream.objects.all()
class RetireUpdateDeleteStreamApi(RetireUpdateDeleteDepartmentApi):
class RetrieveUpdateDeleteStreamApi(RetrieveUpdateDeleteDepartmentApi):
serializer_class = StreamSerializer
queryset = Stream.objects.all()
@ -65,6 +66,12 @@ class ListCreateCommandApi(ListCreateDepartmentApi):
queryset = Command.objects.all()
class RetireUpdateDeleteCommandApi(RetireUpdateDeleteDepartmentApi):
class RetrieveUpdateDeleteCommandApi(RetrieveUpdateDeleteDepartmentApi):
serializer_class = CommandSerializer
queryset = Command.objects.all()
class ListClansApiView(generics.ListAPIView):
serializer_class = ClanSerializer
queryset = Clan.objects.all()
permission_classes = [IsAuthenticated, IsAdmin]

View File

@ -22,7 +22,7 @@ class User(AbstractUser):
type = models.CharField(
max_length=6, choices=WorkerType.choices, default=WorkerType.WORKER
)
clan = models.ForeignKey("users.Clan", on_delete=models.SET_NULL, null=True)
clan = models.ForeignKey("users.Clan", related_name="users", on_delete=models.SET_NULL, null=True)
command = models.ForeignKey(
"users.Command", related_name="workers", on_delete=models.CASCADE
)
@ -47,6 +47,10 @@ class User(AbstractUser):
def department(self):
return self.command.stream.department.name
@property
def clan_name(self):
return self.clan.name
class Meta:
ordering = ["-id"]

View File

@ -12,10 +12,10 @@ def end_season():
mx_value = -1
mx_clan = None
for clan in Clan.objects.all():
if sum(map(lambda user: user.respect, clan.user_set.all())) > mx_value:
mx_value = sum(map(lambda user: user.respect, clan.user_set.all()))
if sum(map(lambda user: user.respect, clan.users.all())) > mx_value:
mx_value = sum(map(lambda user: user.respect, clan.users.all()))
mx_clan = clan
for user in mx_clan.user_set.all():
for user in mx_clan.users.all():
transfer_rubbles(
settings.MAIN_WALLET,
user.wallet_public_key,
@ -25,7 +25,7 @@ def end_season():
def create_chat(clan: Clan):
user_list = list(map(lambda user: user.telegram, clan.user_set.all()))
user_list = list(map(lambda user: user.telegram, clan.users.all()))
if len(user_list):
r.post(
f"{settings.TELEGRAM_API}/create-chat",
@ -38,15 +38,13 @@ def create_season():
if len(Clan.objects.all()):
end_season()
users = list(User.objects.all())
users = list(User.objects.filter(type=User.WorkerType.WORKER))
shuffle(users)
clan = None
for index, user in enumerate(users):
if (index % 10 == 0) or (index == len(users) - 1):
if clan is not None:
create_chat(clan)
if index % 5 == 0:
clan = Clan.objects.create()
user.clan = clan
user.save()
if len(users) % 10 != 0:
for clan in Clan.objects.all():
create_chat(clan)

View File

@ -5,15 +5,13 @@ from users.models import User
from utils.blockchain import create_wallet
@receiver(pre_save, sender=User)
def create_user(sender, instance, **kwargs):
wallet = create_wallet()
instance.wallet_public_key = wallet.publicKey
instance.wallet_private_key = wallet.privateKey
@receiver(post_save, sender=User)
def process_user(sender, instance, created, **kwargs):
if created:
instance.set_password(instance.password)
wallet = create_wallet()
instance.wallet_public_key = wallet.publicKey
instance.wallet_private_key = wallet.privateKey
instance.save()