feat(customer): customer cred and postcode for address
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 5.0.2 on 2024-12-20 12:15
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('accounts', '0015_iamprincipal_twitter_profile'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='iamprincipalextendeddata',
|
||||
name='encrypted_pass',
|
||||
field=models.TextField(blank=True, null=True),
|
||||
),
|
||||
]
|
||||
@@ -13,6 +13,7 @@ from django.utils.text import slugify
|
||||
from phonenumber_field.modelfields import PhoneNumberField
|
||||
|
||||
# from manage_subscriptions.models import Subscription
|
||||
|
||||
from goodtimes.utils import RandomGenerator
|
||||
from .resource_action import (
|
||||
PRINCIPAL_TYPE_EVENT_USER,
|
||||
@@ -334,8 +335,15 @@ class IAmPrincipal(AbstractUser):
|
||||
def __str__(self):
|
||||
return f"{self.email}"
|
||||
|
||||
@staticmethod
|
||||
def generate_random_password():
|
||||
"""Generate a password in the format 'GoodTimes@xxxx'."""
|
||||
random_number = random.randint(1000, 9999) # Generate a 4-digit random number
|
||||
return f"GoodTimes@{random_number}"
|
||||
|
||||
|
||||
class IAmPrincipalExtendedData(models.Model):
|
||||
|
||||
principal = models.OneToOneField(
|
||||
IAmPrincipal,
|
||||
related_name="extended_data",
|
||||
@@ -356,7 +364,7 @@ class IAmPrincipalExtendedData(models.Model):
|
||||
help_text="The date and time when the account was transferred to the user."
|
||||
)
|
||||
pwd_changed_post_transfer = models.BooleanField(default=False, help_text="Indicates if the user changed their password after the account was transferred.")
|
||||
|
||||
encrypted_pass = models.TextField(blank=True, null=True)
|
||||
class Meta:
|
||||
db_table = "iam_principal_extended_data"
|
||||
|
||||
@@ -368,6 +376,12 @@ class IAmPrincipalExtendedData(models.Model):
|
||||
self.transferred_on = datetime.datetime.now()
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
@property
|
||||
def decrypted_field(self):
|
||||
from goodtimes.services import Encryptor
|
||||
encryptor = Encryptor()
|
||||
return encryptor.decrypt(self.encrypted_pass)
|
||||
|
||||
class IAmPrincipalResourceLink(models.Model):
|
||||
principal = models.ForeignKey(
|
||||
IAmPrincipal,
|
||||
|
||||
@@ -42,6 +42,7 @@ urlpatterns = [
|
||||
path('principal/role/delete/<int:pk>/', views.AppRoleDeleteView.as_view(), name="role_delete"),
|
||||
|
||||
path('customer/', views.CustomerListView.as_view(), name="customer_list"),
|
||||
path('customer/get-decrypted-password/<int:customer_id>/', views.GetDecryptedPasswordView.as_view(), name='get_decrypted_password'),
|
||||
path('customer/add/', views.CustomerCreateView.as_view(), name="customer_add"),
|
||||
path('customer/edit/<int:pk>/', views.CustomerUpdateView.as_view(), name="customer_edit"),
|
||||
path('customer/detail/<int:pk>/', views.CustomerDetailView.as_view(), name="customer_detail"),
|
||||
|
||||
@@ -24,7 +24,7 @@ from django.utils import timezone
|
||||
import phonenumbers
|
||||
from accounts import permission
|
||||
from goodtimes import constants
|
||||
from goodtimes.services import EmailService
|
||||
from goodtimes.services import EmailService, Encryptor
|
||||
from goodtimes.utils import JsonResponseUtil
|
||||
from manage_events.models import EventCategory, PrincipalPreference
|
||||
from manage_referrals.models import ReferralCode
|
||||
@@ -621,6 +621,12 @@ class CustomerCreateView(LoginRequiredMixin, generic.View):
|
||||
|
||||
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(
|
||||
email=form.cleaned_data.get('email'),
|
||||
@@ -628,7 +634,7 @@ class CustomerCreateView(LoginRequiredMixin, generic.View):
|
||||
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("goodtimes#2024"),
|
||||
password=make_password(random_password),
|
||||
username=form.cleaned_data.get("email"),
|
||||
email_verified=True,
|
||||
register_complete=True,
|
||||
@@ -651,6 +657,7 @@ class CustomerCreateView(LoginRequiredMixin, generic.View):
|
||||
IAmPrincipalExtendedData.objects.create(
|
||||
principal=principal_obj,
|
||||
is_onboarded=True,
|
||||
encrypted_pass=encrypted_password, # Save encrypted password
|
||||
)
|
||||
|
||||
# save principal preferences record
|
||||
@@ -665,7 +672,6 @@ class CustomerCreateView(LoginRequiredMixin, generic.View):
|
||||
is_paid=True,
|
||||
subscription=free_subscription
|
||||
)
|
||||
|
||||
messages.success(self.request, constants.REGISTRATION_SUCCESS)
|
||||
return redirect(self.success_url)
|
||||
except Exception as e:
|
||||
@@ -863,6 +869,27 @@ class CustomerListView(LoginRequiredMixin, generic.ListView):
|
||||
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
|
||||
@@ -1022,7 +1049,7 @@ class CustomerTransferView(LoginRequiredMixin, generic.View):
|
||||
|
||||
# Send the email
|
||||
try:
|
||||
temp_password = "goodtimes#2024"
|
||||
temp_password = "GoodTimes@2025"
|
||||
principal_obj.password = make_password(temp_password)
|
||||
principal_obj.save()
|
||||
email_service.load_template(
|
||||
@@ -1159,12 +1186,18 @@ class CustomerImportView(LoginRequiredMixin, generic.View):
|
||||
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("goodtimes#2024"),
|
||||
password=make_password(random_password),
|
||||
username=email.strip(),
|
||||
email_verified=True,
|
||||
register_complete=True,
|
||||
@@ -1207,7 +1240,7 @@ class CustomerImportView(LoginRequiredMixin, generic.View):
|
||||
ReferralCode.create_referral_code_for_user_manager(principal=principal, principal_type=principal_type)
|
||||
|
||||
# Create IAmPrincipalExtendedData record
|
||||
IAmPrincipalExtendedData.objects.create(principal=principal, is_onboarded=True)
|
||||
IAmPrincipalExtendedData.objects.create(principal=principal, is_onboarded=True,encrypted_pass=encrypted_password,)
|
||||
|
||||
# Create PrincipalSubscription record
|
||||
subscription = PrincipalSubscription(
|
||||
|
||||
@@ -726,9 +726,6 @@ class FacebookPoster:
|
||||
self.facebook_api = facebook_api
|
||||
|
||||
def post_photo(self, image_url, caption):
|
||||
if not self.facebook_api.authenticate():
|
||||
print("Authentication failed. Please try again.")
|
||||
return {'success': False, 'message': 'Error posting photo. Authenticate failed'}
|
||||
result = self.facebook_api.post_photo(image_url, caption)
|
||||
if not result:
|
||||
return {'success': False, 'message': 'Error posting photo in Facebook'}
|
||||
@@ -1130,4 +1127,18 @@ class StripeService:
|
||||
)
|
||||
return {'success': True, 'data': subscription}
|
||||
except stripe.error.StripeError as e:
|
||||
|
||||
return {'success': False, 'message': f'Error cancelling subscription auto-renewal: {e}'}
|
||||
|
||||
from cryptography.fernet import Fernet
|
||||
class Encryptor:
|
||||
def __init__(self):
|
||||
self.key = "paMSf3Ny8KAMs1tRLcVOQQhRxTnInHLwP7WtVdm8O_4="
|
||||
self.fernet = Fernet(self.key)
|
||||
|
||||
def encrypt(self, plaintext):
|
||||
return self.fernet.encrypt(plaintext.encode()).decode()
|
||||
|
||||
def decrypt(self, encrypted_text):
|
||||
return self.fernet.decrypt(encrypted_text.encode()).decode()
|
||||
|
||||
|
||||
@@ -77,6 +77,7 @@ THIRD_PARTY_APPS = [
|
||||
"taggit",
|
||||
"django_quill",
|
||||
"corsheaders",
|
||||
'django_extensions',
|
||||
"allauth",
|
||||
"allauth.account",
|
||||
"allauth.socialaccount",
|
||||
@@ -211,6 +212,7 @@ TIME_FORMAT = "H:i p"
|
||||
|
||||
# otp expire time limit
|
||||
OTP_EXPIRE_TIME = 1 # mins
|
||||
DEFAULT_CHARSET = 'utf-8'
|
||||
|
||||
|
||||
# Default primary key field type
|
||||
|
||||
@@ -139,6 +139,7 @@ class CreateVenueApi(APIView):
|
||||
def post(self, request):
|
||||
|
||||
data = request.data.copy()
|
||||
print("prindata is ", data)
|
||||
|
||||
# Convert latitude and longitude to float and round to 8 decimal places
|
||||
data["latitude"] = round(float(data["latitude"]), 8)
|
||||
|
||||
@@ -148,6 +148,7 @@ class VenueForm(forms.ModelForm):
|
||||
required=True
|
||||
)
|
||||
image = forms.ImageField(required=True)
|
||||
postcode = forms.CharField(required=True, max_length=10)
|
||||
latitude = forms.DecimalField(
|
||||
widget=forms.NumberInput()
|
||||
)
|
||||
@@ -161,6 +162,7 @@ class VenueForm(forms.ModelForm):
|
||||
"principal",
|
||||
"title",
|
||||
"address",
|
||||
"postcode",
|
||||
"image",
|
||||
"latitude",
|
||||
"longitude",
|
||||
|
||||
18
manage_events/migrations/0017_venue_postcode.py
Normal file
18
manage_events/migrations/0017_venue_postcode.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 5.0.2 on 2024-12-20 09:29
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('manage_events', '0016_freeusagefeaturelimit'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='venue',
|
||||
name='postcode',
|
||||
field=models.CharField(blank=True, max_length=20, null=True),
|
||||
),
|
||||
]
|
||||
@@ -51,6 +51,7 @@ class Venue(BaseModel):
|
||||
longitude = models.DecimalField(
|
||||
max_digits=14, decimal_places=8, blank=True, null=True
|
||||
)
|
||||
postcode = models.CharField(max_length=20, blank=True, null=True)
|
||||
|
||||
def __str__(self):
|
||||
return self.title
|
||||
|
||||
@@ -599,6 +599,8 @@ class SocialMediaPostView(generic.View):
|
||||
|
||||
image_url = request.build_absolute_uri(event.image.url)
|
||||
if platform in ['facebook', 'all']:
|
||||
try:
|
||||
print("facebook is called")
|
||||
facebook_api = FacebookAPI()
|
||||
facebook_poster = FacebookPoster(facebook_api)
|
||||
result = facebook_poster.post_photo(image_url, caption)
|
||||
@@ -606,6 +608,9 @@ class SocialMediaPostView(generic.View):
|
||||
success_messages.append("Posted to Facebook successfully")
|
||||
else:
|
||||
errors.append("Fail to post on Facebook")
|
||||
except Exception as e:
|
||||
print(f"facebook error {e}")
|
||||
errors.append("Fail to post on Facebook")
|
||||
|
||||
if platform in ['instagram', 'all']:
|
||||
instagram_api = InstagramAPI()
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
# Generated by Django 5.0.2 on 2024-12-20 09:29
|
||||
|
||||
import django_quill.fields
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('manage_subscriptions', '0014_alter_subscription_long_description'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='subscription',
|
||||
name='long_description',
|
||||
field=django_quill.fields.QuillField(),
|
||||
),
|
||||
]
|
||||
@@ -75,7 +75,7 @@ stripe==8.2.0
|
||||
tqdm==4.66.2
|
||||
tweepy==4.14.0
|
||||
Twisted==23.10.0
|
||||
twisted-iocpsupport==1.0.4
|
||||
# twisted-iocpsupport==1.0.4
|
||||
txaio==23.1.1
|
||||
typing_extensions==4.9.0
|
||||
tzdata==2024.1
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
{% block stylesheet %}
|
||||
<!-- include required css cdn link through html here -->
|
||||
{% include "cdn_through_html/datatable_cdn_css.html" %}
|
||||
{% include "cdn_through_html/modal_cdn_css.html" %}
|
||||
{% include "cdn_through_html/sweetalert2_cdn_css.html" %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
@@ -46,39 +48,39 @@
|
||||
<th class="checkbox-column text-center sorting_asc" tabindex="0"
|
||||
aria-controls="style-3" rowspan="1" colspan="1" aria-sort="ascending"
|
||||
style="width: 69.2656px;"> Record Id </th>
|
||||
<th class="text-center sorting" tabindex="0" aria-controls="style-3" rowspan="1"
|
||||
style="width: 44.2344px;">Image</th>
|
||||
<th class="text-center sorting" tabindex="0" aria-controls="style-3" rowspan="1" colspan="1"
|
||||
style="width: 79.7969px;">First Name</th>
|
||||
<th class="text-center sorting" tabindex="0" aria-controls="style-3" rowspan="1" colspan="1"
|
||||
style="width: 77.3281px;">Last Name</th>
|
||||
<th class="text-center sorting" tabindex="0" aria-controls="style-3" rowspan="1" colspan="1"
|
||||
style="width: 143.516px;">Email</th>
|
||||
<!-- <th class="text-center sorting" tabindex="0" aria-controls="style-3" rowspan="1" colspan="1"
|
||||
style="width: 98.875px;">Mobile No.</th> -->
|
||||
<th class="text-center sorting" tabindex="0" aria-controls="style-3" rowspan="1" colspan="1"
|
||||
style="width: 98.875px;">Principal Type</th>
|
||||
<th class="text-center sorting" tabindex="0" aria-controls="style-3"
|
||||
rowspan="1" style="width: 44.2344px;">Image</th>
|
||||
<th class="text-center sorting" tabindex="0" aria-controls="style-3"
|
||||
rowspan="1" colspan="1" style="width: 79.7969px;">First Name</th>
|
||||
<th class="text-center sorting" tabindex="0" aria-controls="style-3"
|
||||
rowspan="1" colspan="1" style="width: 77.3281px;">Last Name</th>
|
||||
<th class="text-center sorting" tabindex="0" aria-controls="style-3"
|
||||
rowspan="1" colspan="1" style="width: 143.516px;">Email</th>
|
||||
<th class="text-center sorting" tabindex="0" aria-controls="style-3"
|
||||
rowspan="1" colspan="1" style="width: 98.875px;">#</th>
|
||||
<th class="text-center sorting" tabindex="0" aria-controls="style-3"
|
||||
rowspan="1" colspan="1" style="width: 98.875px;">Principal Type</th>
|
||||
<!-- <th class="text-center sorting" tabindex="0" aria-controls="style-3" rowspan="1" colspan="1"
|
||||
style="width: 98.875px;">Phone Verified</th> -->
|
||||
<th class="text-center sorting" tabindex="0" aria-controls="style-3" rowspan="1" colspan="1"
|
||||
style="width: 98.875px;">Email Verified</th>
|
||||
<th class="text-center sorting" tabindex="0" aria-controls="style-3" rowspan="1" colspan="1"
|
||||
style="width: 98.875px;">Referral Count</th>
|
||||
<th class="text-center sorting" tabindex="0" aria-controls="style-3" rowspan="1" colspan="1"
|
||||
style="width: 98.875px;">Onboarded by Admin</th>
|
||||
<th class="text-center sorting" tabindex="0" aria-controls="style-3" rowspan="1" colspan="1"
|
||||
style="width: 98.875px;">Transferred to Customer</th>
|
||||
<th class="text-center sorting" tabindex="0" aria-controls="style-3" rowspan="1" colspan="1"
|
||||
style="width: 98.875px;">Created On</th>
|
||||
<th class="text-center sorting" tabindex="0" aria-controls="style-3" rowspan="1" colspan="1"
|
||||
style="width: 98.875px;">Modified On</th>
|
||||
<th class="text-center sorting" tabindex="0" aria-controls="style-3" rowspan="1" colspan="1"
|
||||
style="width: 98.875px;">Active</th>
|
||||
<th class="text-center sorting" tabindex="0" aria-controls="style-3"
|
||||
rowspan="1" colspan="1" style="width: 98.875px;">Email Verified</th>
|
||||
<th class="text-center sorting" tabindex="0" aria-controls="style-3"
|
||||
rowspan="1" colspan="1" style="width: 98.875px;">Referral Count</th>
|
||||
<th class="text-center sorting" tabindex="0" aria-controls="style-3"
|
||||
rowspan="1" colspan="1" style="width: 98.875px;">Onboarded by Admin</th>
|
||||
<th class="text-center sorting" tabindex="0" aria-controls="style-3"
|
||||
rowspan="1" colspan="1" style="width: 98.875px;">Transferred to Customer
|
||||
</th>
|
||||
<th class="text-center sorting" tabindex="0" aria-controls="style-3"
|
||||
rowspan="1" colspan="1" style="width: 98.875px;">Created On</th>
|
||||
<th class="text-center sorting" tabindex="0" aria-controls="style-3"
|
||||
rowspan="1" colspan="1" style="width: 98.875px;">Modified On</th>
|
||||
<th class="text-center sorting" tabindex="0" aria-controls="style-3"
|
||||
rowspan="1" colspan="1" style="width: 98.875px;">Active</th>
|
||||
<!-- <th class="text-center sorting" tabindex="0" aria-controls="style-3" rowspan="1" colspan="1"
|
||||
style="width: 98.875px;">Delete</th> -->
|
||||
<th class="text-center dt-no-sorting" tabindex="0"
|
||||
aria-controls="style-3" rowspan="1" colspan="1"
|
||||
style="width: 51.625px;">Action</th>
|
||||
<th class="text-center dt-no-sorting" tabindex="0" aria-controls="style-3"
|
||||
rowspan="1" colspan="1" style="width: 51.625px;">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -92,13 +94,21 @@
|
||||
<td>{{ data_obj.first_name }}</td>
|
||||
<td>{{ data_obj.last_name }}</td>
|
||||
<td>{{ data_obj.email }}</td>
|
||||
<!-- <td>{{ data_obj.phone_no }}</td> -->
|
||||
<td>
|
||||
{% if data_obj.extended_data %}
|
||||
<button class="btn btn-primary btn-sm view-password-btn"
|
||||
data-id="{{ data_obj.id }}" data-email="{{ data_obj.email }}">
|
||||
View
|
||||
</button>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>{{ data_obj.principal_type.name }}</td>
|
||||
<!-- <td>{{ data_obj.phone_verified }}</td> -->
|
||||
<td>{{ data_obj.email_verified }}</td>
|
||||
<td>{{ data_obj.referral_count }}</td>
|
||||
<td class="text-center">
|
||||
<span class="shadow-none badge {% if data_obj.extended_data and data_obj.extended_data.is_onboarded %}badge-primary{% else %}badge-danger{% endif %}">
|
||||
<span
|
||||
class="shadow-none badge {% if data_obj.extended_data and data_obj.extended_data.is_onboarded %}badge-primary{% else %}badge-danger{% endif %}">
|
||||
{% if data_obj.extended_data %}
|
||||
{{ data_obj.extended_data.is_onboarded }}
|
||||
{% else %}
|
||||
@@ -107,7 +117,8 @@
|
||||
</span>
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<span class="shadow-none badge {% if data_obj.extended_data and data_obj.extended_data.is_transferred %}badge-primary{% else %}badge-danger{% endif %}">
|
||||
<span
|
||||
class="shadow-none badge {% if data_obj.extended_data and data_obj.extended_data.is_transferred %}badge-primary{% else %}badge-danger{% endif %}">
|
||||
{% if data_obj.extended_data %}
|
||||
{{ data_obj.extended_data.is_transferred }}
|
||||
{% else %}
|
||||
@@ -118,7 +129,8 @@
|
||||
<td>{{ data_obj.created_on }}</td>
|
||||
<td>{{ data_obj.modified_on }}</td>
|
||||
<td class="text-center">
|
||||
<span class="shadow-none badge {% if data_obj.is_active %}badge-primary{% else %}badge-danger{% endif %}">
|
||||
<span
|
||||
class="shadow-none badge {% if data_obj.is_active %}badge-primary{% else %}badge-danger{% endif %}">
|
||||
{{ data_obj.is_active }}
|
||||
</span>
|
||||
</td>
|
||||
@@ -129,11 +141,12 @@
|
||||
</td> -->
|
||||
<td class="text-center">
|
||||
<ul class="table-controls">
|
||||
<li><a href="{% url 'accounts:customer_edit' data_obj.id%}" class="bs-tooltip"
|
||||
data-bs-toggle="tooltip" data-bs-placement="top" title=""
|
||||
data-original-title="Edit" data-bs-original-title="Edit"
|
||||
aria-label="Edit"><svg xmlns="http://www.w3.org/2000/svg"
|
||||
width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||
<li><a href="{% url 'accounts:customer_edit' data_obj.id%}"
|
||||
class="bs-tooltip" data-bs-toggle="tooltip"
|
||||
data-bs-placement="top" title="" data-original-title="Edit"
|
||||
data-bs-original-title="Edit" aria-label="Edit"><svg
|
||||
xmlns="http://www.w3.org/2000/svg" width="24"
|
||||
height="24" viewBox="0 0 24 24" fill="none"
|
||||
stroke="currentColor" stroke-width="2"
|
||||
stroke-linecap="round" stroke-linejoin="round"
|
||||
class="feather feather-edit-2 p-1 br-8 mb-1">
|
||||
@@ -141,8 +154,19 @@
|
||||
d="M17 3a2.828 2.828 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5L17 3z">
|
||||
</path>
|
||||
</svg></a></li>
|
||||
<li><a href="{% url 'accounts:customer_detail' data_obj.id%}" class="bs-tooltip" data-bs-toggle="tooltip" data-bs-placement="top" title="" data-original-title="View" data-bs-original-title="View" aria-label="View">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-eye"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"></path><circle cx="12" cy="12" r="3"></circle></svg>
|
||||
<li><a href="{% url 'accounts:customer_detail' data_obj.id%}"
|
||||
class="bs-tooltip" data-bs-toggle="tooltip"
|
||||
data-bs-placement="top" title="" data-original-title="View"
|
||||
data-bs-original-title="View" aria-label="View">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24"
|
||||
height="24" viewBox="0 0 24 24" fill="none"
|
||||
stroke="currentColor" stroke-width="2"
|
||||
stroke-linecap="round" stroke-linejoin="round"
|
||||
class="feather feather-eye">
|
||||
<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z">
|
||||
</path>
|
||||
<circle cx="12" cy="12" r="3"></circle>
|
||||
</svg>
|
||||
</a></li>
|
||||
</ul>
|
||||
</td>
|
||||
@@ -159,11 +183,28 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="modal fade" id="passwordModal" tabindex="-1" role="dialog" aria-labelledby="passwordModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="passwordModalLabel">Customer Details</h5>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p><strong>Email:</strong> <span id="modalEmail"></span></p>
|
||||
<p><strong>Password:</strong> <span id="modalPassword"></span></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{% endblock content %}
|
||||
|
||||
{% block javascript %}
|
||||
<!-- include required js cdn link through html here -->
|
||||
{% include "cdn_through_html/datatable_cdn_js.html" %}
|
||||
{% include "cdn_through_html/sweetalert2_cdn_js.html" %}
|
||||
|
||||
<script>
|
||||
c3 = $('#style-3').DataTable({
|
||||
@@ -185,5 +226,45 @@
|
||||
|
||||
multiCheck(c3);
|
||||
|
||||
var viewUrl = "{% url 'accounts:get_decrypted_password' customer_id=0 %}"
|
||||
$(".view-password-btn").on("click", function () {
|
||||
const customerId = $(this).data("id");
|
||||
const email = $(this).data("email");
|
||||
|
||||
// Make the AJAX call
|
||||
$.ajax({
|
||||
// url: `accounts//get-decrypted-password/${customerId}/`,
|
||||
url: viewUrl.replace('0',customerId),
|
||||
type: "GET",
|
||||
dataType: "json",
|
||||
success: function (response) {
|
||||
if (response.success) {
|
||||
// Populate modal with email and decrypted password
|
||||
$("#modalEmail").text(email);
|
||||
$("#modalPassword").text(response.decrypted_password);
|
||||
|
||||
// Show the modal
|
||||
$("#passwordModal").modal("show");
|
||||
} else {
|
||||
Swal.fire({
|
||||
title: 'Error!',
|
||||
text: response.message || "Failed to fetch the password. Please try again.",
|
||||
icon: 'error',
|
||||
showConfirmButton: true
|
||||
});
|
||||
}
|
||||
},
|
||||
error: function (xhr, status, error) {
|
||||
console.error("AJAX Error:", error);
|
||||
Swal.fire({
|
||||
title: 'Error!',
|
||||
text: "An error occurred. Please try again.",
|
||||
icon: 'error',
|
||||
showConfirmButton: true
|
||||
});
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -45,6 +45,8 @@
|
||||
aria-sort="ascending" style="width: 69.2656px;"> Title </th>
|
||||
<th class="checkbox-column sorting_asc" tabindex="0" aria-controls="style-3"
|
||||
aria-sort="ascending" style="width: 69.2656px;"> Address </th>
|
||||
<th class="checkbox-column sorting_asc" tabindex="0" aria-controls="style-3"
|
||||
aria-sort="ascending" style="width: 69.2656px;"> Postcode </th>
|
||||
<th class="checkbox-column sorting_asc" tabindex="0" aria-controls="style-3"
|
||||
aria-sort="ascending" style="width: 69.2656px;"> Latitude </th>
|
||||
<th class="checkbox-column sorting_asc" tabindex="0" aria-controls="style-3"
|
||||
@@ -68,6 +70,7 @@
|
||||
</td>
|
||||
<td>{{data_obj.title}}</td>
|
||||
<td>{{data_obj.address}}</td>
|
||||
<td>{{data_obj.postcode}}</td>
|
||||
<td>{{data_obj.latitude}}</td>
|
||||
<td>{{data_obj.longitude}}</td>
|
||||
<td class="text-center">
|
||||
|
||||
Reference in New Issue
Block a user