exwiseapi / api /views.py
devnamdev2003
up5
7cc204e
raw
history blame
13.5 kB
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from .models import UserData, AIKey, AppVersion, Contact
from django.shortcuts import get_object_or_404
from .serializers import ContactSerializer
from rest_framework.generics import CreateAPIView
import os
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
class UserDataPostView(APIView):
def post(self, request):
user_id = request.data.get("user_id")
if not user_id:
return Response(
{"error": "user_id is required"}, status=status.HTTP_400_BAD_REQUEST
)
obj, created = UserData.objects.get_or_create(user_id=user_id)
# Track if updates were actually made
updated = False
for key in ["expenses", "salary", "category", "user_data"]:
if key in request.data and getattr(obj, key) != request.data[key]:
setattr(obj, key, request.data[key])
updated = True
if updated:
obj.save()
if created:
obj = get_object_or_404(UserData, user_id=user_id)
if obj.has_ai_access:
AI_KEY = get_object_or_404(AIKey, isActive=True).aikey
else:
AI_KEY = None
return Response(
{
"message": "Data created successfull",
"app_version": get_object_or_404(AppVersion, isActive=True).version,
"has_music_url_access": obj.has_music_url_access,
"has_ai_access": obj.has_ai_access,
"ai_key": AI_KEY,
},
status=status.HTTP_201_CREATED,
)
elif updated:
obj = get_object_or_404(UserData, user_id=user_id)
print(obj.has_ai_access)
if obj.has_ai_access:
AI_KEY = get_object_or_404(AIKey, isActive=True).aikey
else:
AI_KEY = None
return Response(
{
"message": "Data updated successfull",
"app_version": get_object_or_404(AppVersion, isActive=True).version,
"has_music_url_access": obj.has_music_url_access,
"has_ai_access": obj.has_ai_access,
"ai_key": AI_KEY,
},
status=status.HTTP_200_OK,
)
else:
obj = get_object_or_404(UserData, user_id=user_id)
if obj.has_ai_access:
AI_KEY = get_object_or_404(AIKey, isActive=True).aikey
else:
AI_KEY = None
return Response(
{
"message": "No changes made",
"app_version": get_object_or_404(AppVersion, isActive=True).version,
"has_music_url_access": obj.has_music_url_access,
"has_ai_access": obj.has_ai_access,
"ai_key": AI_KEY,
},
status=status.HTTP_200_OK,
)
class GetFieldView(APIView):
def get(self, request, field, user_id):
obj = get_object_or_404(UserData, user_id=user_id)
if field == "all":
data = {
"userData": obj.user_data,
"expenseData": obj.expenses,
"categoryData": obj.category,
"salaryData": obj.salary,
}
return Response(data)
if hasattr(obj, field):
return Response({field: getattr(obj, field)})
return Response({"error": "Invalid field"}, status=status.HTTP_400_BAD_REQUEST)
upper_body = """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Contact Form Confirmation Template</title>
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
<style>
:root {
--brand-100: #dbeafe;
--brand-500: #3b82f6;
--brand-600: #2563eb;
--brand-900: #1e3a8a;
--gray-50: #f9fafb;
--gray-100: #f3f4f6;
--gray-200: #e5e7eb;
--gray-400: #9ca3af;
--gray-500: #6b7280;
--gray-600: #4b5563;
--gray-700: #374151;
--gray-900: #111827;
--white: #ffffff;
}
body {
margin: 0;
padding: 20px;
background-color: var(--gray-100);
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
color: var(--gray-700);
display: flex;
flex-direction: column;
align-items: center;
min-height: 100vh;
}
a {
text-decoration: none;
}
strong {
font-weight: 700;
}
.btn-copy {
background-color: var(--gray-900);
color: var(--white);
border: none;
padding: 8px 16px;
border-radius: 6px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
display: flex;
align-items: center;
gap: 8px;
transition: background-color 0.2s;
}
.btn-copy:hover {
background-color: #000000;
}
#email-template {
width: 100%;
max-width: 600px;
background-color: var(--white);
border-radius: 12px;
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
overflow: hidden;
border: 1px solid var(--gray-100);
margin: 0 auto;
}
.email-header {
background-color: var(--brand-600);
padding: 32px;
text-align: left;
}
.email-header h1 {
color: var(--white);
font-size: 24px;
font-weight: 700;
letter-spacing: 0.025em;
margin: 0;
text-transform: uppercase;
}
.email-header p {
color: var(--brand-100);
margin-top: 4px;
margin-bottom: 0;
font-size: 14px;
}
.email-body {
padding: 32px;
}
.greeting {
font-size: 18px;
color: var(--gray-700);
margin-bottom: 24px;
}
.highlight {
color: var(--brand-600);
font-weight: 600;
}
.text-paragraph {
color: var(--gray-600);
line-height: 1.6;
margin-bottom: 24px;
margin-top: 0;
}
.recap-box {
background-color: var(--gray-50);
border-radius: 8px;
padding: 24px;
border-left: 4px solid var(--brand-500);
margin-bottom: 32px;
}
.recap-label {
font-size: 12px;
font-weight: 700;
color: var(--gray-400);
text-transform: uppercase;
letter-spacing: 0.05em;
margin: 0 0 8px 0;
}
.recap-content {
font-style: italic;
color: var(--gray-600);
font-size: 14px;
margin: 0;
}
.btn-container {
margin-top: 32px;
text-align: left;
}
.btn-primary {
display: inline-block;
background-color: var(--brand-600);
color: var(--white);
font-weight: 500;
padding: 12px 24px;
border-radius: 8px;
font-size: 14px;
transition: background-color 0.2s;
}
.btn-primary:hover {
background-color: var(--brand-900);
}
.email-footer {
background-color: var(--gray-50);
padding: 24px 32px;
border-top: 1px solid var(--gray-100);
text-align: center;
}
.social-icons {
margin-bottom: 16px;
}
.social-link {
color: var(--gray-400);
margin: 0 8px;
font-size: 20px;
transition: color 0.2s;
}
.social-link:hover {
color: var(--brand-600);
}
.footer-text {
font-size: 12px;
color: var(--gray-400);
margin: 0;
line-height: 1.5;
}
.footer-link {
color: var(--gray-400);
text-decoration: underline;
}
.footer-link:hover {
color: var(--gray-600);
}
#toast {
position: fixed;
bottom: 20px;
right: 20px;
background-color: var(--gray-900);
color: var(--white);
padding: 12px 24px;
border-radius: 8px;
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
opacity: 0;
transform: translateY(20px);
transition: all 0.3s ease;
}
#toast.show {
opacity: 1;
transform: translateY(0);
}
@media (max-width: 600px) {
.email-header,
.email-body,
.email-footer {
padding: 24px;
}
.email-header,
.btn-container {
text-align: center;
}
.btn-copy {
width: 100%;
justify-content: center;
}
}
</style>
</head>
<body>
<div id="email-template">
<div class="email-header">
<h1>THANK YOU!</h1>
<p>I've received your message.</p>
</div>
<div class="email-body">
<p class="greeting">Hi <span class="highlight">"""
mid_body = """</span>,</p>
<p class="text-paragraph">
Thanks for reaching out via my portfolio! I wanted to let you know that your message has landed safely
in my inbox.
</p>
<p class="text-paragraph">
I appreciate your interest. I typically review inquiries within <strong>24 hours</strong> and will get
back to you as soon as possible.
</p>
<div class="recap-box">
<h3 class="recap-label">You wrote:</h3>
<p class="recap-content">
"""
lower_body = """
</p>
</div>
<p class="text-paragraph" style="margin-bottom: 0;">
Best regards,<br>
<span style="font-weight: 600; color: #111827;">Dev Namdev</span>
</p>
<div class="btn-container">
<a href="https://devnamdev2003.github.io/" class="btn-primary">
Return to Portfolio
</a>
</div>
</div>
<div class="email-footer">
<div class="social-icons">
<a href="https://www.linkedin.com/in/devnamdev/" class="social-link"><i class="fab fa-linkedin"></i></a>
<a href="https://github.com/devnamdev2003" class="social-link"><i class="fab fa-github"></i></a>
</div>
<p class="footer-text">
&copy; 2024 Dev Namdev. All rights reserved.<br>
</p>
</div>
</div>
</body>
</html>
"""
EMAIL_HOST = "smtp.gmail.com"
EMAIL_PORT = 587
EMAIL_USER = os.getenv("EMAIL_HOST_USER")
EMAIL_PASSWORD = os.getenv("EMAIL_HOST_PASSWORD")
class ContactList1(CreateAPIView):
queryset = Contact.objects.all()
serializer_class = ContactSerializer
def perform_create(self, serializer):
instance = serializer.save()
user_ip = self.get_client_ip(self.request)
email = instance.email
name = instance.name
message = instance.message
try:
print("mail sending..")
msg = MIMEMultipart()
msg["From"] = EMAIL_USER
msg["To"] = email
msg["Subject"] = "Confirmation: We've Received Your Message"
body = upper_body + name + mid_body + message + lower_body
msg.attach(MIMEText(body, "html"))
# 🔥 IMPORTANT: timeout added
server = smtplib.SMTP(EMAIL_HOST, EMAIL_PORT, timeout=10)
server.starttls()
server.login(EMAIL_USER, EMAIL_PASSWORD)
server.sendmail(EMAIL_USER, email, msg.as_string())
print("mail send to user")
admin_text = (
f"Subject: Form Submission from {name}\n\n"
f"Name: {name}\n"
f"Email: {email}\n"
f"Message: {message}\n"
f"IP Address: {user_ip}"
)
server.sendmail(EMAIL_USER, "devnamdevcse@gmail.com", admin_text)
print("mail send to devnamdevcse@gmail.com")
except Exception as e:
# ❗ Prevent worker crash
print("Email error:", e)
finally:
try:
server.quit()
except:
pass
def get_client_ip(self, request):
x_forwarded_for = request.META.get("HTTP_X_FORWARDED_FOR")
if x_forwarded_for:
ip = x_forwarded_for.split(",")[0]
else:
ip = request.META.get("REMOTE_ADDR")
return ip