Files
goodtimes/accounts/views.py
2025-01-08 12:37:07 +05:30

1397 lines
56 KiB
Python

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)