diff --git a/api/common/common_consumer.py b/api/common/common_consumer.py index 996daf30..86a3e627 100644 --- a/api/common/common_consumer.py +++ b/api/common/common_consumer.py @@ -5,6 +5,9 @@ from django.db.models import Count from django.db.models.functions import Coalesce +from channels.generic.websocket import WebsocketConsumer +from asgiref.sync import async_to_sync + from db.learning_circle import LearningCircle from db.learning_circle import UserCircleLink from db.organization import Organization @@ -12,103 +15,110 @@ from db.user import User, UserRoleLink from utils.types import IntegrationType, OrganizationType -from utils.baseconsumer import BaseConsumer - -class GlobalCount(BaseConsumer): - def receive(self, text_data): - if json.loads(text_data)['type'] == 'global_count': - org_type_counts = Organization.objects.filter( +class GlobalCount(WebsocketConsumer): + data = {} + group_name = "landing_stats" + + def connect(self): + async_to_sync(self.channel_layer.group_add)( + self.group_name, + self.channel_name + ) + self.accept() + + self.data = { + 'members': self.members_count, + 'org_type_counts': self.org_type_counts, + 'enablers_mentors_count': self.enablers_mentors_count, + 'ig_count': self.interest_groups_count, + 'learning_circle_count': self.learning_circles_count + } + + self.send(text_data=json.dumps(self.data)) + + def disconnect(self, code): + self.channel_layer.group_discard(self.group_name, self.channel_name) + + @property + def members_count(self): + members_count = User.objects.all().count() + return members_count + + @property + def org_type_counts(self): + org_type_counts = Organization.objects.filter( org_type__in=[OrganizationType.COLLEGE.value, OrganizationType.COMPANY.value, OrganizationType.COMMUNITY.value] ).values('org_type').annotate(org_count=Coalesce(Count('org_type'), 0)) - org_type_counts = list(org_type_counts) - - enablers_mentors_count = UserRoleLink.objects.filter( - role__title__in=["Mentor", "Enabler"]).values( - 'role__title').annotate(role_count=Coalesce(Count('role__title'), 0)) - enablers_mentors_count = list(enablers_mentors_count) - - interest_groups_count = InterestGroup.objects.all().count() - learning_circles_count = LearningCircle.objects.all().count() - members_count = User.objects.all().count() - - data = { - 'members': members_count, - 'org_type_counts': org_type_counts, - 'enablers_mentors_count': enablers_mentors_count, - 'ig_count': interest_groups_count, - 'learning_circle_count': learning_circles_count - } - - self.send(text_data=json.dumps(data)) + org_type_counts = list(org_type_counts) + + return org_type_counts + + @property + def enablers_mentors_count(self): + enablers_mentors_count = UserRoleLink.objects.filter( + role__title__in=["Mentor", "Enabler"]).values( + 'role__title').annotate(role_count=Coalesce(Count('role__title'), 0)) + enablers_mentors_count = list(enablers_mentors_count) + + return enablers_mentors_count + + @property + def interest_groups_count(self): + interest_groups_count = InterestGroup.objects.all().count() + return interest_groups_count + + @property + def learning_circles_count(self): + learning_circles_count = LearningCircle.objects.all().count() + return learning_circles_count + + def get_based_on_sender(self, sender): + if sender == User: + self.data['members'] = self.members_count + + elif sender == Organization: + self.data['org_type_counts'] = self.org_type_counts + + elif sender == UserRoleLink: + self.data['enablers_mentors_count'] = self.enablers_mentors_count + + elif sender == InterestGroup: + self.data['ig_count'] = self.interest_groups_count + + elif sender == LearningCircle: + self.data['learning_circle_count'] = self.learning_circles_count + def receive(self, text_data): + @receiver(post_save, sender=User) @receiver(post_save, sender=LearningCircle) @receiver(post_save, sender=InterestGroup) @receiver(post_save, sender=UserRoleLink) @receiver(post_save, sender=Organization) - def user_post_save(sender, instance, created, **kwargs): - data = {} - - if created: - if sender == User: - count = User.objects.all().count() - data['members'] = count - - elif sender == LearningCircle: - count = LearningCircle.objects.all().count() - data['learning_circle_count'] = count - - elif sender == InterestGroup: - count = InterestGroup.objects.all().count() - data['ig_count'] = count - - elif sender == UserRoleLink: - count = UserRoleLink.objects.filter( - role__title__in=["Mentor", "Enabler"]).values( - 'role__title').annotate(role_count=Coalesce(Count('role__title'), 0)) - data['enablers_mentors_count'] = list(count) - - elif sender == Organization: - count = Organization.objects.filter( - org_type__in=[OrganizationType.COLLEGE.value, OrganizationType.COMPANY.value, - OrganizationType.COMMUNITY.value] - ).values('org_type').annotate(org_count=Coalesce(Count('org_type'), 0)) - data['org_type_counts'] = list(count) - - self.send(text_data=json.dumps(data)) - @receiver(post_delete, sender=User) @receiver(post_delete, sender=LearningCircle) @receiver(post_delete, sender=InterestGroup) - def user_post_delete(sender, instance, created, **kwargs): - data = {} - - if sender == User: - count = User.objects.all().count() - data['members'] = count - - elif sender == LearningCircle: - count = LearningCircle.objects.all().count() - data['learning_circle_count'] = count - - elif sender == InterestGroup: - count = InterestGroup.objects.all().count() - data['ig_count'] = count - - elif sender == UserRoleLink: - count = UserRoleLink.objects.filter( - role__title__in=["Mentor", "Enabler"]).values( - 'role__title').annotate(role_count=Coalesce(Count('role__title'), 0)) - data['enablers_mentors_count'] = list(count) - - elif sender == Organization: - count = Organization.objects.filter( - org_type__in=[OrganizationType.COLLEGE.value, OrganizationType.COMPANY.value, - OrganizationType.COMMUNITY.value] - ).values('org_type').annotate(org_count=Coalesce(Count('org_type'), 0)) - data['org_type_counts'] = list(count) - - self.send(text_data=json.dumps(data)) + @receiver(post_delete, sender=UserRoleLink) + @receiver(post_delete, sender=Organization) + def db_signals(sender, instance, created=None, *args, **kwargs): + if created: + self.get_based_on_sender(sender) + async_to_sync(self.channel_layer.group_send)( + self.group_name, + {"type": "send_data", "data": self.data} + ) + + if created == None: + self.get_based_on_sender(sender) + async_to_sync(self.channel_layer.group_send)( + self.group_name, + {"type": "send_data", "data": self.data} + ) + + def send_data(self, event): + self.send(text_data=json.dumps(event['data'])) + + diff --git a/api/dashboard/campus/serializers.py b/api/dashboard/campus/serializers.py index f3a774ae..b3e62450 100644 --- a/api/dashboard/campus/serializers.py +++ b/api/dashboard/campus/serializers.py @@ -39,7 +39,6 @@ def get_active_members(self, obj): last_month = DateTimeUtils.get_current_utc_time() - timedelta(days=30) return obj.org.user_organization_link_org.filter( verified=True, - user__active=True, user__wallet_user__isnull=False, user__wallet_user__created_at__gte=last_month, ).count() diff --git a/api/dashboard/karma_voucher/assets/base_template.xlsx b/api/dashboard/karma_voucher/assets/voucher_base_template.xlsx similarity index 100% rename from api/dashboard/karma_voucher/assets/base_template.xlsx rename to api/dashboard/karma_voucher/assets/voucher_base_template.xlsx diff --git a/api/dashboard/karma_voucher/karma_voucher_view.py b/api/dashboard/karma_voucher/karma_voucher_view.py index 33a3ff8d..e6fb7cef 100644 --- a/api/dashboard/karma_voucher/karma_voucher_view.py +++ b/api/dashboard/karma_voucher/karma_voucher_view.py @@ -332,7 +332,7 @@ class VoucherBaseTemplateAPI(APIView): authentication_classes = [CustomizePermission] def get(self, request): - wb = load_workbook('./api/dashboard/karma_voucher/assets/base_template.xlsx') + wb = load_workbook('./api/dashboard/karma_voucher/assets/voucher_base_template.xlsx') ws = wb['Data Definitions'] hashtags = TaskList.objects.all().values_list('hashtag', flat=True) data = { @@ -352,4 +352,4 @@ def get(self, request): with open(tmp.name, 'rb') as f: f.seek(0) new_file_object = f.read() - return FileResponse(BytesIO(new_file_object), as_attachment=True, filename='base_template.xlsx') \ No newline at end of file + return FileResponse(BytesIO(new_file_object), as_attachment=True, filename='voucher_base_template.xlsx') \ No newline at end of file diff --git a/api/dashboard/lc/dash_lc_serializer.py b/api/dashboard/lc/dash_lc_serializer.py index e2f246cd..4d92d418 100644 --- a/api/dashboard/lc/dash_lc_serializer.py +++ b/api/dashboard/lc/dash_lc_serializer.py @@ -43,7 +43,59 @@ def get_member_count(self, obj): ).count() +class LearningCircleMainSerializer(serializers.ModelSerializer): + ig_name = serializers.CharField(source='ig.name') + member_count = serializers.SerializerMethodField() + members = serializers.SerializerMethodField() + lead_name = serializers.SerializerMethodField() + + class Meta: + model = LearningCircle + fields = [ + 'name', + 'ig_name', + 'member_count', + 'members', + 'meet_place', + 'meet_time', + 'lead_name' + ] + + def get_lead_name(self, obj): + user_circle_link = obj.user_circle_link_circle.filter( + circle=obj, + accepted=1, + lead=True + ).first() + + return user_circle_link.user.fullname if user_circle_link else None + + def get_member_count(self, obj): + return obj.user_circle_link_circle.filter( + circle=obj, + accepted=1 + ).count() + + def get_members(self, obj): + user_circle_link = obj.user_circle_link_circle.filter( + circle=obj, + accepted=1 + ) + return [ + { + 'username': f'{member.user.fullname}' + } + for member in user_circle_link + ] + + class LearningCircleCreateSerializer(serializers.ModelSerializer): + ig = serializers.CharField(required=True, error_messages={ + 'required': 'ig field must not be left blank.' + }) + name = serializers.CharField(required=True, error_messages={ + 'required': 'name field must not be left blank.'} + ) class Meta: model = LearningCircle @@ -53,6 +105,7 @@ class Meta: ] def validate(self, data): + user_id = self.context.get('user_id') ig_id = data.get('ig') @@ -141,6 +194,75 @@ def create(self, validated_data): return lc +class LearningCircleMemberListSerializer(serializers.ModelSerializer): + members = serializers.SerializerMethodField() + + class Meta: + model = LearningCircle + fields = [ + 'members', + ] + + def get_members(self, obj): + user_circle_link = obj.user_circle_link_circle.filter(circle=obj, accepted=True) + return [ + { + 'full_name': f'{member.user.fullname}', + 'discord_id': member.user.discord_id, + } + for member in user_circle_link + ] + + +class LearningCircleJoinSerializer(serializers.ModelSerializer): + class Meta: + model = UserCircleLink + fields = [] + + def create(self, validated_data): + user_id = self.context.get('user_id') + circle_id = self.context.get('circle_id') + no_of_entry = UserCircleLink.objects.filter( + circle_id=circle_id, + accepted=True + ).count() + + ig_id = LearningCircle.objects.get(pk=circle_id).ig_id + + if entry := UserCircleLink.objects.filter( + circle_id=circle_id, + user_id=user_id + ).first(): + + raise serializers.ValidationError( + "Cannot send another request at the moment" + ) + + if UserCircleLink.objects.filter( + user_id=user_id, + circle_id__ig_id=ig_id, + accepted=True + ).exists(): + + raise serializers.ValidationError( + "Already a member of learning circle with same interest group" + ) + + if no_of_entry >= 5: + raise serializers.ValidationError( + "Maximum member count reached" + ) + + validated_data['id'] = uuid.uuid4() + validated_data['user_id'] = user_id + validated_data['circle_id'] = circle_id + validated_data['lead'] = False + validated_data['accepted'] = None + validated_data['accepted_at'] = None + validated_data['created_at'] = DateTimeUtils.get_current_utc_time() + return UserCircleLink.objects.create(**validated_data) + + class LearningCircleHomeSerializer(serializers.ModelSerializer): college = serializers.CharField(source='org.title', allow_null=True) total_karma = serializers.SerializerMethodField() @@ -174,27 +296,19 @@ class Meta: def get_is_member(self, obj): user = self.context.get('user_id') - try: - if link := UserCircleLink.objects.get( - user=user, - circle=obj, - accepted=True - ): - return True - except UserCircleLink.DoesNotExist: - return False + return obj.user_circle_link_circle.filter( + user=user, + circle=obj, + accepted=True + ).exists() def get_is_lead(self, obj): user = self.context.get('user_id') - try: - if link := UserCircleLink.objects.get( - user=user, - circle=obj, - lead=True - ): - return True - except UserCircleLink.DoesNotExist: - return False + return obj.user_circle_link_circle.filter( + user=user, + circle=obj, + lead=True + ).exists() def get_total_karma(self, obj): return ( @@ -216,10 +330,12 @@ def get_pending_members(self, obj): return self._get_member_info(obj, accepted=None) def _get_member_info(self, obj, accepted): - members = UserCircleLink.objects.filter( + + members = obj.user_circle_link_circle.filter( circle=obj, accepted=accepted ) + member_info = [] for member in members: @@ -234,9 +350,7 @@ def _get_member_info(self, obj, accepted): member_info.append({ 'id': member.user.id, - 'username': f'{member.user.first_name} {member.user.last_name}' - if member.user.last_name - else member.user.first_name, + 'username': f'{member.user.fullname}', 'profile_pic': member.user.profile_pic or None, 'karma': total_ig_karma, 'is_lead': member.lead, @@ -302,33 +416,32 @@ def get_previous_meetings(self, obj): return previous_meetings -class LearningCircleJoinSerializer(serializers.ModelSerializer): +class LearningCircleDataSerializer(serializers.ModelSerializer): + interest_group = serializers.SerializerMethodField() + college = serializers.SerializerMethodField() + learning_circle = serializers.SerializerMethodField() + total_no_of_users = serializers.SerializerMethodField() + class Meta: - model = UserCircleLink - fields = [] + model = LearningCircle + fields = [ + "interest_group", + "college", + "learning_circle", + "total_no_of_users" + ] - def create(self, validated_data): - user_id = self.context.get('user_id') - circle_id = self.context.get('circle_id') - no_of_entry = UserCircleLink.objects.filter(circle_id=circle_id, accepted=True).count() - ig_id = LearningCircle.objects.get(pk=circle_id).ig_id - if entry := UserCircleLink.objects.filter( - circle_id=circle_id, user_id=user_id - ).first(): - raise serializers.ValidationError("Cannot send another request at the moment") - if UserCircleLink.objects.filter(user_id=user_id, circle_id__ig_id=ig_id, accepted=True).exists(): - raise serializers.ValidationError("Already a member of learning circle with same interest group") - if no_of_entry >= 5: - raise serializers.ValidationError("Maximum member count reached") + def get_interest_group(self, obj): + return obj.values('ig_id').distinct().count() - validated_data['id'] = uuid.uuid4() - validated_data['user_id'] = user_id - validated_data['circle_id'] = circle_id - validated_data['lead'] = False - validated_data['accepted'] = None - validated_data['accepted_at'] = None - validated_data['created_at'] = DateTimeUtils.get_current_utc_time() - return UserCircleLink.objects.create(**validated_data) + def get_total_no_of_users(self, obj): + return UserCircleLink.objects.all().count() + + def get_learning_circle(self, obj): + return obj.count() + + def get_college(self, obj): + return obj.values('org_id').distinct().count() class LearningCircleUpdateSerializer(serializers.ModelSerializer): @@ -391,108 +504,6 @@ def update(self, instance, validated_data): return instance -class LearningCircleMainSerializer(serializers.ModelSerializer): - ig_name = serializers.SerializerMethodField() - member_count = serializers.SerializerMethodField() - members = serializers.SerializerMethodField() - lead_name = serializers.SerializerMethodField() - - class Meta: - model = LearningCircle - fields = [ - 'name', - 'ig_name', - 'member_count', - 'members', - 'meet_place', - 'meet_time', - 'lead_name' - ] - - def get_lead_name(self, obj): - user_circle_link = UserCircleLink.objects.filter( - circle=obj, - accepted=1, - lead=True - ).first() - - if user_circle_link: - user = user_circle_link.user - return f'{user.first_name} {user.last_name}' - return None - - def get_ig_name(self, obj): - return obj.ig.name if obj.ig else None - - def get_member_count(self, obj): - return UserCircleLink.objects.filter( - circle=obj, - accepted=1 - ).count() - - def get_members(self, obj): - members = UserCircleLink.objects.filter( - circle=obj, - accepted=1 - ) - return [ - { - 'username': f'{member.user.first_name} {member.user.last_name}' - if member.user.last_name - else member.user.first_name, - } - for member in members - ] - - -class LearningCircleDataSerializer(serializers.ModelSerializer): - interest_group = serializers.SerializerMethodField() - college = serializers.SerializerMethodField() - learning_circle = serializers.SerializerMethodField() - total_no_of_users = serializers.SerializerMethodField() - - class Meta: - model = LearningCircle - fields = [ - "interest_group", - "college", - "learning_circle", - "total_no_of_users" - ] - - def get_total_no_of_users(self, obj): - return UserCircleLink.objects.all().count() - - def get_learning_circle(self, obj): - return LearningCircle.objects.all().count() - - def get_college(self, obj): - return LearningCircle.objects.values('org_id').distinct().count() - - def get_interest_group(self, obj): - return LearningCircle.objects.values('ig_id').distinct().count() - - -class LearningCircleMemberlistSerializer(serializers.ModelSerializer): - members = serializers.SerializerMethodField() - - class Meta: - model = LearningCircle - fields = [ - 'members', - ] - - def get_members(self, obj): - members = UserCircleLink.objects.filter(circle=obj, accepted=True) - return [ - { - 'full_name': f'{member.user.first_name} {member.user.last_name}' if member.user.last_name else member.user.first_name, - 'discord_id': member.user.discord_id, - } - for member in members - ] - - class MeetCreateEditDeleteSerializer(serializers.ModelSerializer): class Meta: diff --git a/api/dashboard/lc/dash_lc_view.py b/api/dashboard/lc/dash_lc_view.py index c6cdd00a..d1ce35a8 100644 --- a/api/dashboard/lc/dash_lc_view.py +++ b/api/dashboard/lc/dash_lc_view.py @@ -16,7 +16,7 @@ from .dash_lc_serializer import LearningCircleSerializer, LearningCircleCreateSerializer, LearningCircleHomeSerializer, \ LearningCircleUpdateSerializer, LearningCircleJoinSerializer, LearningCircleCreateEditDeleteSerializer, \ LearningCircleMainSerializer, LearningCircleNoteSerializer, LearningCircleDataSerializer, \ - LearningCircleMemberlistSerializer, MeetCreateEditDeleteSerializer + LearningCircleMemberListSerializer, MeetCreateEditDeleteSerializer domain = config("FR_DOMAIN_NAME") from_mail = config("FROM_MAIL") @@ -50,6 +50,109 @@ def get(self, request): # Lists user's learning circle ).get_success_response() +class LearningCircleMainApi(APIView): + def post(self, request): + all_circles = LearningCircle.objects.all() + ig_id = request.data.get('ig_id') + org_id = request.data.get('org_id') + district_id = request.data.get('district_id') + + if district_id: + all_circles = all_circles.filter(org__district_id=district_id) + + if org_id: + all_circles = all_circles.filter(org_id=org_id) + + if ig_id: + all_circles = all_circles.filter(ig_id=ig_id) + + if ig_id or org_id or district_id: + serializer = LearningCircleMainSerializer( + all_circles, + many=True + ) + else: + random_circles = all_circles.order_by('?')[:9] + + serializer = LearningCircleMainSerializer( + random_circles, + many=True + ) + + return CustomResponse( + response=serializer.data + ).get_success_response() + + +class LearningCircleDataAPI(APIView): + """ + API endpoint for retrieving basic data about all learning circles. + + Endpoint: /api/v1/dashboard/lc/data/ (GET) + + Returns: + CustomResponse: A custom response containing data about all learning circles. + """ + + def get(self, request): + learning_circle = LearningCircle.objects.all() + + serializer = LearningCircleDataSerializer( + learning_circle, + many=False + ) + + return CustomResponse( + response=serializer.data + ).get_success_response() + + +class LearningCircleCreateApi(APIView): + def post(self, request): + user_id = JWTUtils.fetch_user_id(request) + + serializer = LearningCircleCreateSerializer( + data=request.data, + context={ + 'user_id': user_id + } + ) + if serializer.is_valid(): + circle = serializer.save() + + return CustomResponse( + general_message='LearningCircle created successfully', + response={ + 'circle_id': circle.id + } + ).get_success_response() + + return CustomResponse( + message=serializer.errors + ).get_failure_response() + + +class LearningCircleListMembersApi(APIView): + def get(self, request, circle_id): + learning_circle = LearningCircle.objects.filter( + id=circle_id + ) + + if learning_circle is None: + return CustomResponse( + general_message='Learning Circle Not Exists' + ).get_failure_response() + + serializer = LearningCircleMemberListSerializer( + learning_circle, + many=True + ) + + return CustomResponse( + response=serializer.data + ).get_success_response() + + class TotalLearningCircleListApi(APIView): def post(self, request, circle_code=None): user_id = JWTUtils.fetch_user_id(request) @@ -98,39 +201,14 @@ def post(self, request, circle_code=None): ).get_success_response() -class LearningCircleCreateApi(APIView): - def post(self, request): - user_id = JWTUtils.fetch_user_id(request) - - serializer = LearningCircleCreateSerializer( - data=request.data, - context={ - 'user_id': user_id - } - ) - if serializer.is_valid(): - circle = serializer.save() - - return CustomResponse( - general_message='LearningCircle created successfully', - response={ - 'circle_id': circle.id - } - ).get_success_response() - - return CustomResponse( - message=serializer.errors - ).get_failure_response() - - class LearningCircleJoinApi(APIView): def post(self, request, circle_id): user_id = JWTUtils.fetch_user_id(request) user = User.objects.filter(id=user_id).first() - full_name = f'{user.first_name} {user.last_name}' if user.last_name else user.first_name + full_name = f'{user.fullname}' - lc = UserCircleLink.objects.filter( + user_learning_circle = UserCircleLink.objects.filter( circle_id=circle_id, lead=True ).first() @@ -144,10 +222,12 @@ def post(self, request, circle_id): ) if serializer.is_valid(): serializer.save() - lead_obj = User.objects.filter(id=lc.user.id).first() + user = User.objects.filter( + id=user_learning_circle.user.id + ).first() NotificationUtils.insert_notification( - user=lead_obj, + user=user, title="Member Request", description=f"{full_name} has requested to join your learning circle", button="LC", @@ -164,96 +244,6 @@ def post(self, request, circle_id): ).get_failure_response() -class MeetCreateEditDeleteAPI(APIView): - - def post(self, request, circle_id): - user_id = JWTUtils.fetch_user_id(request) - - serializer = MeetCreateEditDeleteSerializer( - data=request.data, - context={ - 'user_id': user_id, - 'circle_id': circle_id - } - ) - if serializer.is_valid(): - circle_meet_log = serializer.save() - - return CustomResponse( - general_message=f'Meet scheduled at {circle_meet_log.meet_time}' - ).get_success_response() - - return CustomResponse( - message=serializer.errors - ).get_failure_response() - - def patch(self, request, circle_id): - user_id = JWTUtils.fetch_user_id(request) - - learning_circle = LearningCircle.objects.filter( - id=circle_id - ).first() - - serializer = MeetCreateEditDeleteSerializer( - learning_circle, - data=request.data, - context={ - 'user_id': user_id - } - ) - if serializer.is_valid(): - serializer.save() - - return CustomResponse( - general_message='Meet updated successfully' - ).get_success_response() - - return CustomResponse( - message=serializer.errors - ).get_failure_response() - - -class LearningCircleLeadTransfer(APIView): - def patch(self, request, circle_id, lead_id): - user_id = JWTUtils.fetch_user_id(request) - - usr_circle_link = UserCircleLink.objects.filter( - circle__id=circle_id, - user__id=user_id - ).first() - - lead_circle_link = UserCircleLink.objects.filter( - circle__id=circle_id, - user__id=lead_id - ).first() - - if not LearningCircle.objects.filter( - id=circle_id - ).exists(): - - return CustomResponse( - general_message='Learning Circle not found' - ).get_failure_response() - - if usr_circle_link is None or usr_circle_link.lead != 1: - return CustomResponse( - general_message='User is not lead' - ).get_failure_response() - - if lead_circle_link is None: - return CustomResponse( - general_message='New lead not found in the circle' - ).get_failure_response() - - usr_circle_link.lead = None - lead_circle_link.lead = 1 - usr_circle_link.save() - lead_circle_link.save() - return CustomResponse( - general_message='Lead transferred successfully' - ).get_success_response() - - class LearningCircleHomeApi(APIView): def get(self, request, circle_id, member_id=None): user_id = JWTUtils.fetch_user_id(request) @@ -409,81 +399,115 @@ def delete(self, request, circle_id): return CustomResponse(general_message='Left').get_success_response() -class LearningCircleMainApi(APIView): - def post(self, request): - all_circles = LearningCircle.objects.all() - ig_id = request.data.get('ig_id') - org_id = request.data.get('org_id') - district_id = request.data.get('district_id') - - if district_id: - all_circles = all_circles.filter(org__district_id=district_id) +class MeetGetPostPatchDeleteAPI(APIView): - if org_id: - all_circles = all_circles.filter(org_id=org_id) - - if ig_id: - all_circles = all_circles.filter(ig_id=ig_id) - - if ig_id or org_id or district_id: - serializer = LearningCircleMainSerializer( - all_circles, - many=True - ) - else: - random_circles = all_circles.order_by('?')[:9] + def get(self, request, meet_id): - serializer = LearningCircleMainSerializer( - random_circles, - many=True - ) + circle_meeting_log = CircleMeetingLog.objects.filter( + id=meet_id + ).values( + "id", + "meet_time", + "meet_place", + "day", + "attendees", + "agenda", + meet_created_by=F("created_by__first_name"), + meet_created_at=F("created_at"), + meet_updated_by=F("updated_by__first_name"), + meet_updated_at=F("updated_at"), + ) return CustomResponse( - response=serializer.data + response=circle_meeting_log ).get_success_response() + def post(self, request, circle_id): + user_id = JWTUtils.fetch_user_id(request) -class LearningCircleDataAPI(APIView): - """ - API endpoint for retrieving basic data about all learning circles. + serializer = MeetCreateEditDeleteSerializer( + data=request.data, + context={ + 'user_id': user_id, + 'circle_id': circle_id + } + ) + if serializer.is_valid(): + circle_meet_log = serializer.save() - Endpoint: /api/v1/dashboard/lc/data/ (GET) + return CustomResponse( + general_message=f'Meet scheduled at {circle_meet_log.meet_time}' + ).get_success_response() - Returns: - CustomResponse: A custom response containing data about all learning circles. - """ + return CustomResponse( + message=serializer.errors + ).get_failure_response() - def get(self, request): - all_circles = LearningCircle.objects.all() + def patch(self, request, circle_id): + user_id = JWTUtils.fetch_user_id(request) - serializer = LearningCircleDataSerializer( - all_circles, - many=False + learning_circle = LearningCircle.objects.filter( + id=circle_id + ).first() + + serializer = MeetCreateEditDeleteSerializer( + learning_circle, + data=request.data, + context={ + 'user_id': user_id + } ) + if serializer.is_valid(): + serializer.save() + + return CustomResponse( + general_message='Meet updated successfully' + ).get_success_response() return CustomResponse( - response=serializer.data - ).get_success_response() + message=serializer.errors + ).get_failure_response() -class LearningCircleListMembersApi(APIView): - def get(self, request, circle_id): - learning_circle = LearningCircle.objects.filter( - id=circle_id - ) +class LearningCircleLeadTransfer(APIView): + def patch(self, request, circle_id, lead_id): + user_id = JWTUtils.fetch_user_id(request) + + user_circle_link = UserCircleLink.objects.filter( + circle__id=circle_id, + user__id=user_id + ).first() + + lead_circle_link = UserCircleLink.objects.filter( + circle__id=circle_id, + user__id=lead_id + ).first() + + if not LearningCircle.objects.filter( + id=circle_id + ).exists(): - if learning_circle is None: return CustomResponse( - general_message='Learning Circle Not Exists' + general_message='Learning Circle not found' ).get_failure_response() - serializer = LearningCircleMemberlistSerializer( - learning_circle, - many=True - ) + if user_circle_link is None or user_circle_link.lead != 1: + return CustomResponse( + general_message='User is not lead' + ).get_failure_response() + + if lead_circle_link is None: + return CustomResponse( + general_message='New lead not found in the circle' + ).get_failure_response() + + user_circle_link.lead = None + lead_circle_link.lead = 1 + user_circle_link.save() + lead_circle_link.save() return CustomResponse( - response=serializer.data + general_message='Lead transferred successfully' ).get_success_response() @@ -515,7 +539,7 @@ def post(self, request): return CustomResponse(general_message='User Invited').get_success_response() -class LearningCircleInviteMember(APIView): +class LearningCircleInviteMemberAPI(APIView): """ Invite a member to a learning circle. """ @@ -533,19 +557,19 @@ def post(self, request, circle_id, muid): general_message='Muid is Invalid' ).get_failure_response() - usr_circle_link = UserCircleLink.objects.filter( + user_circle_link = UserCircleLink.objects.filter( circle__id=circle_id, user__id=user.id ).first() - if usr_circle_link: - if usr_circle_link.accepted: + if user_circle_link: + if user_circle_link.accepted: return CustomResponse( general_message='User already part of circle' ).get_failure_response() - elif usr_circle_link.is_invited: + elif user_circle_link.is_invited: return CustomResponse( general_message='User already invited' ).get_failure_response() @@ -553,7 +577,7 @@ def post(self, request, circle_id, muid): receiver_email = user.email html_address = ["lc_invitation.html"] inviter = User.objects.filter(id=JWTUtils.fetch_user_id(request)).first() - inviter_name = inviter.first_name + " " + inviter.last_name + inviter_name = inviter.full_name context = { "circle_name": LearningCircle.objects.filter( id=circle_id @@ -570,7 +594,7 @@ def post(self, request, circle_id, muid): ) if status == 1: - usr_circle_link_new = UserCircleLink( + UserCircleLink.objects.create( id=uuid.uuid4(), circle_id=circle_id, user=user, @@ -578,7 +602,6 @@ def post(self, request, circle_id, muid): accepted=False, created_at=DateTimeUtils.get_current_utc_time(), ) - usr_circle_link_new.save() return CustomResponse( general_message='User Invited' @@ -608,58 +631,28 @@ def post(self, request, circle_id, muid, status): general_message='Muid is Invalid' ).get_failure_response() - usr_circle_link = UserCircleLink.objects.filter( + user_circle_link = UserCircleLink.objects.filter( circle__id=circle_id, user__id=user.id ).first() - if not usr_circle_link: + if not user_circle_link: return CustomResponse( general_message='User not invited' ).get_failure_response() if status == "accepted": - usr_circle_link.accepted = True - usr_circle_link.accepted_at = DateTimeUtils.get_current_utc_time() - usr_circle_link.save() + user_circle_link.accepted = True + user_circle_link.accepted_at = DateTimeUtils.get_current_utc_time() + user_circle_link.save() # return CustomResponse(general_message='User added to circle').get_success_response() return redirect(f'{domain}/dashboard/learning-circle/') elif status == "rejected": - usr_circle_link.delete() + user_circle_link.delete() return CustomResponse( general_message='User rejected invitation' ).get_failure_response() -class PreviousMeetingsDetailsAPI(APIView): - """ - API for retrieving details of a previous meeting by ID. - - This API allows you to retrieve information about a previous meeting - based on its unique ID. - Methode: - - get: Retrieve details of a previous meeting. - """ - def get(self, request, meet_id): - - circle_meeting_log = CircleMeetingLog.objects.filter( - id=meet_id - ).values( - "id", - "meet_time", - "meet_place", - "day", - "attendees", - "agenda", - meet_created_by=F("created_by__first_name"), - meet_created_at=F("created_at"), - meet_updated_by=F("updated_by__first_name"), - meet_updated_at=F("updated_at"), - ) - - return CustomResponse( - response=circle_meeting_log - ).get_success_response() - diff --git a/api/dashboard/lc/urls.py b/api/dashboard/lc/urls.py index c1867326..1c4b2855 100644 --- a/api/dashboard/lc/urls.py +++ b/api/dashboard/lc/urls.py @@ -14,10 +14,10 @@ path('join//', dash_lc_view.LearningCircleJoinApi.as_view()), path('//', dash_lc_view.LearningCircleHomeApi.as_view()), path('/', dash_lc_view.LearningCircleHomeApi.as_view()), - path('meeting-log//', dash_lc_view.PreviousMeetingsDetailsAPI.as_view()), - path('meet/edit//', dash_lc_view.MeetCreateEditDeleteAPI.as_view()), # optim - path('meet/create//', dash_lc_view.MeetCreateEditDeleteAPI.as_view()), # optim - path('member/invite///', dash_lc_view.LearningCircleInviteMember.as_view()), + path('meeting-log//', dash_lc_view.MeetGetPostPatchDeleteAPI.as_view()), + path('meet/edit//', dash_lc_view.MeetGetPostPatchDeleteAPI.as_view()), # optim + path('meet/create//', dash_lc_view.MeetGetPostPatchDeleteAPI.as_view()), # optim + path('member/invite///', dash_lc_view.LearningCircleInviteMemberAPI.as_view()), path('member/invite/status////', dash_lc_view.LearningCircleInvitationStatus.as_view()), path('lead///', dash_lc_view.LearningCircleLeadTransfer.as_view()), ] diff --git a/api/dashboard/location/location_serializer.py b/api/dashboard/location/location_serializer.py index a6f78191..2b541223 100644 --- a/api/dashboard/location/location_serializer.py +++ b/api/dashboard/location/location_serializer.py @@ -9,84 +9,81 @@ class LocationSerializer(serializers.ModelSerializer): label = serializers.CharField(source="name") value = serializers.CharField(source="id") + created_by = serializers.CharField(source="created_by.fullname") + updated_by = serializers.CharField(source="updated_by.fullname") class Meta: model = Country - fields = ["label", "value"] + fields = [ + "label", + "value", + "created_at", + "updated_at", + "created_by", + "updated_by", + ] class CountryCreateEditSerializer(serializers.ModelSerializer): label = serializers.CharField(source="name") - # value = serializers.CharField(source="id") + # value = serializers.CharField(source="id") class Meta: model = Country - fields = ["label"] - - def create(self, validated_data): - validated_data['id'] = str(uuid.uuid4()) - validated_data["updated_at"] = validated_data["created_at"] = DateTimeUtils.get_current_utc_time() - validated_data["updated_by_id"] = validated_data["created_by_id"] = self.context.get("user_id") - - return super().create(validated_data) - - def update(self, instance, validated_data): - validated_data["updated_at"] = DateTimeUtils.get_current_utc_time() - validated_data["updated_by_id"] = self.context.get("user_id") - - return super().update(instance, validated_data) - - def validate_label(self, country): - country_obj = Country.objects.filter(name=country).first() - if country_obj: - raise serializers.ValidationError('Country with this name is already exists') - return country + fields = ["label", "updated_by", "created_by"] class StateRetrievalSerializer(serializers.ModelSerializer): + country = serializers.CharField(source="country.name", required=False, default=None) label = serializers.CharField(source="name") value = serializers.CharField(source="id") + created_by = serializers.CharField(source="created_by.fullname") + updated_by = serializers.CharField(source="updated_by.fullname") class Meta: - model = Country - fields = ["label", "value"] + model = State + fields = [ + "label", + "value", + "country", + "created_at", + "updated_at", + "created_by", + "updated_by", + ] class StateCreateEditSerializer(serializers.ModelSerializer): label = serializers.CharField(source="name") - # value = serializers.CharField(source="id") + # value = serializers.CharField(source="id") class Meta: model = State - fields = ["label", "country"] - - def create(self, validated_data): - validated_data['id'] = str(uuid.uuid4()) - validated_data["updated_at"] = validated_data["created_at"] = DateTimeUtils.get_current_utc_time() - validated_data["updated_by_id"] = validated_data["created_by_id"] = self.context.get("user_id") - - return super().create(validated_data) - - def update(self, instance, validated_data): - validated_data["updated_at"] = DateTimeUtils.get_current_utc_time() - validated_data["updated_by_id"] = self.context.get("user_id") - - return super().update(instance, validated_data) - - def validate_label(self, state): - state_obj = State.objects.filter(name=state).first() - if state_obj: - raise serializers.ValidationError("State with this name is already exists") - return state + fields = ["label", "created_by", "updated_by"] class ZoneRetrievalSerializer(serializers.ModelSerializer): + country = serializers.CharField( + source="state.country.name", required=False, default=None + ) + state = serializers.CharField(source="state.name", required=False, default=None) label = serializers.CharField(source="name") value = serializers.CharField(source="id") + created_by = serializers.CharField(source="created_by.fullname") + updated_by = serializers.CharField(source="updated_by.fullname") class Meta: - model = Country - fields = ["label", "value"] + model = Zone + fields = [ + "label", + "value", + "country", + "state", + "created_at", + "updated_at", + "created_by", + "updated_by", + ] class ZoneCreateEditSerializer(serializers.ModelSerializer): @@ -95,35 +92,35 @@ class ZoneCreateEditSerializer(serializers.ModelSerializer): class Meta: model = Zone - fields = ["label", "state"] - - def create(self, validated_data): - validated_data['id'] = str(uuid.uuid4()) - validated_data["updated_at"] = validated_data["created_at"] = DateTimeUtils.get_current_utc_time() - validated_data["updated_by_id"] = validated_data["created_by_id"] = self.context.get("user_id") - - return super().create(validated_data) - - def update(self, instance, validated_data): - validated_data["updated_at"] = DateTimeUtils.get_current_utc_time() - validated_data["updated_by_id"] = self.context.get("user_id") - - return super().update(instance, validated_data) - - def validate_label(self, zone): - zone_obj = Zone.objects.filter(name=zone).first() - if zone_obj: - raise serializers.ValidationError("Zone with this name is already exists") - return zone + fields = ["label", "created_by", "updated_by"] class DistrictRetrievalSerializer(serializers.ModelSerializer): + country = serializers.CharField( + source="zone.state.country.name", required=False, default=None + ) + state = serializers.CharField( + source="zone.state.name", required=False, default=None + ) + zone = serializers.CharField(source="zone.name", required=False, default=None) label = serializers.CharField(source="name") value = serializers.CharField(source="id") + created_by = serializers.CharField(source="created_by.fullname") + updated_by = serializers.CharField(source="updated_by.fullname") class Meta: - model = Country - fields = ["label", "value"] + model = District + fields = [ + "label", + "value", + "country", + "state", + "zone", + "created_at", + "updated_at", + "created_by", + "updated_by", + ] class DistrictCreateEditSerializer(serializers.ModelSerializer): @@ -132,23 +129,4 @@ class DistrictCreateEditSerializer(serializers.ModelSerializer): class Meta: model = District - fields = ["label", "zone"] - - def create(self, validated_data): - validated_data['id'] = str(uuid.uuid4()) - validated_data["updated_at"] = validated_data["created_at"] = DateTimeUtils.get_current_utc_time() - validated_data["updated_by_id"] = validated_data["created_by_id"] = self.context.get("user_id") - - return super().create(validated_data) - - def update(self, instance, validated_data): - validated_data["updated_at"] = DateTimeUtils.get_current_utc_time() - validated_data["updated_by_id"] = self.context.get("user_id") - - return super().update(instance, validated_data) - - def validate_label(self, district): - district_obj = District.objects.filter(name=district).first() - if district_obj: - raise serializers.ValidationError("District with this name is already exists") - return district + fields = ["label", "created_by", "updated_by"] diff --git a/api/dashboard/location/location_views.py b/api/dashboard/location/location_views.py index 64137738..a4e7fc30 100644 --- a/api/dashboard/location/location_views.py +++ b/api/dashboard/location/location_views.py @@ -15,76 +15,55 @@ class CountryDataAPI(APIView): @role_required([RoleType.ADMIN.value]) def get(self, request, country_id=None): - if country_id: - countries = Country.objects.filter(id=country_id) + countries = Country.objects.filter(id=country_id).select_related( + "created_by", "updated_by" + ) else: - countries = Country.objects.all() + countries = Country.objects.all().select_related("created_by", "updated_by") paginated_queryset = CommonUtils.get_paginated_queryset( - countries, - request, - [ - "name" - ], - { - "label": "name" - } + countries, request, ["name"], {"label": "name"} ) serializer = location_serializer.LocationSerializer( - paginated_queryset.get("queryset"), - many=True + paginated_queryset.get("queryset"), many=True ) return CustomResponse().paginated_response( - data=serializer.data, - pagination=paginated_queryset.get("pagination") + data=serializer.data, pagination=paginated_queryset.get("pagination") ) @role_required([RoleType.ADMIN.value]) def post(self, request): - user_id = JWTUtils.fetch_user_id(request) - + request_data = request.data + request_data["created_by"] = request_data[ + "updated_by" + ] = JWTUtils.fetch_user_id(request) serializer = location_serializer.CountryCreateEditSerializer( - data=request.data, - context={ - "user_id": user_id - } + data=request_data, ) if serializer.is_valid(): serializer.save() - return CustomResponse( - general_message="Country created Successfully" - ).get_success_response() + return CustomResponse(response=serializer.data).get_success_response() - return CustomResponse( - general_message=serializer.errors - ).get_failure_response() + return CustomResponse(general_message=serializer.errors).get_failure_response() @role_required([RoleType.ADMIN.value]) def patch(self, request, country_id): - user_id = JWTUtils.fetch_user_id(request) country = Country.objects.get(id=country_id) - + request_data = request.data + request_data["updated_by"] = JWTUtils.fetch_user_id(request) serializer = location_serializer.CountryCreateEditSerializer( - country, - data=request.data, - context={ - "user_id": user_id - } + country, data=request_data, partial=True ) if serializer.is_valid(): serializer.save() - return CustomResponse( - general_message="Country edited successfully" - ).get_success_response() + return CustomResponse(response=serializer.data).get_success_response() - return CustomResponse( - general_message=serializer.errors - ).get_failure_response() + return CustomResponse(general_message=serializer.errors).get_failure_response() @role_required([RoleType.ADMIN.value]) def delete(self, request, country_id): @@ -101,78 +80,61 @@ class StateDataAPI(APIView): @role_required([RoleType.ADMIN.value]) def get(self, request, state_id=None): - if state_id: - states = State.objects.filter( - Q(pk=state_id) | - Q(country__pk=state_id) - ).all() + states = ( + State.objects.filter(Q(pk=state_id) | Q(country__pk=state_id)) + .all() + .select_related("country", "created_by", "updated_by") + ) else: - states = State.objects.all() + states = State.objects.all().select_related( + "country", "created_by", "updated_by" + ) paginated_queryset = CommonUtils.get_paginated_queryset( - states, - request, - [ - "name" - ], - { - "name": "name" - } + states, request, ["name"], {"name": "name"} ) serializer = location_serializer.StateRetrievalSerializer( - paginated_queryset.get("queryset"), - many=True + paginated_queryset.get("queryset"), many=True ) return CustomResponse().paginated_response( - data=serializer.data, - pagination=paginated_queryset.get("pagination") + data=serializer.data, pagination=paginated_queryset.get("pagination") ) @role_required([RoleType.ADMIN.value]) def post(self, request): - user_id = JWTUtils.fetch_user_id(request) + request_data = request.data + request_data["created_by"] = request_data[ + "updated_by" + ] = JWTUtils.fetch_user_id(request) serializer = location_serializer.StateCreateEditSerializer( - data=request.data, - context={ - "user_id": user_id - } + data=request_data, ) if serializer.is_valid(): serializer.save() - return CustomResponse( - general_message="State created successfully" - ).get_success_response() + return CustomResponse(response=serializer.data).get_success_response() - return CustomResponse( - general_message=serializer.errors - ).get_failure_response() + return CustomResponse(general_message=serializer.errors).get_failure_response() @role_required([RoleType.ADMIN.value]) def patch(self, request, state_id): - user_id = JWTUtils.fetch_user_id(request) state = State.objects.get(id=state_id) - + request_data = request.data + request_data["updated_by"] = JWTUtils.fetch_user_id(request) serializer = location_serializer.StateCreateEditSerializer( - state, - data=request.data, - context={ - "user_id": user_id - } + state, data=request_data, partial=True ) if serializer.is_valid(): serializer.save() - return CustomResponse( - general_message=serializer.data - ).get_success_response() + return CustomResponse(response=serializer.data).get_success_response() return CustomResponse( general_message="State edited successfully" @@ -193,83 +155,64 @@ class ZoneDataAPI(APIView): @role_required([RoleType.ADMIN.value]) def get(self, request, zone_id=None): - if zone_id: - zones = Zone.objects.filter( - Q(pk=zone_id) | - Q(state__pk=zone_id) | - Q(state__country__pk=zone_id) - ).all() + zones = ( + Zone.objects.filter( + Q(pk=zone_id) | Q(state__pk=zone_id) | Q(state__country__pk=zone_id) + ) + .all() + .select_related("state", "state__country", "created_by", "updated_by") + ) else: - zones = Zone.objects.all() + zones = Zone.objects.all().select_related( + "state", "state__country", "created_by", "updated_by" + ) paginated_queryset = CommonUtils.get_paginated_queryset( - zones, - request, - [ - "name" - ], - { - "name": "name" - } + zones, request, ["name"], {"name": "name"} ) serializer = location_serializer.ZoneRetrievalSerializer( - paginated_queryset.get("queryset"), - many=True + paginated_queryset.get("queryset"), many=True ) return CustomResponse().paginated_response( - data=serializer.data, - pagination=paginated_queryset.get("pagination") + data=serializer.data, pagination=paginated_queryset.get("pagination") ) @role_required([RoleType.ADMIN.value]) def post(self, request): - user_id = JWTUtils.fetch_user_id(request) - + request_data = request.data + request_data["created_by"] = request_data[ + "updated_by" + ] = JWTUtils.fetch_user_id(request) serializer = location_serializer.ZoneCreateEditSerializer( data=request.data, - context={ - "user_id": user_id - } ) if serializer.is_valid(): serializer.save() - return CustomResponse( - general_message="Zone created successfully" - ).get_success_response() + return CustomResponse(response=serializer.data).get_success_response() - return CustomResponse( - general_message=serializer.errors - ).get_failure_response() + return CustomResponse(general_message=serializer.errors).get_failure_response() @role_required([RoleType.ADMIN.value]) def patch(self, request, zone_id): - user_id = JWTUtils.fetch_user_id(request) zone = Zone.objects.get(id=zone_id) - + request_data = request.data + request_data["updated_by"] = JWTUtils.fetch_user_id(request) serializer = location_serializer.ZoneCreateEditSerializer( - zone, - data=request.data, - context={ - "user_id": user_id - } + zone, data=request.data, partial=True ) if serializer.is_valid(): serializer.save() - return CustomResponse( - general_message="zone edited successfully" - ).get_success_response() + return CustomResponse(response=serializer.data).get_success_response() - return CustomResponse( - general_message=serializer.errors - ).get_failure_response() + return CustomResponse(general_message=serializer.errors).get_failure_response() @role_required([RoleType.ADMIN.value]) def delete(self, request, zone_id): @@ -286,55 +229,59 @@ class DistrictDataAPI(APIView): @role_required([RoleType.ADMIN.value]) def get(self, request, district_id=None): - if district_id: - districts = District.objects.filter( - Q(pk=district_id) | - Q(zone__pk=district_id) | - Q(zone__state__pk=district_id) | - Q(zone__state__country__pk=district_id) - ).all() + districts = ( + District.objects.filter( + Q(pk=district_id) + | Q(zone__pk=district_id) + | Q(zone__state__pk=district_id) + | Q(zone__state__country__pk=district_id) + ) + .all() + .select_related( + "zone", + "zone__state", + "zone__state__country", + "created_by", + "updated_by", + ) + ) else: - districts = District.objects.all() + districts = District.objects.all().select_related( + "zone", + "zone__state", + "zone__state__country", + "created_by", + "updated_by", + ) paginated_queryset = CommonUtils.get_paginated_queryset( - districts, - request, - [ - "name" - ], - { - "name": "name" - } + districts, request, ["name"], {"name": "name"} ) serializer = location_serializer.DistrictRetrievalSerializer( - paginated_queryset.get("queryset"), - many=True + paginated_queryset.get("queryset"), many=True ) return CustomResponse().paginated_response( - data=serializer.data, - pagination=paginated_queryset.get("pagination") + data=serializer.data, pagination=paginated_queryset.get("pagination") ) @role_required([RoleType.ADMIN.value]) def post(self, request): - user_id = JWTUtils.fetch_user_id(request) + request_data = request.data + request_data["created_by"] = request_data[ + "updated_by" + ] = JWTUtils.fetch_user_id(request) serializer = location_serializer.DistrictCreateEditSerializer( data=request.data, - context={ - "user_id": user_id - } ) if serializer.is_valid(): serializer.save() - return CustomResponse( - general_message=serializer.data - ).get_success_response() + return CustomResponse(response=serializer.data).get_success_response() return CustomResponse( general_message="Zone created successfully" @@ -342,27 +289,19 @@ def post(self, request): @role_required([RoleType.ADMIN.value]) def patch(self, request, district_id): - user_id = JWTUtils.fetch_user_id(request) district = District.objects.get(id=district_id) - + request_data = request.data + request_data["updated_by"] = JWTUtils.fetch_user_id(request) serializer = location_serializer.DistrictCreateEditSerializer( - district, - data=request.data, - context={ - "user_id": user_id - } + district, data=request.data, partial=True ) if serializer.is_valid(): serializer.save() - return CustomResponse( - general_message="Zone edited successfully" - ).get_success_response() + return CustomResponse(response=serializer.data).get_success_response() - return CustomResponse( - general_message=serializer.errors - ).get_failure_response() + return CustomResponse(general_message=serializer.errors).get_failure_response() @role_required([RoleType.ADMIN.value]) def delete(self, request, district_id): @@ -376,35 +315,20 @@ def delete(self, request, district_id): class CountryListApi(APIView): def get(self, request): - country = Country.objects.all().values( - 'id', - 'name' - ).order_by('name') + country = Country.objects.all().values("id", "name").order_by("name") - return CustomResponse( - response=country - ).get_success_response() + return CustomResponse(response=country).get_success_response() class StateListApi(APIView): def get(self, request): - state = State.objects.all().values( - 'id', - 'name' - ).order_by('name') + state = State.objects.all().values("id", "name").order_by("name") - return CustomResponse( - response=state - ).get_success_response() + return CustomResponse(response=state).get_success_response() class ZoneListApi(APIView): def get(self, request): - zone = Zone.objects.all().values( - 'id', - 'name' - ).order_by('name') + zone = Zone.objects.all().values("id", "name").order_by("name") - return CustomResponse( - response=zone - ).get_success_response() + return CustomResponse(response=zone).get_success_response() diff --git a/api/dashboard/organisation/organisation_views.py b/api/dashboard/organisation/organisation_views.py index a9b059e0..23c45fb7 100644 --- a/api/dashboard/organisation/organisation_views.py +++ b/api/dashboard/organisation/organisation_views.py @@ -19,7 +19,8 @@ InstitutionCreateUpdateSerializer, InstitutionSerializer, InstitutionPrefillSerializer, - OrganizationMergerSerializer, + OrganizationMergerSerializer, OrganizationKarmaTypeGetPostPatchDeleteSerializer, + OrganizationKarmaLogGetPostPatchDeleteSerializer, ) @@ -470,3 +471,48 @@ def patch(self, request, organisation_id): return CustomResponse( general_message="An organization with the given id doesn't exist" ).get_failure_response() + + +class OrganizationKarmaTypeGetPostPatchDeleteAPI(APIView): + def post(self, request): + user_id = JWTUtils.fetch_user_id(request) + + serializer = OrganizationKarmaTypeGetPostPatchDeleteSerializer( + data=request.data, + context={ + 'user_id': user_id + } + ) + if serializer.is_valid(): + serializer.save() + + return CustomResponse( + "Organization karma type created successfully" + ).get_success_response() + + return CustomResponse( + serializer.errors + ).get_failure_response() + + +class OrganizationKarmaLogGetPostPatchDeleteAPI(APIView): + def post(self, request): + user_id = JWTUtils.fetch_user_id(request) + + serializer = OrganizationKarmaLogGetPostPatchDeleteSerializer( + data=request.data, + context={ + 'user_id': user_id + } + ) + + if serializer.is_valid(): + serializer.save() + + return CustomResponse( + "Organization karma Log created successfully" + ).get_success_response() + + return CustomResponse( + serializer.errors + ).get_failure_response() diff --git a/api/dashboard/organisation/serializers.py b/api/dashboard/organisation/serializers.py index a665a281..d4d760d2 100644 --- a/api/dashboard/organisation/serializers.py +++ b/api/dashboard/organisation/serializers.py @@ -11,6 +11,8 @@ State, OrgAffiliation, Department, + OrgKarmaType, + OrgKarmaLog, ) from utils.permission import JWTUtils from utils.types import OrganizationType @@ -256,7 +258,7 @@ class OrganizationMergerSerializer(serializers.Serializer): }, ) - def validate_source_code(self, attrs): + def validate_source_org(self, attrs): if self.instance.code == attrs.code: raise serializers.ValidationError( "You can't merge an organization into itself." @@ -361,3 +363,39 @@ def update(self, instance, validated_data): source_org.delete() return instance + + +class OrganizationKarmaTypeGetPostPatchDeleteSerializer(serializers.ModelSerializer): + + class Meta: + model = OrgKarmaType + fields = [ + "title", + "karma", + "description", + ] + + def create(self, validated_data): + user_id = self.context.get("user_id") + validated_data["updated_by_id"] = user_id + validated_data["created_by_id"] = user_id + + return OrgKarmaType.objects.create(**validated_data) + + +class OrganizationKarmaLogGetPostPatchDeleteSerializer(serializers.ModelSerializer): + + class Meta: + model = OrgKarmaLog + fields = [ + "org", + "karma", + "type", + ] + + def create(self, validated_data): + user_id = self.context.get("user_id") + validated_data["updated_by_id"] = user_id + validated_data["created_by_id"] = user_id + + return OrgKarmaLog.objects.create(**validated_data) diff --git a/api/dashboard/organisation/urls.py b/api/dashboard/organisation/urls.py index 5c9f9694..fc588ee9 100644 --- a/api/dashboard/organisation/urls.py +++ b/api/dashboard/organisation/urls.py @@ -21,5 +21,7 @@ path('departments/edit//', organisation_views.DepartmentAPI.as_view()), path('departments/delete//', organisation_views.DepartmentAPI.as_view()), path('affiliation/list/', organisation_views.AffiliationListAPI.as_view()), - path('merge_organizations//', organisation_views.OrganizationMergerView.as_view()) + path('merge_organizations//', organisation_views.OrganizationMergerView.as_view()), + path('karma-type/create/', organisation_views.OrganizationKarmaTypeGetPostPatchDeleteAPI.as_view()), + path('karma-log/create/', organisation_views.OrganizationKarmaLogGetPostPatchDeleteAPI.as_view()), ] diff --git a/api/dashboard/profile/profile_serializer.py b/api/dashboard/profile/profile_serializer.py index 8218ebf7..8ee11149 100644 --- a/api/dashboard/profile/profile_serializer.py +++ b/api/dashboard/profile/profile_serializer.py @@ -12,6 +12,7 @@ from utils.permission import JWTUtils from utils.types import OrganizationType, RoleType, MainRoles from utils.utils import DateTimeUtils +from django.core.files.storage import FileSystemStorage class UserLogSerializer(ModelSerializer): @@ -35,6 +36,7 @@ class UserProfileSerializer(serializers.ModelSerializer): karma_distribution = serializers.SerializerMethodField() interest_groups = serializers.SerializerMethodField() org_district_id = serializers.SerializerMethodField() + profile_pic = serializers.SerializerMethodField() class Meta: model = User @@ -57,7 +59,16 @@ class Meta: "interest_groups", "is_public", ) - + + def get_profile_pic(self,obj): + fs = FileSystemStorage() + path = f'user/profile/{obj.id}.png' + if fs.exists(path): + profile_pic = f"{self.context.get('request').build_absolute_uri('/')}{fs.url(path)[1:]}" + else: + profile_pic = obj.profile_pic + return profile_pic + def get_roles(self, obj): return list({link.role.title for link in obj.user_role_link_user.all()}) diff --git a/api/dashboard/profile/profile_view.py b/api/dashboard/profile/profile_view.py index 9f231cf2..d49702ba 100644 --- a/api/dashboard/profile/profile_view.py +++ b/api/dashboard/profile/profile_view.py @@ -139,7 +139,8 @@ def get(self, request, muid=None): serializer = profile_serializer.UserProfileSerializer( user, - many=False + many=False, + context={'request':request} ) return CustomResponse( diff --git a/api/dashboard/task/assets/base_template.xlsx b/api/dashboard/task/assets/task_base_template.xlsx similarity index 100% rename from api/dashboard/task/assets/base_template.xlsx rename to api/dashboard/task/assets/task_base_template.xlsx diff --git a/api/dashboard/task/dash_task_serializer.py b/api/dashboard/task/dash_task_serializer.py index 766f05dd..a64fc2d5 100644 --- a/api/dashboard/task/dash_task_serializer.py +++ b/api/dashboard/task/dash_task_serializer.py @@ -4,7 +4,7 @@ class TaskListSerializer(serializers.ModelSerializer): - channel = serializers.CharField(source="channels.name", required=False, default=None) + channel = serializers.CharField(source="channel.name", required=False, default=None) type = serializers.CharField(source="type.title") level = serializers.CharField(source="level.name", required=False, default=None) ig = serializers.CharField(source="ig.name", required=False, default=None) diff --git a/api/dashboard/task/dash_task_view.py b/api/dashboard/task/dash_task_view.py index 113cb242..c555355b 100644 --- a/api/dashboard/task/dash_task_view.py +++ b/api/dashboard/task/dash_task_view.py @@ -199,7 +199,7 @@ def get(self, request): task_queryset = TaskList.objects.select_related( "created_by", "updated_by", - "channels", + "channel", "type", "level", "ig", @@ -508,7 +508,7 @@ class TaskBaseTemplateAPI(APIView): authentication_classes = [CustomizePermission] def get(self, request): - wb = load_workbook('./api/dashboard/task/assets/base_template.xlsx') + wb = load_workbook('./api/dashboard/task/assets/task_base_template.xlsx') ws = wb['Data Definitions'] levels = Level.objects.all().values_list('name', flat=True) channels = Channel.objects.all().values_list('name', flat=True) @@ -536,4 +536,4 @@ def get(self, request): with open(tmp.name, 'rb') as f: f.seek(0) new_file_object = f.read() - return FileResponse(BytesIO(new_file_object), as_attachment=True, filename='base_template.xlsx') \ No newline at end of file + return FileResponse(BytesIO(new_file_object), as_attachment=True, filename='task_base_template.xlsx') \ No newline at end of file diff --git a/api/dashboard/task/urls.py b/api/dashboard/task/urls.py index a7bab4b6..5072de8f 100644 --- a/api/dashboard/task/urls.py +++ b/api/dashboard/task/urls.py @@ -4,7 +4,7 @@ urlpatterns = [ - path('channels/', dash_task_view.ChannelDropdownAPI.as_view()), + path('channel/', dash_task_view.ChannelDropdownAPI.as_view()), path('ig/', dash_task_view.IGDropdownAPI.as_view()), path('organization/', dash_task_view.OrganizationDropdownAPI.as_view()), path('level/', dash_task_view.LevelDropdownAPI.as_view()), diff --git a/api/dashboard/user/dash_user_serializer.py b/api/dashboard/user/dash_user_serializer.py index e873275c..d20d6808 100644 --- a/api/dashboard/user/dash_user_serializer.py +++ b/api/dashboard/user/dash_user_serializer.py @@ -45,7 +45,6 @@ class Meta: "mobile", "gender", "dob", - "active", "exist_in_guild", "joined", "roles", diff --git a/api/dashboard/user/dash_user_views.py b/api/dashboard/user/dash_user_views.py index 6081b780..3dccb574 100644 --- a/api/dashboard/user/dash_user_views.py +++ b/api/dashboard/user/dash_user_views.py @@ -7,10 +7,11 @@ from db.user import ForgotPassword, User, UserRoleLink from utils.permission import CustomizePermission, JWTUtils, role_required -from utils.response import CustomResponse +from utils.response import CustomResponse, ImageResponse from utils.types import RoleType, WebHookActions, WebHookCategory from utils.utils import CommonUtils, DateTimeUtils, DiscordWebhooks, send_template_mail from . import dash_user_serializer +from django.core.files.storage import FileSystemStorage class UserInfoAPI(APIView): @@ -25,14 +26,9 @@ def get(self, request): general_message="No user data available" ).get_failure_response() - response = dash_user_serializer.UserSerializer( - user, - many=False - ).data + response = dash_user_serializer.UserSerializer(user, many=False).data - return CustomResponse( - response=response - ).get_success_response() + return CustomResponse(response=response).get_success_response() class UserGetPatchDeleteAPI(APIView): @@ -49,9 +45,7 @@ def get(self, request, user_id): serializer = dash_user_serializer.UserDetailsSerializer(user) - return CustomResponse( - response=serializer.data - ).get_success_response() + return CustomResponse(response=serializer.data).get_success_response() @role_required([RoleType.ADMIN.value]) def delete(self, request, user_id): @@ -62,7 +56,8 @@ def delete(self, request, user_id): general_message="User Not Available" ).get_failure_response() - user.active = False + user.deleted_by = User.objects.get(pk=JWTUtils.fetch_user_id(request)) + user.deleted_at = DateTimeUtils.get_current_utc_time() user.save() return CustomResponse( @@ -76,24 +71,19 @@ def patch(self, request, user_id): request.data["admin"] = JWTUtils.fetch_user_id(request) serializer = dash_user_serializer.UserDetailsEditSerializer( - user, data=request.data, - partial=True + user, data=request.data, partial=True ) if serializer.is_valid(): serializer.save() DiscordWebhooks.general_updates( - WebHookCategory.USER.value, - WebHookActions.UPDATE.value, - user_id + WebHookCategory.USER.value, WebHookActions.UPDATE.value, user_id ) return CustomResponse( general_message="User Edited Successfully" ).get_success_response() - return CustomResponse( - general_message=serializer.errors - ).get_failure_response() + return CustomResponse(general_message=serializer.errors).get_failure_response() class UserAPI(APIView): @@ -102,9 +92,7 @@ class UserAPI(APIView): @role_required([RoleType.ADMIN.value]) def get(self, request): user_queryset = User.objects.select_related( - "wallet_user", - "user_lvl_link_user", - "user_lvl_link_user__level" + "wallet_user", "user_lvl_link_user", "user_lvl_link_user__level" ).all() queryset = CommonUtils.get_paginated_queryset( @@ -126,13 +114,11 @@ def get(self, request): }, ) serializer = dash_user_serializer.UserDashboardSerializer( - queryset.get("queryset"), - many=True + queryset.get("queryset"), many=True ) return CustomResponse().paginated_response( - data=serializer.data, - pagination=queryset.get("pagination") + data=serializer.data, pagination=queryset.get("pagination") ) @@ -142,20 +128,14 @@ class UserManagementCSV(APIView): @role_required([RoleType.ADMIN.value]) def get(self, request): user_queryset = User.objects.select_related( - "wallet_user", - "user_lvl_link_user", - "user_lvl_link_user__level" + "wallet_user", "user_lvl_link_user", "user_lvl_link_user__level" ).all() serializer = dash_user_serializer.UserDashboardSerializer( - user_queryset, - many=True + user_queryset, many=True ) - return CommonUtils.generate_csv( - serializer.data, - "User" - ) + return CommonUtils.generate_csv(serializer.data, "User") class UserVerificationAPI(APIView): @@ -163,13 +143,10 @@ class UserVerificationAPI(APIView): @role_required([RoleType.ADMIN.value]) def get(self, request): - user_queryset = UserRoleLink.objects.select_related( - "user", - "role" - ).filter( + user_queryset = UserRoleLink.objects.select_related("user", "role").filter( verified=False ) - + queryset = CommonUtils.get_paginated_queryset( user_queryset, request, @@ -190,15 +167,11 @@ def get(self, request): }, ) serializer = dash_user_serializer.UserVerificationSerializer( - queryset.get( - "queryset" - ), - many=True + queryset.get("queryset"), many=True ) return CustomResponse().paginated_response( - data=serializer.data, - pagination=queryset.get("pagination") + data=serializer.data, pagination=queryset.get("pagination") ) @role_required([RoleType.ADMIN.value]) @@ -206,9 +179,7 @@ def patch(self, request, link_id): user = UserRoleLink.objects.get(id=link_id) user_serializer = dash_user_serializer.UserVerificationSerializer( - user, - data=request.data, - partial=True + user, data=request.data, partial=True ) if not user_serializer.is_valid(): @@ -250,19 +221,14 @@ class UserVerificationCSV(APIView): @role_required([RoleType.ADMIN.value]) def get(self, request): - user_queryset = UserRoleLink.objects.select_related( - "user", - "role" - ).filter(verified=False) - - serializer = dash_user_serializer.UserVerificationSerializer( - user_queryset, - many=True + user_queryset = UserRoleLink.objects.select_related("user", "role").filter( + verified=False ) - return CommonUtils.generate_csv( - serializer.data, - "User" + + serializer = dash_user_serializer.UserVerificationSerializer( + user_queryset, many=True ) + return CommonUtils.generate_csv(serializer.data, "User") class ForgotPasswordAPI(APIView): @@ -271,8 +237,7 @@ def post(self, request): if not ( user := User.objects.filter( - Q(muid=email_muid) | - Q(email=email_muid) + Q(muid=email_muid) | Q(email=email_muid) ).first() ): return CustomResponse( @@ -283,10 +248,7 @@ def post(self, request): expiry = created_at + timedelta(seconds=900) # 15 minutes forget_user = ForgotPassword.objects.create( - id=uuid.uuid4(), - user=user, - expiry=expiry, - created_at=created_at + id=uuid.uuid4(), user=user, expiry=expiry, created_at=created_at ) receiver_mail = user.email @@ -310,7 +272,6 @@ def post(self, request): class ResetPasswordVerifyTokenAPI(APIView): def post(self, request, token): if not (forget_user := ForgotPassword.objects.filter(id=token).first()): - return CustomResponse( general_message="Invalid Token" ).get_failure_response() @@ -319,9 +280,7 @@ def post(self, request, token): if forget_user.expiry > current_time: muid = forget_user.user.muid - return CustomResponse( - response={"muid": muid} - ).get_success_response() + return CustomResponse(response={"muid": muid}).get_success_response() else: forget_user.delete() return CustomResponse( @@ -332,24 +291,17 @@ def post(self, request, token): class ResetPasswordConfirmAPI(APIView): def post(self, request, token): if not (forget_user := ForgotPassword.objects.filter(id=token).first()): - return CustomResponse( general_message="Invalid Token" ).get_failure_response() current_time = DateTimeUtils.get_current_utc_time() if forget_user.expiry > current_time: - - return self.save_password( - request, - forget_user - ) + return self.save_password(request, forget_user) forget_user.delete() - return CustomResponse( - general_message="Link is expired" - ).get_failure_response() + return CustomResponse(general_message="Link is expired").get_failure_response() def save_password(self, request, forget_user): new_password = request.data.get("password") @@ -362,3 +314,65 @@ def save_password(self, request, forget_user): return CustomResponse( general_message="New Password Saved Successfully" ).get_success_response() + + +class UserProfilePictureView(APIView): + # def get(self, request, user_id): + # user = User.objects.filter(id=user_id).first() + + # if user is None: + # return CustomResponse( + # general_message="No user data available" + # ).get_failure_response() + # image_path = f'user/profile/{user_id}.png' + # response = ImageResponse(path=image_path) + # if response.exists(): + # return response.get_success_response() + # else: + # return CustomResponse( + # general_message="No Profile picture available" + # ).get_failure_response() + + def patch(self, request): + DiscordWebhooks.general_updates( + WebHookCategory.USER_PROFILE.value, + WebHookActions.UPDATE.value, + JWTUtils.fetch_user_id(request), + ) + return CustomResponse( + general_message="Successfully updated" + ).get_success_response() + + def post(self, request): + user_id = request.data.get("user_id") + user = User.objects.filter(id=user_id).first() + + if user is None: + return CustomResponse( + general_message="No user data available" + ).get_failure_response() + + pic = request.FILES.get("profile") + + if pic is None: + return CustomResponse( + general_message="No profile picture" + ).get_failure_response() + + if not pic.content_type.startswith("image/"): + return CustomResponse( + general_message="Expected an image" + ).get_failure_response() + + extention = ".png" # os.path.splitext(pic.name)[1] + fs = FileSystemStorage() + filename = f"user/profile/{user_id}{extention}" + if fs.exists(filename): + fs.delete(filename) + filename = fs.save(filename, pic) + file_url = fs.url(filename) + uploaded_file_url = f"{request.build_absolute_uri('/')}{file_url[1:]}" + + return CustomResponse( + response={"user_id": user.id, "profile_pic": uploaded_file_url} + ).get_success_response() diff --git a/api/dashboard/user/urls.py b/api/dashboard/user/urls.py index ad2a8608..f3f11f05 100644 --- a/api/dashboard/user/urls.py +++ b/api/dashboard/user/urls.py @@ -13,6 +13,7 @@ path('forgot-password/', dash_user_views.ForgotPasswordAPI.as_view(), name="forgot-password"), path('reset-password/verify-token//', dash_user_views.ResetPasswordVerifyTokenAPI.as_view()), path('reset-password//', dash_user_views.ResetPasswordConfirmAPI.as_view()), + path('profile/update/',dash_user_views.UserProfilePictureView.as_view()), path('csv/', dash_user_views.UserManagementCSV.as_view(), name="csv-user"), path('', dash_user_views.UserAPI.as_view(), name='list-user'), diff --git a/api/leaderboard/leaderboard_view.py b/api/leaderboard/leaderboard_view.py index 81aec664..d57e53b2 100644 --- a/api/leaderboard/leaderboard_view.py +++ b/api/leaderboard/leaderboard_view.py @@ -17,7 +17,6 @@ def get(self, request): user_organization_link_user__org__org_type=OrganizationType.COLLEGE.value, user_role_link_user__role__title=RoleType.STUDENT.value, exist_in_guild=True, - active=True, ) .distinct() .select_related("wallet_user") @@ -49,7 +48,6 @@ def get(self, request): user_role_link_user__role__title=RoleType.STUDENT.value, user_organization_link_user__org__org_type=OrganizationType.COLLEGE.value, exist_in_guild=True, - active=True, ) .annotate( full_name=Concat(F("first_name"), Value(" "), F("last_name")), @@ -86,7 +84,6 @@ def get(self, request): Organization.objects.filter( org_type=OrganizationType.COLLEGE.value, user_organization_link_org__user__user_role_link_user__role__title=RoleType.STUDENT.value, - user_organization_link_org__user__active=True, user_organization_link_org__user__exist_in_guild=True, ) .distinct() diff --git a/api/leaderboard/serializers.py b/api/leaderboard/serializers.py index e35a4dc3..d404d67f 100644 --- a/api/leaderboard/serializers.py +++ b/api/leaderboard/serializers.py @@ -40,7 +40,6 @@ def get_active_members(self, obj): last_month = DateTimeUtils.get_current_utc_time() - timedelta(days=30) return obj.org.user_organization_link_org.filter( verified=True, - user__active=True, user__wallet_user__isnull=False, user__wallet_user__created_at__gte=last_month, ).count() diff --git a/db/learning_circle.py b/db/learning_circle.py index 39a678b0..a1b2f8ad 100644 --- a/db/learning_circle.py +++ b/db/learning_circle.py @@ -13,7 +13,7 @@ class LearningCircle(models.Model): id = models.CharField(primary_key=True, max_length=36, default=uuid.uuid4()) name = models.CharField(max_length=255, unique=True) circle_code = models.CharField(unique=True, max_length=36) - ig = models.ForeignKey(InterestGroup, on_delete=models.CASCADE, blank=True, null=True, + ig = models.ForeignKey(InterestGroup, on_delete=models.CASCADE, blank=True, related_name="learning_circle_ig") org = models.ForeignKey(Organization, on_delete=models.CASCADE, blank=True, null=True, related_name="learning_circle_org") diff --git a/db/managers/user_manager.py b/db/managers/user_manager.py new file mode 100644 index 00000000..9368ff21 --- /dev/null +++ b/db/managers/user_manager.py @@ -0,0 +1,16 @@ +from django.db import models + + +class ActiveUserManager(models.Manager): + def get_queryset(self): + # This will return only the users where deleted_at, deleted_by, suspended_at, and suspended_by are NULL + return ( + super() + .get_queryset() + .filter( + deleted_at__isnull=True, + deleted_by__isnull=True, + suspended_at__isnull=True, + suspended_by__isnull=True, + ) + ) diff --git a/db/organization.py b/db/organization.py index f78433d7..ccaa560b 100644 --- a/db/organization.py +++ b/db/organization.py @@ -143,7 +143,6 @@ class Meta: db_table = 'org_discord_link' - class UserOrganizationLink(models.Model): id = models.CharField(primary_key=True, max_length=36, default=uuid.uuid4) user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='user_organization_link_user') @@ -159,6 +158,38 @@ class Meta: db_table = 'user_organization_link' +class OrgKarmaType(models.Model): + id = models.CharField(primary_key=True, max_length=36, default=uuid.uuid4()) + title = models.CharField(max_length=75) + karma = models.IntegerField() + description = models.CharField(max_length=200, blank=True, null=True) + updated_by = models.ForeignKey(User, models.DO_NOTHING, db_column='updated_by', related_name='org_karma_type_updated_by') + updated_at = models.DateTimeField(auto_now=True) + created_by = models.ForeignKey(User, models.DO_NOTHING, db_column='created_by', + related_name='org_karma_type_created_by') + created_at = models.DateTimeField(auto_now=True) + + class Meta: + managed = False + db_table = 'org_karma_type' + + +class OrgKarmaLog(models.Model): + id = models.CharField(primary_key=True, max_length=36, default=uuid.uuid4()) + org = models.ForeignKey(Organization, models.DO_NOTHING, related_name='org_karma_log_org') + karma = models.IntegerField() + type = models.ForeignKey(OrgKarmaType, models.DO_NOTHING, db_column='type', related_name='org_karma_log_type') + updated_by = models.ForeignKey(User, models.DO_NOTHING, db_column='updated_by', related_name='org_karma_log_updated_by') + updated_at = models.DateTimeField(auto_now=True) + created_by = models.ForeignKey(User, models.DO_NOTHING, db_column='created_by', + related_name='org_karma_log_created_by') + created_at = models.DateTimeField(auto_now=True) + + class Meta: + managed = False + db_table = 'org_karma_log' + + @property def total_karma(self): try: diff --git a/db/user.py b/db/user.py index 8a512b4a..2dd211ad 100644 --- a/db/user.py +++ b/db/user.py @@ -1,6 +1,7 @@ import uuid from django.db import models +from .managers import user_manager # fmt: off # noinspection PyPep8 @@ -17,11 +18,16 @@ class User(models.Model): gender = models.CharField(max_length=10, blank=True, null=True, choices=[("Male", "Male"),("Female", "Female")]) dob = models.DateField(blank=True, null=True) admin = models.BooleanField(default=False) - active = models.BooleanField(default=True) exist_in_guild = models.BooleanField(default=False) profile_pic = models.CharField(max_length=200, blank=True, null=True) - district = models.ForeignKey("District",on_delete=models.CASCADE, blank=True, null=True) + district = models.ForeignKey("District", on_delete=models.CASCADE, blank=True, null=True) created_at = models.DateTimeField(auto_now_add=True) + suspended_at = models.DateTimeField(blank=True, null=True) + suspended_by = models.ForeignKey("self", on_delete=models.CASCADE, blank=True, null=True, related_name="suspended_by_user", db_column="suspended_by") + deleted_at = models.DateTimeField(blank=True, null=True) + deleted_by = models.ForeignKey("self", on_delete=models.CASCADE, blank=True, null=True, related_name="deleted_by_user", db_column="deleted_by") + objects = user_manager.ActiveUserManager() + every = models.Manager() class Meta: managed = False diff --git a/mulearnbackend/asgi.py b/mulearnbackend/asgi.py index 7ca754d2..66c033d6 100644 --- a/mulearnbackend/asgi.py +++ b/mulearnbackend/asgi.py @@ -13,7 +13,6 @@ from django.core.asgi import get_asgi_application from channels.routing import ProtocolTypeRouter, URLRouter - os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mulearnbackend.settings') django.setup() diff --git a/mulearnbackend/urls.py b/mulearnbackend/urls.py index 7da20c5a..1cebec42 100644 --- a/mulearnbackend/urls.py +++ b/mulearnbackend/urls.py @@ -15,14 +15,15 @@ """ from django.conf import settings -from django.conf.urls.static import static +# from django.conf.urls.static import static # from django.contrib import admin -from django.urls import path, include +from django.urls import path, include, re_path +from django.views.static import serve urlpatterns = [ # path('admin/', admin.site.urls), path('api/v1/', include('api.urls')), - + re_path(r'^muback-media/(?P.*)$',serve,{'document_root':settings.MEDIA_ROOT}) ] -urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) +# urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) diff --git a/utils/baseconsumer.py b/utils/baseconsumer.py deleted file mode 100644 index e4323d32..00000000 --- a/utils/baseconsumer.py +++ /dev/null @@ -1,9 +0,0 @@ -from channels.generic.websocket import WebsocketConsumer - -class BaseConsumer(WebsocketConsumer): - - def connect(self): - self.accept() - - def disconnect(self, close_code): - super().disconnect(close_code) \ No newline at end of file diff --git a/utils/response.py b/utils/response.py index 7bef98fb..0600eeea 100644 --- a/utils/response.py +++ b/utils/response.py @@ -3,6 +3,8 @@ from rest_framework import status from rest_framework.response import Response +from django.core.files.storage import FileSystemStorage +from django.http import HttpResponse class CustomResponse: """A custom response class for API views. @@ -101,4 +103,20 @@ def paginated_response(self, data: dict, pagination: dict) -> Response: "response": self.response, }, status=status.HTTP_200_OK, - ) \ No newline at end of file + ) + + +class ImageResponse: + def __init__(self,path:str): + fs = FileSystemStorage() + if fs.exists(path):self.file = fs.open(path) + else: self.file = None + + def exists(self) -> bool: + return False if self.file is None else True + + def get_success_response(self) -> Response: + return HttpResponse(self.file,status=status.HTTP_200_OK,content_type='image/png') + + def get_failure_response(self,http_status_code : int = status.HTTP_400_BAD_REQUEST) -> Response: + return HttpResponse(self.file,status=http_status_code,content_type='image/png') \ No newline at end of file diff --git a/utils/types.py b/utils/types.py index ca84a8d6..d300dc49 100644 --- a/utils/types.py +++ b/utils/types.py @@ -73,6 +73,7 @@ class WebHookCategory(Enum): USER_ROLE = 'user-role' USER = 'user' USER_NAME = 'user-name' + USER_PROFILE = 'user-profile' class RefferalType(Enum): diff --git a/utils/utils.py b/utils/utils.py index 49e2a209..7ce72127 100644 --- a/utils/utils.py +++ b/utils/utils.py @@ -17,7 +17,6 @@ from django.http import HttpResponse from django.template.loader import render_to_string - class CommonUtils: @staticmethod def get_paginated_queryset( @@ -172,7 +171,6 @@ def read_excel_file(self, file_obj): return rows - def send_template_mail( context: dict, subject: str, address: list[str], attachment: str = None): """