import logging from django.conf import settings from django.db.models import Count, Q from django.contrib import messages from django.contrib.auth import authenticate, login, logout from django.contrib.auth.views import LogoutView from django.contrib.auth.forms import PasswordResetForm from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.hashers import make_password from django.contrib.auth.views import ( LoginView, PasswordResetCompleteView, PasswordResetConfirmView, PasswordResetDoneView, PasswordResetView, ) from django.core.exceptions import ValidationError from django.http import JsonResponse from django.shortcuts import get_object_or_404, redirect, render from django.urls import reverse_lazy from django.views import generic from django.db import models, transaction, IntegrityError from django.utils import timezone import phonenumbers from accounts import permission from goodtimes import constants from goodtimes.services import EmailService, Encryptor from goodtimes.utils import JsonResponseUtil from manage_events.models import EventCategory, PrincipalPreference from manage_referrals.models import ReferralCode from manage_subscriptions.models import PrincipalSubscription, Subscription import datetime from datetime import datetime, timedelta from . import resource_action from .forms import ( CreateCustomerForm, CustomAuthenticationForm, IAmPrincipalForm, IAmPrincipalGroupRoleLinkForm, IAmPrincipalResourceLinkForm, IAmPrincipalRoleAppResourceActionLinkForm, IAmPrincipalGroupLinkForm, ProfileEditForm, UpdateCustomerForm, UploadExcelForm, ) from .models import ( IAmPrincipal, IAmPrincipalExtendedData, IAmPrincipalType, IAmAppResourceActionLink, IAmPrincipalGroup, IAmRole, ) logger = logging.getLogger(__name__) class AdminLoginView(generic.View): form_class = CustomAuthenticationForm template_name = "accounts/authentication/login.html" success_url = reverse_lazy("dashboard:main_dashboard") error_url = reverse_lazy("accounts:login") success_message = constants.LOGIN_SUCCESS error_message = "Login failed, Invalid email or password!" def get(self, request): form = self.form_class() return render(request, self.template_name, context={"form": form}) def post(self, request): form = self.form_class(data=request.POST) if not form.is_valid(): error_message = form.errors.get("__all__") or ["Invalid email or password."] messages.error( request, error_message[0] ) # Display the form-level error or fallback message return redirect(self.error_url) # Uncomment this block if you implement the first-time login logic # if not user.last_login: # messages.info(request, "Welcome! Since this is your first login, please change your password.") # return redirect(reverse_lazy('accounts:change_password')) login(request, form.user) return redirect(self.success_url) class AdminLogoutView(LogoutView): next_page = reverse_lazy("accounts:login") class CustomPasswordResetView(PasswordResetView): form_class = PasswordResetForm template_name = "accounts/authentication/password_reset_form.html" email_template_name = "accounts/authentication/password_reset_email_template.html" success_url = reverse_lazy("accounts:password_reset_done") class CustomPasswordResetDoneView(PasswordResetDoneView): template_name = "accounts/authentication/password_reset_done.html" class CustomPasswordResetConfirmView(PasswordResetConfirmView): template_name = "accounts/authentication/password_reset_confirm.html" success_url = reverse_lazy("accounts:password_reset_complete") class CustomPasswordResetCompleteView(PasswordResetCompleteView): template_name = "accounts/authentication/password_reset_complete.html" # class PrinicpalCreateView(generic.View): # model = IAmPrincipal # form_class = RegistrationForm # template_name = "registration/form.html" # title = "Add Sub admin" # success_message = constants.RECORD_CREATED # error_message = constants.ERROR_OCCURR # success_url = reverse_lazy("accounts:register") # def get_context_data(self, **kwargs): # context = {"title": self.title, "operation": "Add"} # context.update(kwargs) # return context # def get(self, *args, **kwargs): # form = self.form_class() # context = self.get_context_data(form=form) # return render(self.request, self.template_name, context=context) # def post(self, *args, **kwargs): # form = self.form_class(self.request.POST) # if not form.is_valid(): # messages.error(self.request, self.error_message) # context = self.get_context_data(form=form) # return render(self.request, self.template_name, context=context) # form.save() # messages.success(self.request, self.success_message) # return redirect(self.success_url) # template_name = "registration/password_reset_complete.html" class AdminDashboard(generic.View): template_name = "dashboard/index.html" def get(self, request): return render(request, self.template_name) """I Am Principal""" class PrincipalListView(LoginRequiredMixin, generic.ListView): page_name = resource_action.RESOURCE_IAM_PRINCIPAL # resource = resource_action.RESOURCE_IAM_PRINCIPAL # action = resource_action.ACTION_READ model = IAmPrincipal template_name = "accounts/iam_module/iam_principal_list.html" context_object_name = "data_obj" def get_queryset(self): return ( super() .get_queryset() .select_related("principal_type", "principal_source") .exclude( models.Q( principal_type__name=resource_action.PRINCIPAL_TYPE_EVENT_MANAGER ) | models.Q( principal_type__name=resource_action.PRINCIPAL_TYPE_EVENT_USER ) | models.Q( principal_type__name=resource_action.PRINCIPAL_TYPE_FREE_USER ) ) ) def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context["page_name"] = self.page_name return context class PrincipalCreateOrUpdateView(LoginRequiredMixin, generic.View): page_name = resource_action.RESOURCE_IAM_PRINCIPAL model = IAmPrincipal form_class = IAmPrincipalForm template_name = "accounts/iam_module/iam_principal_add.html" success_url = reverse_lazy("accounts:principal_list") success_message = "Saved Successfully" error_message = "An error occurred while saving the data." def get_object(self): pk = self.kwargs.get("pk") return get_object_or_404(self.model, pk=pk) if pk else None def get_context_data(self, **kwargs): context = { "page_name": self.page_name, "operation": "Edit" if self.object else "Add", } context.update(kwargs) # Include any additional context data passed to the view return context def get(self, request, *args, **kwargs): self.object = self.get_object() form = self.form_class(instance=self.object) context = self.get_context_data(form=form) return render(request, self.template_name, context=context) @transaction.atomic def post(self, request, *args, **kwargs): print(request.POST) self.object = self.get_object() form = self.form_class(request.POST, instance=self.object) try: if form.is_valid(): principal = form.save(commit=False) # Check if it's a new object (create action) or an existing one (update action) if not principal.pk: # pk is None for new objects principal.created_by = request.user principal.modified_by = request.user principal.modified_on = timezone.now() # Save the object principal.save() messages.success(request, "Form submitted successfully") return redirect(self.success_url) except Exception as e: self.error_message = constants.ERROR_OCCURR.format(str(e)) print(self.error_message) messages.error(request, self.error_message) context = self.get_context_data(form=form) return render(request, template_name=self.template_name, context=context) class PrincipalResourcePermissionEditView(permission.ResourcePermissionRequiredMixin, LoginRequiredMixin, generic.View): page_name = resource_action.RESOURCE_IAM_PRINCIPAL resource = resource_action.RESOURCE_IAM_PRINCIPAL_GROUP model = IAmPrincipal template_name = "accounts/iam_module/iam_principal_resource_permission_edit.html" form_class = IAmPrincipalResourceLinkForm success_url = reverse_lazy("accounts:principal_group_link_list") success_message = "Record Updated Successfully" error_message = "An error occurred while saving the data" def get_object(self): pk = self.kwargs.get("pk") return get_object_or_404(self.model, pk=pk) if pk else None def get_context_data(self, **kwargs): context = { "page_name": self.page_name, "operation": "Edit", } context.update(kwargs) # Include any additional context data passed to the view return context def get(self, request, *args, **kwargs): self.object = self.get_object() form = self.form_class(instance=self.object) context = self.get_context_data(form=form) return render(request, self.template_name, context=context) def post(self, request, *args, **kwargs): self.object = self.get_object() form = self.form_class(request.POST, instance=self.object) if not form.is_valid(): context = self.get_context_data(form=form) return render(request, self.template_name, context=context) form.save() messages.success(request, self.success_message) return redirect(self.success_url) """Principal Group Link""" class PrincipalGroupLinkListView(LoginRequiredMixin, generic.ListView): page_name = resource_action.RESOURCE_IAM_PRINCIPAL_GROUP model = IAmPrincipal template_name = "accounts/iam_module/iam_principal_group_link_list.html" context_object_name = "data_obj" def get_queryset(self): return ( super() .get_queryset() .select_related("principal_type", "principal_source") .prefetch_related("principal_group") ) def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context["page_name"] = self.page_name context["admin_principal"] = self.get_queryset().filter( principal_type__name=resource_action.PRINCIPAL_TYPE_ADMIN, is_active=True ) context["subadmin_principal"] = self.get_queryset().filter( principal_type__name=resource_action.PRINCIPAL_TYPE_SUBADMIN, is_active=True ) print(context["subadmin_principal"]) return context class PrincipalGroupLinkEditView(LoginRequiredMixin, generic.View): page_name = resource_action.RESOURCE_IAM_PRINCIPAL_GROUP model = IAmPrincipal template_name = "accounts/iam_module/iam_principal_group_link_edit.html" form_class = IAmPrincipalGroupLinkForm success_url = reverse_lazy("accounts:principal_group_link_list") success_message = "Record Updated Successfully" error_message = "An error occurred while saving the data" def get_object(self): pk = self.kwargs.get("pk") return get_object_or_404(self.model, pk=pk) if pk else None def get_context_data(self, **kwargs): context = { "page_name": self.page_name, "operation": "Edit", } context.update(kwargs) # Include any additional context data passed to the view return context def get(self, request, *args, **kwargs): self.object = self.get_object() form = self.form_class(instance=self.object) context = self.get_context_data(form=form) return render(request, self.template_name, context=context) def post(self, request, *args, **kwargs): self.object = self.get_object() form = self.form_class(request.POST, instance=self.object) if not form.is_valid(): context = self.get_context_data(form=form) return render(request, self.template_name, context=context) form.save() messages.success(request, self.success_message) return redirect(self.success_url) """Principal Group""" class PrincipalGroupListView(LoginRequiredMixin, generic.ListView): page_name = resource_action.RESOURCE_IAM_GROUP model = IAmPrincipalGroup template_name = "accounts/iam_module/iam_group_list.html" context_object_name = "data_obj" def get_queryset(self): return super().get_queryset().prefetch_related("role").filter(deleted=False) def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context["page_name"] = self.page_name return context class PrincipalGroupCreateOrUpdateView(LoginRequiredMixin, generic.View): page_name = resource_action.RESOURCE_IAM_GROUP page_title = "Principal Group" model = IAmPrincipalGroup template_name = "accounts/iam_module/iam_group_add.html" form_class = IAmPrincipalGroupRoleLinkForm success_url = reverse_lazy("accounts:principal_group_list") error_message = "An error occurred while saving the data." def get_success_message(self): self.success_message = ( constants.RECORD_CREATED if not self.object else constants.RECORD_UPDATED ) return self.success_message def get_object(self): pk = self.kwargs.get("pk") return get_object_or_404(self.model, pk=pk) if pk else None def get_context_data(self, **kwargs): context = { "page_name": self.page_name, "operation": "Add" if not self.object else "Edit", } context.update(kwargs) # Include any additional context data passed to the view return context def get(self, request, *args, **kwargs): self.object = self.get_object() form = self.form_class(instance=self.object) context = self.get_context_data(form=form) return render(request, self.template_name, context=context) def post(self, request, *args, **kwargs): self.object = self.get_object() form = self.form_class(request.POST, instance=self.object) if not form.is_valid(): print(form.errors) context = self.get_context_data(form=form) return render(request, self.template_name, context=context) form.save() messages.success(self.request, self.get_success_message()) return redirect(self.success_url) class PrincipalGroupDeleteView(LoginRequiredMixin, generic.View): page_name = resource_action.RESOURCE_IAM_GROUP model = IAmPrincipalGroup success_url = reverse_lazy("accounts:principal_group_list") success_message = constants.RECORD_DELETED error_message = constants.RECORD_NOT_FOUND def get(self, request, pk): try: type_obj = self.model.objects.get(id=pk) principal = IAmPrincipal.objects.filter(principal_group=type_obj).exists() if principal: messages.success( request, "You can't delete this record as it's assigned to principals.", ) else: type_obj.deleted = True type_obj.save() messages.success(request, self.success_message) except self.model.DoesNotExist: messages.success(request, self.error_message) return redirect(self.success_url) """ Role""" class AppRoleListView(LoginRequiredMixin, generic.ListView): page_name = resource_action.RESOURCE_IAM_ROLE model = IAmRole template_name = "accounts/iam_module/iam_role_list.html" context_object_name = "data_obj" def get_queryset(self): return ( super() .get_queryset() .prefetch_related( "app_resource_action", "app_resource_action__app_resource", "app_resource_action__app_action", ) .filter(deleted=False) ) def generate_role_data(self): roles = self.get_queryset() role_data = [] for role in roles: role_info = { "id": role.id, "name": role.name, "active": role.active, "resources": {}, } for link in role.app_resource_action.all(): resource = link.app_resource.name action = link.app_action.name if resource in role_info["resources"]: role_info["resources"][resource].append(action) else: role_info["resources"][resource] = [action] role_data.append(role_info) return role_data def get_context_data(self, **kwargs): context = {"page_name": self.page_name, "roles": self.generate_role_data()} context.update(kwargs) return context class AppRoleCreateOrUpdateView(LoginRequiredMixin, generic.View): page_name = resource_action.RESOURCE_IAM_ROLE model = IAmRole template_name = "accounts/iam_module/iam_role_add.html" form_class = IAmPrincipalRoleAppResourceActionLinkForm success_url = reverse_lazy("accounts:role_list") success_message = "Saved Successfully" error_message = "An error occurred while saving the data." def get_success_message(self): self.success_message = ( f"Record {'Created' if not self.object else 'Updated'} Successfully" ) return self.success_message def get_object(self): pk = self.kwargs.get("pk") return get_object_or_404(self.model, pk=pk) if pk else None def get_context_data(self, **kwargs): context = { "page_name": self.page_name, "operation": "Add" if not self.object else "Edit", "app_resource_action": IAmAppResourceActionLink.objects.generate_app_resource_action_data(), } context.update(kwargs) # Include any additional context data passed to the view return context def get(self, request, *args, **kwargs): try: self.object = self.get_object() form = self.form_class(instance=self.object) context = self.get_context_data(form=form) return render(request, self.template_name, context=context) except Exception as e: messages.error(request, str(e)) return redirect(self.success_url) def post(self, request, *args, **kwargs): try: self.object = self.get_object() form = self.form_class(request.POST, instance=self.object) if not form.is_valid(): print(form.errors) context = self.get_context_data(form=form) return render(request, self.template_name, context=context) form.save() messages.success(self.request, self.get_success_message()) return redirect(self.success_url) except Exception as e: messages.error(self.request, str(e)) return redirect(self.success_url) class AppRoleDeleteView(LoginRequiredMixin, generic.View): page_name = resource_action.RESOURCE_IAM_ROLE model = IAmRole success_url = reverse_lazy("accounts:role_list") success_message = constants.RECORD_DELETED error_message = constants.RECORD_NOT_FOUND def get(self, request, pk): try: type_obj = self.model.objects.get(id=pk) principal = IAmPrincipalGroup.objects.filter(role=type_obj).exists() if principal: messages.success( request, "You can't delete this record as it's assigned to groups." ) else: type_obj.deleted = True type_obj.save() messages.success(request, self.success_message) except self.model.DoesNotExist: messages.success(request, self.error_message) return redirect(self.success_url) """Customer""" class CustomerCheckEmail(generic.View): model = IAmPrincipal def post(self, request, *args, **kwargs): email = request.POST.get('email') print("check email is cllaed ", email) if self.model.objects.filter(email=email).exists(): print("exist called") return JsonResponse({'message': 'This email address is already in use.'}, status=400) else: print("email is valid") return JsonResponse({'message': 'Email is available.'}, status=200) class CustomerCreateView(LoginRequiredMixin, generic.View): page_name = resource_action.RESOURCE_MANAGE_CUSTOMER resource = resource_action.RESOURCE_MANAGE_CUSTOMER model = IAmPrincipal form_class = CreateCustomerForm template_name = "accounts/customer/customer_add.html" success_url = reverse_lazy("accounts:customer_list") success_message = "Saved Successfully" error_message = "An error occurred while saving the data." def get_context_data(self, **kwargs): context = { "page_name": self.page_name, "operation": "Add", } context.update(kwargs) # Include any additional context data passed to the view return context def get(self, request, *args, **kwargs): form = self.form_class() context = self.get_context_data(form=form) return render(request, self.template_name, context=context) def post(self, request, *args, **kwargs): print(request.POST) # return redirect(self.success_url) form = self.form_class(request.POST, request.FILES) context = self.get_context_data(form=form) if not form.is_valid(): return render(request, self.template_name, context=context) free_subscription = Subscription.objects.filter(is_free=True, active=True).first() if not free_subscription: messages.error(self.request, "Create a free subscription record for admin in manage subscription") return render(request, self.template_name, context=context) try: with transaction.atomic(): random_password = IAmPrincipal.generate_random_password() # Encrypt the password encryptor = Encryptor() encrypted_password = encryptor.encrypt(random_password) # save principal data principal_obj = IAmPrincipal.objects.create( profile_photo = form.cleaned_data.get("profile_photo"), email=form.cleaned_data.get('email'), first_name=form.cleaned_data.get('first_name'), last_name=form.cleaned_data.get('last_name'), business_name=form.cleaned_data.get('business_name'), phone_no=form.cleaned_data.get('phone_no'), password=make_password(random_password), username=form.cleaned_data.get("email"), email_verified=True, register_complete=True, principal_type=IAmPrincipalType.objects.get(name=resource_action.PRINCIPAL_TYPE_EVENT_MANAGER), address_line1=form.cleaned_data.get("address_line1"), city=form.cleaned_data.get("city"), country=form.cleaned_data.get("country"), website=form.cleaned_data.get("website"), linkedin_profile=form.cleaned_data.get("linkedin_profile"), facebook_profile=form.cleaned_data.get("facebook_profile"), instagram_profile=form.cleaned_data.get("instagram_profile"), twitter_profile=form.cleaned_data.get("twitter_profile"), ) # generate referralcode of manager ReferralCode.create_referral_code_for_user_manager( principal=principal_obj, principal_type=principal_obj.principal_type ) IAmPrincipalExtendedData.objects.create( principal=principal_obj, is_onboarded=True, encrypted_pass=encrypted_password, # Save encrypted password ) # save principal preferences record principal_preference = PrincipalPreference.objects.create(principal=principal_obj) principal_preference.preferred_categories.set(form.cleaned_data.get("preferences")) principal_subscription = PrincipalSubscription.objects.create( start_date=form.cleaned_data.get("free_start_date"), end_date=form.cleaned_data.get("free_end_date"), principal=principal_obj, grace_period_end_date=PrincipalSubscription.generate_grace_period_end_date(form.cleaned_data.get("free_end_date")), is_paid=True, subscription=free_subscription ) messages.success(self.request, constants.REGISTRATION_SUCCESS) return redirect(self.success_url) except Exception as e: print("errror is ", e) messages.error(self.request, str(e)) context = self.get_context_data(form=form) return render(request, self.template_name, context=context) class CustomerUpdateView(LoginRequiredMixin, generic.View): page_name = resource_action.RESOURCE_MANAGE_CUSTOMER resource = resource_action.RESOURCE_MANAGE_CUSTOMER model = IAmPrincipal form_class = UpdateCustomerForm template_name = "accounts/customer/customer_edit.html" success_url = reverse_lazy("accounts:customer_list") success_message = "Updated Successfully" error_message = "An error occurred while saving the data." def get_context_data(self, **kwargs): context = { "page_name": self.page_name, "operation": "Edit", } context.update(kwargs) # Include any additional context data passed to the view return context def get(self, request, *args, **kwargs): principal_id = kwargs.get("pk") try: principal_obj = IAmPrincipal.objects.get(pk=principal_id) except Exception as e: messages.error(request, f"No Record of id {principal_id} is found") return redirect(self.success_url) print(f"principal address is {principal_obj.address_line1}") initial_data = { "profile_photo": principal_obj.profile_photo, "first_name": principal_obj.first_name, "last_name": principal_obj.last_name, "email": principal_obj.email, "business_name": principal_obj.business_name, "phone_no": principal_obj.phone_no, "address_line1": principal_obj.address_line1, "city": principal_obj.city, "country": principal_obj.country, "website": principal_obj.website, "linkedin_profile": principal_obj.linkedin_profile, "facebook_profile": principal_obj.facebook_profile, "instagram_profile": principal_obj.instagram_profile, "twitter_profile": principal_obj.twitter_profile, "active": principal_obj.is_active } try: principal_preference = PrincipalPreference.objects.get(principal=principal_obj) initial_data["preferences"] = list(principal_preference.preferred_categories.all().values_list("id", flat=True)) except PrincipalPreference.DoesNotExist: initial_data["preferences"] = [] try: subscription = PrincipalSubscription.objects.filter(principal=principal_obj).latest("created_on") initial_data["free_start_date"] = subscription.start_date initial_data["free_end_date"] = subscription.end_date except PrincipalSubscription.DoesNotExist: initial_data["free_start_date"] = None initial_data["free_end_date"] = None form = self.form_class(initial=initial_data) context = self.get_context_data(form=form, principal_obj=principal_obj) print("context dta is ", context) return render(request, self.template_name, context=context) def post(self, request, *args, **kwargs): principal_id = kwargs.get("pk") try: principal_obj = IAmPrincipal.objects.get(pk=principal_id) except Exception as e: messages.error(request, f"No Record of customer id {principal_id} is found") return redirect(self.success_url) form = self.form_class(request.POST, request.FILES) print(request.POST) if not form.is_valid(): context = self.get_context_data(form=form) return render(request, self.template_name, context=context) try: with transaction.atomic(): # update principal data principal_obj.profile_photo = form.cleaned_data.get('profile_photo') principal_obj.first_name = form.cleaned_data.get('first_name') principal_obj.last_name = form.cleaned_data.get('last_name') principal_obj.business_name = form.cleaned_data.get("business_name") principal_obj.phone_no = form.cleaned_data.get("phone_no") principal_obj.address_line1 = form.cleaned_data.get("address_line1") principal_obj.city = form.cleaned_data.get("city") principal_obj.country = form.cleaned_data.get("country") principal_obj.website = form.cleaned_data.get("website") principal_obj.linkedin_profile = form.cleaned_data.get("linkedin_profile") principal_obj.facebook_profile = form.cleaned_data.get("facebook_profile") principal_obj.instagram_profile = form.cleaned_data.get("instagram_profile") principal_obj.twitter_profile = form.cleaned_data.get("twitter_profile") principal_obj.is_active = form.cleaned_data.get("active") principal_obj.save() # update principal preferences record principal_preference, _ = PrincipalPreference.objects.get_or_create(principal=principal_obj) principal_preference.preferred_categories.set(form.cleaned_data.get("preferences")) # update principal subscription record principal_subscription = PrincipalSubscription.objects.filter(principal=principal_obj).order_by('-end_date').first() if principal_subscription: principal_subscription.start_date = form.cleaned_data.get("free_start_date") principal_subscription.end_date = form.cleaned_data.get("free_end_date") principal_subscription.grace_period_end_date = form.cleaned_data.get("free_end_date") + timedelta(days=15) principal_subscription.save() else: PrincipalSubscription.objects.create( principal=principal_obj, start_date=form.cleaned_data.get("free_start_date"), end_date=form.cleaned_data.get("free_end_date"), grace_period_end_date=PrincipalSubscription.generate_grace_period_end_date(form.cleaned_data.get("free_end_date")), is_paid=True, subscription=Subscription.objects.filter().first() # Assuming you want to link a default subscription ) messages.success(self.request, self.success_message) return redirect(self.success_url) except Exception as e: messages.error(self.request, str(e)) context = self.get_context_data(form=form) return render(request, self.template_name, context=context) class CustomerDetailView(LoginRequiredMixin, generic.DetailView): page_name = resource_action.RESOURCE_MANAGE_CUSTOMER resource = resource_action.RESOURCE_MANAGE_CUSTOMER action = resource_action.ACTION_READ template_name = 'accounts/customer/customer_detail.html' def get_context_data(self, **kwargs): context = { "page_name": self.page_name, } context.update(kwargs) # Include any additional context data passed to the view return context def get(self, request, *args, **kwargs): principal_obj = IAmPrincipal.objects.get(pk=kwargs.get("pk")) try: principal_preference = PrincipalPreference.objects.get(principal_id=principal_obj.id) except Exception as e: principal_preference = None principal_subscription = PrincipalSubscription.objects.filter(principal=principal_obj).order_by("-start_date").first() context = self.get_context_data(principal_obj=principal_obj,principal_preference=principal_preference,principal_subscription=principal_subscription) return render(request, self.template_name, context=context) class CustomerListView(LoginRequiredMixin, generic.ListView): page_name = resource_action.RESOURCE_MANAGE_CUSTOMER resource = resource_action.RESOURCE_MANAGE_CUSTOMER action = resource_action.ACTION_READ model = IAmPrincipal template_name = "accounts/customer/customer_list.html" context_object_name = "data_objs" def get_queryset(self): queryset = ( super() .get_queryset() .select_related("principal_type", "principal_source", "extended_data") .filter( models.Q( principal_type__name=resource_action.PRINCIPAL_TYPE_EVENT_MANAGER ) | models.Q( principal_type__name=resource_action.PRINCIPAL_TYPE_EVENT_USER ) | models.Q( principal_type__name=resource_action.PRINCIPAL_TYPE_FREE_USER ), ) ) # Annotate the queryset with the count of referrals for each principal queryset = queryset.annotate( referral_count=Count( "referrals_by_referrer", filter=Q( referrals_by_referrer__is_completed=True ), # Assuming you only want to count completed referrals distinct=True, # Ensures referrals are not double-counted if there are multiple conditions or joins ) ) return queryset def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context["page_name"] = self.page_name return context class GetDecryptedPasswordView(generic.View): def get(self, request, customer_id): try: # Fetch the extended data for the customer extended_data = IAmPrincipalExtendedData.objects.get(principal_id=customer_id) if not extended_data.encrypted_pass: return JsonResponse({"success": False, "message": "No password found."}) # Use Encryptor to decrypt the password encryptor = Encryptor() decrypted_password = encryptor.decrypt(extended_data.encrypted_pass) return JsonResponse({"success": True, "decrypted_password": decrypted_password}) except IAmPrincipalExtendedData.DoesNotExist: return JsonResponse({"success": False, "message": "Customer not found."}) except Exception as e: return JsonResponse({"success": False, "message": str(e)}) import pandas as pd from openpyxl import Workbook, load_workbook from openpyxl.worksheet.datavalidation import DataValidation from openpyxl.styles import Font from django.http import HttpResponse # def export_excel_template(request): # # Define the columns and create an empty DataFrame # columns = ['First Name', 'Last Name', 'Email', 'Preferences', 'Free period start date', 'Free period end date'] # df = pd.DataFrame(columns=columns) # # Create a workbook and select the active worksheet # wb = Workbook() # ws = wb.active # ws.title = 'Customer Registration' # # # Write the column headers # # for col_num, column_title in enumerate(df.columns, 1): # # cell = ws.cell(row=1, column=col_num, value=column_title) # # cell.font = Font(bold=True) # # # Create a hidden sheet for preferences # # ws_prefs = wb.create_sheet(title="Preferences") # # ws_prefs.sheet_state = 'hidden' # # # Fetch preferences options from the EventCategory model # # preferences_options = EventCategory.objects.values_list('title', flat=True) # # # Write preferences to the hidden sheet # # for row_num, preference in enumerate(preferences_options, 1): # # ws_prefs.cell(row=row_num, column=1, value=preference) # # # Define the range for preferences in the hidden sheet # # preferences_range = f"Preferences!$A$1:$A${len(preferences_options)}" # # # Add Data Validation for preferences (drop-down list) # # dv_preferences = DataValidation( # # type="list", # # formula1=preferences_range, # # allow_blank=True, # # showDropDown=True # # ) # # ws.add_data_validation(dv_preferences) # # dv_preferences.add(f'D2:D1048576') # Apply to the whole column # # # Add Data Validation for date comparison # # dv_start_date = DataValidation( # # type="date", # # operator="greaterThan", # # formula1='"1900-01-01"', # # showErrorMessage=True # # ) # # dv_end_date = DataValidation( # # type="custom", # # formula1="=AND(ISNUMBER(F2), F2>E2)", # # showErrorMessage=True, # # errorTitle="Invalid Date", # # error="End date must be greater than start date." # # ) # # ws.add_data_validation(dv_start_date) # # ws.add_data_validation(dv_end_date) # # dv_start_date.add(f'E2:E1048576') # # dv_end_date.add(f'F2:F1048576') # # Save the workbook to a bytes buffer # response = HttpResponse(content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') # response['Content-Disposition'] = 'attachment; filename=customer_registration_template.xlsx' # wb.save(response) # return response # from openpyxl.styles import Font def export_excel_template(request): # Define the columns for the Customer Registration sheet columns = [ 'First Name', 'Last Name', 'Business Name', 'Email', 'Phone No (+919999999999)', 'Preferences (should be separated by comma)', 'Free period start date (DD-MM-YYYY)', 'Free period end date (DD-MM-YYYY)', 'Address', 'Region', 'Country', 'Website', 'LinkedIn', 'Facebook', 'Instagram', 'Twitter', ] df = pd.DataFrame(columns=columns) # Create a workbook and add the Customer Registration worksheet wb = Workbook() ws_customer = wb.active ws_customer.title = 'Manager Onboarding' # Write the column headers for the Customer Registration sheet for col_num, column_title in enumerate(df.columns, 1): cell = ws_customer.cell(row=1, column=col_num, value=column_title) cell.font = Font(bold=True) # Create the Readme worksheet ws_readme = wb.create_sheet(title='Readme') # Add information about each field to the Readme sheet readme_data = [ ['Field Name', 'Description'], ['First Name', 'The first name of the customer. This is a required field.'], ['Last Name', 'The last name of the customer. This is a required field.'], ['Business Name', 'The official name of the customer\'s business or organization.'], ['Email', 'The email address of the customer. This must be a unique email not already used in the system. This is a required Field'], ['Phone No', 'The business phone number. It should include the country code if applicable (+919999999999).'], ['Category', 'A comma-separated list of event categories the customer is interested in. These should match existing categories in the system. This is a required Field'], ['Free period start date', 'The start date of the customer\'s free trial period, formatted as DD-MM-YYYY.'], ['Free period end date', 'The end date of the customer\'s free trial period, formatted as DD-MM-YYYY. This date must be later than the start date.'], ['Address', 'The complete business address, including street, city, and postal code.'], ['Region', 'The geographic region where the business operates.'], ['Country', 'The country where the business is based.'], ['Website', 'The URL of the business\'s official website. Ensure it includes "http://" or "https://".'], ['LinkedIn', 'The LinkedIn profile URL of the business. Ensure it includes "http://" or "https://".'], ['Facebook', 'The Facebook page URL of the business. Ensure it includes "http://" or "https://".'], ['Instagram', 'The Instagram profile URL of the business. Ensure it includes "http://" or "https://".'], ['Twitter', 'The Twitter handle or profile URL of the business. Ensure it includes "http://" or "https://".'], ] # Write the Readme data to the Readme worksheet for row_num, row_data in enumerate(readme_data, 1): for col_num, cell_value in enumerate(row_data, 1): cell = ws_readme.cell(row=row_num, column=col_num, value=cell_value) if row_num == 1: # Make the header bold cell.font = Font(bold=True) # Save the workbook to a bytes buffer response = HttpResponse(content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') response['Content-Disposition'] = 'attachment; filename=customer_registration_template.xlsx' wb.save(response) return response class CustomerTransferView(LoginRequiredMixin, generic.View): model = IAmPrincipal def get(self, request, *args, **kwargs): try: principal_obj = self.model.objects.get(pk=kwargs.get("pk")) except self.model.DoesNotExist: messages.error(request, "Something went wrong") return redirect(reverse_lazy("accounts:customer_detail")) email_service = EmailService( subject="Your Exclusive Account Access Details with Good Times!", to=principal_obj.email, from_email=settings.DEFAULT_FROM_EMAIL, ) # Send the email try: principal_preference = IAmPrincipalExtendedData.objects.get(principal=principal_obj) # Use Encryptor to decrypt the password encryptor = Encryptor() temp_password = encryptor.decrypt(principal_preference.encrypted_pass) # updating password principal_obj.password = make_password(temp_password) principal_obj.save() principal_preference.is_transferred = True principal_preference.save() email_service.load_template( "accounts/customer/account_transfer_email_template.html", locals() ) email_service.send() messages.success(request, "Account Transfer mail send successfully") except Exception as e: messages.error(request, f"{str(e)}") return redirect(reverse_lazy("accounts:customer_detail", kwargs={"pk": kwargs.get("pk")})) class CustomerImportView(LoginRequiredMixin, generic.View): page_name = resource_action.RESOURCE_MANAGE_CUSTOMER resource = resource_action.RESOURCE_MANAGE_CUSTOMER action = resource_action.ACTION_READ template_name = "accounts/customer/customer_bulk_template.html" form_class = UploadExcelForm def get_context_data(self, **kwargs): context = { "page_name": self.page_name, } context.update(kwargs) # Include any additional context data passed to the view return context def validate_date(self, date_str, row_num, error_log, field_name): """function to validate the date format DD-MM-YYYY""" # Check if the input is already a datetime object if isinstance(date_str, datetime): return date_str # If it's a string, attempt to validate it if isinstance(date_str, str): try: return datetime.strptime(date_str, '%d-%m-%Y') except ValueError: error_log.append(f"Row {row_num}: {field_name} '{date_str}' is not in the format DD-MM-YYYY.") return None # If it's neither a string nor a datetime object, log an error error_log.append(f"Row {row_num}: {field_name} '{date_str}' is of invalid type.") return None def validate_phone(self, phone_str, row_num, error_log): """Helper function to validate phone number""" try: phone_number = phonenumbers.parse(phone_str, None) if not phonenumbers.is_valid_number(phone_number): error_log.append(f"Row {row_num}: Phone number '{phone_str}' is not valid.") return None return phone_number except Exception as e: error_log.append(f"Row {row_num}: Phone number '{phone_str}' could not be parsed.") return None def get(self, request, *args, **kwargs): form = self.form_class() context = self.get_context_data(form=form) return render(request, self.template_name, context=context) def post(self, request, *args, **kwargs): form = self.form_class(request.POST, request.FILES) context = self.get_context_data(form=form) if not form.is_valid(): print(form.errors) return render(request, self.template_name, context=context) excel_file = request.FILES['file'] wb = load_workbook(filename=excel_file) # Check if the specific sheet exists if 'Manager Onboarding' not in wb.sheetnames: form.add_error('file', 'The required sheet "Manager Onboarding" is not present in the uploaded file.') return render(request, self.template_name, context=context) # Load the "Manager Onboarding" worksheet ws = wb['Manager Onboarding'] error_log = [] principals = [] preferences_list = [] subscriptions = [] principal_type = IAmPrincipalType.objects.get(name=resource_action.PRINCIPAL_TYPE_EVENT_MANAGER) free_subscription = Subscription.objects.filter(is_free=True, active=True).first() if not free_subscription: messages.error(self.request, "Create a free subscription record for admin in manage subscription") return render(request, self.template_name, context=context) for idx, row in enumerate(ws.iter_rows(min_row=2, values_only=True), start=2): first_name, last_name, business_name, email, phone_no, preferences, start_date, end_date, address, region, country, website, linkedin, facebook, instagram, twitter = row print(f"{first_name}, {last_name, email, preferences, start_date, end_date}") # validate all data if not first_name or not last_name or not email or not preferences or not start_date or not end_date: error_log.append(f"Row {idx}: Missing data.") continue # validate email existence if IAmPrincipal.objects.filter(email=email).exists(): error_log.append(f"Row {idx}: Email {email} already exists.") continue # Validate start_date and end_date formats start_date = self.validate_date(start_date, idx, error_log, 'Start Date') end_date = self.validate_date(end_date, idx, error_log, 'End Date') if not start_date or not end_date: continue # Skip if dates are invalid # validate date rnage if end_date < start_date: error_log.append(f"Row {idx}: End date {end_date} must greater then start date {start_date}.") continue # Validate phone number if phone_no: phone_number = self.validate_phone(str(phone_no), idx, error_log) if not phone_number: continue # Skip if phone number is invalid # validate preferences preference_list = [pref.strip() for pref in preferences.split(',')] event_categories = EventCategory.objects.filter(title__in=preference_list) if len(event_categories) != len(preference_list): error_log.append(f"Row {idx}: One or more preferences are invalid.") continue random_password = IAmPrincipal.generate_random_password() # Encrypt the password encryptor = Encryptor() encrypted_password = encryptor.encrypt(random_password) # collect the principals principal = IAmPrincipal( first_name=first_name.strip().capitalize(), last_name=last_name.strip().capitalize(), email=email.strip(), password=make_password(random_password), username=email.strip(), email_verified=True, register_complete=True, principal_type=principal_type, business_name=business_name, phone_no=phone_no, address_line1=address, city=region, country=country, website=website, linkedin_profile=linkedin, facebook_profile=facebook, instagram_profile=instagram, twitter_profile=twitter ) principals.append(principal) # Collect preferences to be set later preferences_list.append((principal, event_categories, start_date, end_date)) if error_log: context = self.get_context_data(form=form, error_log=error_log) messages.error(request, "No record is created check error log and fix the error in the file ") return render(request, self.template_name, context=context) # Use transaction.atomic to ensure all-or-nothing with transaction.atomic(): # Bulk create principals for principal in principals: principal.save() # Now we need to refresh principals from the DB to get their IDs principals = IAmPrincipal.objects.filter(email__in=[p.email for p in principals]) # Create subscriptions and preferences for principal, event_categories, start_date, end_date in preferences_list: principal = principals.get(email=principal.email) # Generate referral code for the manager ReferralCode.create_referral_code_for_user_manager(principal=principal, principal_type=principal_type) # Create IAmPrincipalExtendedData record IAmPrincipalExtendedData.objects.create(principal=principal, is_onboarded=True,encrypted_pass=encrypted_password,) # Create PrincipalSubscription record subscription = PrincipalSubscription( principal=principal, start_date=start_date, end_date=end_date, grace_period_end_date=PrincipalSubscription.generate_grace_period_end_date(end_date), is_paid=True, subscription=free_subscription ) subscriptions.append(subscription) # Create PrincipalPreferences record preference = PrincipalPreference(principal=principal) preference.save() preference.preferred_categories.set(event_categories) # Bulk create subscriptions PrincipalSubscription.objects.bulk_create(subscriptions) messages.success(request, "Data imported successfully") return render(request, self.template_name, context=context) class CustomerExportView(LoginRequiredMixin, generic.View): model = IAmPrincipal def get(self, request, *args, **kwargs): princiapls = IAmPrincipal.objects.select_related("extended_data").filter(principal_type__name=resource_action.PRINCIPAL_TYPE_EVENT_MANAGER) # prepare data for excel file data = [] for principal in princiapls: data.append([ principal.email, principal.first_name, principal.last_name, str(principal.phone_no) if principal.phone_no else "N/A", principal.email_verified, principal.is_active, # principal.extended_data.is_onboarded if principal.extended_data else 'N/A', # principal.extended_data.is_transferred if principal.extended_data else 'N/A', # principal.created_on.replace(tzinfo=None) if principal.created_on else 'N/A' ]) # Define the columns for the Excel file columns = ["Email", "First Name", "Last Name", "Phone Number", "Email Verified", "Active"] # Create a workbook and select the active worksheet wb = Workbook() ws = wb.active ws.title = "Event Managers List" # Write the column headers for col_num, column_title in enumerate(columns, 1): cell = ws.cell(row=1, column=col_num, value=column_title) cell.font = Font(bold=True) # write the data rows for row_num, row_data in enumerate(data, 2): for col_num, cell_value in enumerate(row_data, 1): ws.cell(row=row_num, column=col_num, value=cell_value) response = HttpResponse(content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') response['Content-Disposition'] = 'attachment; filename=event_managers.xlsx' wb.save(response) return response class DatatableListView(LoginRequiredMixin, generic.ListView): pass class PrincipalProfileView(LoginRequiredMixin, generic.ListView): page_name = resource_action.RESOURCE_MANAGE_DASHBOARD model = IAmPrincipal template_name = "accounts/iam_module/profile_details.html" context_object_name = "data_obj" def get_queryset(self): return ( super() .get_queryset() .select_related("principal_type", "principal_source") .get(id=self.request.user.id) ) def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context["page_name"] = self.page_name return context class PrincipalProfileEditView(LoginRequiredMixin, generic.View): page_name = resource_action.RESOURCE_MANAGE_DASHBOARD model = IAmPrincipal template_name = "accounts/iam_module/profile_details_edit.html" form_class = ProfileEditForm success_url = reverse_lazy("accounts:profile_details") success_message = "Saved Successfully" error_message = "An error occurred while saving the data." def get_success_message(self): self.success_message = ( f"Record {'Created' if not self.object else 'Updated'} Successfully" ) return self.success_message def get_object(self): return self.request.user def get_context_data(self, **kwargs): context = { # "page_name": self.page_name, "operation": "Edit", "page_name": self.page_name, } context.update(kwargs) # Include any additional context data passed to the view return context def get(self, request, *args, **kwargs): # try: self.object = self.get_object() form = self.form_class(instance=self.object) context = self.get_context_data(form=form) return render(request, self.template_name, context=context) # except Exception as e: # print("error in project ", str) # messages.error(request, str(e)) # return redirect(self.success_url) def post(self, request, *args, **kwargs): self.object = self.get_object() form = self.form_class(request.POST, request.FILES, instance=self.object) if not form.is_valid(): print(form.errors) context = self.get_context_data(form=form) return render(request, self.template_name, context=context) form.save() messages.success(self.request, self.get_success_message()) return redirect(self.success_url)