devnamdev2003 commited on
Commit
3784aa0
·
1 Parent(s): 0da497e

Add Contact model, serializer, and admin interface; implement contact form handling

Browse files
api/admin.py CHANGED
@@ -1,6 +1,12 @@
1
  from django.contrib import admin
2
  from .models import UserData, AIKey, AppVersion
 
3
 
 
 
 
 
 
4
 
5
  @admin.register(AIKey)
6
  class AIKeyAdmin(admin.ModelAdmin):
 
1
  from django.contrib import admin
2
  from .models import UserData, AIKey, AppVersion
3
+ from .models import Contact
4
 
5
+ @admin.register(Contact)
6
+ class ContactAdmin(admin.ModelAdmin):
7
+ list_display = ('id', 'name', 'email', 'message')
8
+ list_filter = ('id', 'name', 'email')
9
+ search_fields = ('id', 'name', 'email', 'message')
10
 
11
  @admin.register(AIKey)
12
  class AIKeyAdmin(admin.ModelAdmin):
api/migrations/0006_contact.py ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Generated by Django 5.2.4 on 2026-01-26 15:54
2
+
3
+ from django.db import migrations, models
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ dependencies = [
9
+ ('api', '0005_appversion'),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.CreateModel(
14
+ name='Contact',
15
+ fields=[
16
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
17
+ ('name', models.CharField(max_length=20)),
18
+ ('email', models.EmailField(max_length=50)),
19
+ ('message', models.TextField(max_length=500)),
20
+ ],
21
+ ),
22
+ ]
api/models.py CHANGED
@@ -1,6 +1,7 @@
1
  from django.db import models
2
  from django.contrib.postgres.fields import JSONField # If using PostgreSQL
3
 
 
4
  class UserData(models.Model):
5
  user_id = models.CharField(max_length=100, unique=True)
6
  expenses = models.JSONField(default=dict, blank=True)
@@ -10,7 +11,6 @@ class UserData(models.Model):
10
  has_music_url_access = models.BooleanField(default=False)
11
  has_ai_access = models.BooleanField(default=False)
12
 
13
-
14
  def __str__(self):
15
  return f"Data for User {self.user_id}"
16
 
@@ -37,3 +37,8 @@ class AppVersion(models.Model):
37
  def __str__(self):
38
  return self.version
39
 
 
 
 
 
 
 
1
  from django.db import models
2
  from django.contrib.postgres.fields import JSONField # If using PostgreSQL
3
 
4
+
5
  class UserData(models.Model):
6
  user_id = models.CharField(max_length=100, unique=True)
7
  expenses = models.JSONField(default=dict, blank=True)
 
11
  has_music_url_access = models.BooleanField(default=False)
12
  has_ai_access = models.BooleanField(default=False)
13
 
 
14
  def __str__(self):
15
  return f"Data for User {self.user_id}"
16
 
 
37
  def __str__(self):
38
  return self.version
39
 
40
+
41
+ class Contact(models.Model):
42
+ name = models.CharField(max_length=20)
43
+ email = models.EmailField(max_length=50)
44
+ message = models.TextField(max_length=500)
api/serializers.py CHANGED
@@ -1,7 +1,17 @@
1
  from rest_framework import serializers
2
  from .models import UserData
3
 
 
4
  class UserDataSerializer(serializers.ModelSerializer):
5
  class Meta:
6
  model = UserData
7
- fields = '__all__'
 
 
 
 
 
 
 
 
 
 
1
  from rest_framework import serializers
2
  from .models import UserData
3
 
4
+
5
  class UserDataSerializer(serializers.ModelSerializer):
6
  class Meta:
7
  model = UserData
8
+ fields = "__all__"
9
+
10
+
11
+ from .models import Contact
12
+
13
+
14
+ class ContactSerializer(serializers.ModelSerializer):
15
+ class Meta:
16
+ model = Contact
17
+ fields = ["id", "name", "email", "message"]
api/urls.py CHANGED
@@ -1,7 +1,8 @@
1
  from django.urls import path
2
- from .views import UserDataPostView, GetFieldView
3
 
4
  urlpatterns = [
5
  path("post/", UserDataPostView.as_view(), name="post_user_data"),
6
  path("<str:field>/<str:user_id>/", GetFieldView.as_view(), name="get_field_data"),
7
- ]
 
 
1
  from django.urls import path
2
+ from .views import UserDataPostView, GetFieldView, ContactList1
3
 
4
  urlpatterns = [
5
  path("post/", UserDataPostView.as_view(), name="post_user_data"),
6
  path("<str:field>/<str:user_id>/", GetFieldView.as_view(), name="get_field_data"),
7
+ path('contact/', ContactList1.as_view()),
8
+ ]
api/views.py CHANGED
@@ -90,3 +90,913 @@ class GetFieldView(APIView):
90
  if hasattr(obj, field):
91
  return Response({field: getattr(obj, field)})
92
  return Response({"error": "Invalid field"}, status=status.HTTP_400_BAD_REQUEST)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
  if hasattr(obj, field):
91
  return Response({field: getattr(obj, field)})
92
  return Response({"error": "Invalid field"}, status=status.HTTP_400_BAD_REQUEST)
93
+
94
+
95
+
96
+ from .models import Contact
97
+ from .serializers import ContactSerializer
98
+ from rest_framework.generics import ListCreateAPIView, RetrieveUpdateDestroyAPIView, CreateAPIView
99
+ import os
100
+ import os
101
+ import smtplib
102
+ from email.mime.text import MIMEText
103
+ from email.mime.multipart import MIMEMultipart
104
+
105
+ EMAIL_HOST = "smtp.gmail.com"
106
+ EMAIL_PORT = 587
107
+ EMAIL_USER = os.getenv('EMAIL_HOST_USER')
108
+ EMAIL_PASSWORD = os.getenv('EMAIL_HOST_PASSWORD')
109
+
110
+ upper_body="""
111
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional //EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
112
+ <html
113
+ xmlns="http://www.w3.org/1999/xhtml"
114
+ xmlns:v="urn:schemas-microsoft-com:vml"
115
+ xmlns:o="urn:schemas-microsoft-com:office:office"
116
+ >
117
+ <head>
118
+ <!--[if gte mso 9]>
119
+ <xml>
120
+ <o:OfficeDocumentSettings>
121
+ <o:AllowPNG />
122
+ <o:PixelsPerInch>96</o:PixelsPerInch>
123
+ </o:OfficeDocumentSettings>
124
+ </xml>
125
+ <![endif]-->
126
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
127
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
128
+ <meta name="x-apple-disable-message-reformatting" />
129
+ <!--[if !mso]><!-->
130
+ <meta http-equiv="X-UA-Compatible" content="IE=edge" />
131
+ <!--<![endif]-->
132
+ <title></title>
133
+
134
+ <style type="text/css">
135
+ @media only screen and (min-width: 620px) {
136
+ .u-row {
137
+ width: 600px !important;
138
+ }
139
+ .u-row .u-col {
140
+ vertical-align: top;
141
+ }
142
+ .u-row .u-col-100 {
143
+ width: 600px !important;
144
+ }
145
+ }
146
+
147
+ @media (max-width: 620px) {
148
+ .u-row-container {
149
+ max-width: 100% !important;
150
+ padding-left: 0px !important;
151
+ padding-right: 0px !important;
152
+ }
153
+ .u-row .u-col {
154
+ min-width: 320px !important;
155
+ max-width: 100% !important;
156
+ display: block !important;
157
+ }
158
+ .u-row {
159
+ width: 100% !important;
160
+ }
161
+ .u-col {
162
+ width: 100% !important;
163
+ }
164
+ .u-col > div {
165
+ margin: 0 auto;
166
+ }
167
+ }
168
+
169
+ body {
170
+ margin: 0;
171
+ padding: 0;
172
+ }
173
+
174
+ table,
175
+ tr,
176
+ td {
177
+ vertical-align: top;
178
+ border-collapse: collapse;
179
+ }
180
+
181
+ p {
182
+ margin: 0;
183
+ }
184
+
185
+ .ie-container table,
186
+ .mso-container table {
187
+ table-layout: fixed;
188
+ }
189
+
190
+ * {
191
+ line-height: inherit;
192
+ }
193
+
194
+ a[x-apple-data-detectors="true"] {
195
+ color: inherit !important;
196
+ text-decoration: none !important;
197
+ }
198
+
199
+ table,
200
+ td {
201
+ color: #000000;
202
+ }
203
+
204
+ #u_body a {
205
+ color: #0000ee;
206
+ text-decoration: underline;
207
+ }
208
+ </style>
209
+
210
+ <!--[if !mso]><!-->
211
+ <link
212
+ href="https://fonts.googleapis.com/css?family=Cabin:400,700"
213
+ rel="stylesheet"
214
+ type="text/css"
215
+ />
216
+ <!--<![endif]-->
217
+ </head>
218
+
219
+ <body
220
+ class="clean-body u_body"
221
+ style="
222
+ margin: 0;
223
+ padding: 0;
224
+ -webkit-text-size-adjust: 100%;
225
+ background-color: #f9f9f9;
226
+ color: #000000;
227
+ "
228
+ >
229
+ <!--[if IE]><div class="ie-container"><![endif]-->
230
+ <!--[if mso]><div class="mso-container"><![endif]-->
231
+ <table
232
+ id="u_body"
233
+ style="
234
+ border-collapse: collapse;
235
+ table-layout: fixed;
236
+ border-spacing: 0;
237
+ mso-table-lspace: 0pt;
238
+ mso-table-rspace: 0pt;
239
+ vertical-align: top;
240
+ min-width: 320px;
241
+ margin: 0 auto;
242
+ background-color: #f9f9f9;
243
+ width: 100%;
244
+ "
245
+ cellpadding="0"
246
+ cellspacing="0"
247
+ >
248
+ <tbody>
249
+ <tr style="vertical-align: top">
250
+ <td
251
+ style="
252
+ word-break: break-word;
253
+ border-collapse: collapse !important;
254
+ vertical-align: top;
255
+ "
256
+ >
257
+ <!--[if (mso)|(IE)]><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td align="center" style="background-color: #f9f9f9;"><![endif]-->
258
+
259
+ <div
260
+ class="u-row-container"
261
+ style="padding: 0px; background-color: transparent"
262
+ >
263
+ <div
264
+ class="u-row"
265
+ style="
266
+ margin: 0 auto;
267
+ min-width: 320px;
268
+ max-width: 600px;
269
+ overflow-wrap: break-word;
270
+ word-wrap: break-word;
271
+ word-break: break-word;
272
+ background-color: #ffffff;
273
+ "
274
+ >
275
+ <div
276
+ style="
277
+ border-collapse: collapse;
278
+ display: table;
279
+ width: 100%;
280
+ height: 100%;
281
+ background-color: transparent;
282
+ "
283
+ >
284
+ <!--[if (mso)|(IE)]><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td style="padding: 0px;background-color: transparent;" align="center"><table cellpadding="0" cellspacing="0" border="0" style="width:600px;"><tr style="background-color: #ffffff;"><![endif]-->
285
+
286
+ <!--[if (mso)|(IE)]><td align="center" width="600" style="width: 600px;padding: 0px;border-top: 0px solid transparent;border-left: 0px solid transparent;border-right: 0px solid transparent;border-bottom: 0px solid transparent;" valign="top"><![endif]-->
287
+ <div
288
+ class="u-col u-col-100"
289
+ style="
290
+ max-width: 320px;
291
+ min-width: 600px;
292
+ display: table-cell;
293
+ vertical-align: top;
294
+ "
295
+ >
296
+ <div style="height: 100%; width: 100% !important">
297
+ <!--[if (!mso)&(!IE)]><!-->
298
+ <div
299
+ style="
300
+ box-sizing: border-box;
301
+ height: 100%;
302
+ padding: 0px;
303
+ border-top: 0px solid transparent;
304
+ border-left: 0px solid transparent;
305
+ border-right: 0px solid transparent;
306
+ border-bottom: 0px solid transparent;
307
+ "
308
+ >
309
+ <!--<![endif]-->
310
+
311
+ <table
312
+ style="font-family: 'Cabin', sans-serif"
313
+ role="presentation"
314
+ cellpadding="0"
315
+ cellspacing="0"
316
+ width="100%"
317
+ border="0"
318
+ >
319
+ <tbody>
320
+ <tr>
321
+ <td
322
+ style="
323
+ overflow-wrap: break-word;
324
+ word-break: break-word;
325
+ padding: 33px 55px;
326
+ font-family: 'Cabin', sans-serif;
327
+ "
328
+ align="left"
329
+ >
330
+ <div
331
+ style="
332
+ font-size: 14px;
333
+ line-height: 160%;
334
+ text-align: left;
335
+ word-wrap: break-word;
336
+ "
337
+ >
338
+ <p style="line-height: 160%">
339
+ Dear
340
+ """
341
+ lower_body = """,
342
+ </p>
343
+ <p style="line-height: 160%">&nbsp;</p>
344
+ <p style="line-height: 160%">
345
+ Thank you for reaching out to me via the
346
+ contact form on my portfolio website. I
347
+ appreciate your interest and the time you
348
+ took to get in touch.
349
+ </p>
350
+ <p style="line-height: 160%">&nbsp;</p>
351
+ <p style="line-height: 160%">
352
+ I have received your message, and I will
353
+ review it as soon as possible. If your
354
+ inquiry requires a response, I will do my
355
+ best to get back to you promptly.
356
+ </p>
357
+ <p style="line-height: 160%">&nbsp;</p>
358
+ <p style="line-height: 160%">
359
+ In the meantime, if you have any urgent
360
+ questions or need immediate assistance,
361
+ please don't hesitate to contact me
362
+ directly.
363
+ </p>
364
+ <p style="line-height: 160%">&nbsp;</p>
365
+ <p style="line-height: 160%">
366
+ Thank you once again for considering me. I
367
+ look forward to connecting with you and
368
+ addressing your inquiry.
369
+ </p>
370
+ <p style="line-height: 160%">&nbsp;</p>
371
+ <p style="line-height: 160%">
372
+ Best regards,<br />Dev Namdev<br /><a
373
+ href="https://devnamdev2003.github.io/"
374
+ >https://devnamdev2003.github.io/</a
375
+ ><br />devnamdevcse@gmail.com
376
+ </p>
377
+ </div>
378
+ </td>
379
+ </tr>
380
+ </tbody>
381
+ </table>
382
+
383
+ <table
384
+ style="font-family: 'Cabin', sans-serif"
385
+ role="presentation"
386
+ cellpadding="0"
387
+ cellspacing="0"
388
+ width="100%"
389
+ border="0"
390
+ >
391
+ <tbody>
392
+ <tr>
393
+ <td
394
+ style="
395
+ overflow-wrap: break-word;
396
+ word-break: break-word;
397
+ padding: 47px;
398
+ font-family: 'Cabin', sans-serif;
399
+ "
400
+ align="left"
401
+ >
402
+ <div
403
+ style="
404
+ font-size: 14px;
405
+ line-height: 160%;
406
+ text-align: center;
407
+ word-wrap: break-word;
408
+ "
409
+ >
410
+ <p style="line-height: 160%; font-size: 14px">
411
+ <span
412
+ style="
413
+ font-size: 18px;
414
+ line-height: 28.8px;
415
+ "
416
+ >Thanks</span
417
+ >
418
+ </p>
419
+ </div>
420
+ </td>
421
+ </tr>
422
+ </tbody>
423
+ </table>
424
+
425
+ <!--[if (!mso)&(!IE)]><!-->
426
+ </div>
427
+ <!--<![endif]-->
428
+ </div>
429
+ </div>
430
+ <!--[if (mso)|(IE)]></td><![endif]-->
431
+ <!--[if (mso)|(IE)]></tr></table></td></tr></table><![endif]-->
432
+ </div>
433
+ </div>
434
+ </div>
435
+
436
+ <div
437
+ class="u-row-container"
438
+ style="padding: 0px; background-color: transparent"
439
+ >
440
+ <div
441
+ class="u-row"
442
+ style="
443
+ margin: 0 auto;
444
+ min-width: 320px;
445
+ max-width: 600px;
446
+ overflow-wrap: break-word;
447
+ word-wrap: break-word;
448
+ word-break: break-word;
449
+ background-color: #e5eaf5;
450
+ "
451
+ >
452
+ <div
453
+ style="
454
+ border-collapse: collapse;
455
+ display: table;
456
+ width: 100%;
457
+ height: 100%;
458
+ background-color: transparent;
459
+ "
460
+ >
461
+ <!--[if (mso)|(IE)]><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td style="padding: 0px;background-color: transparent;" align="center"><table cellpadding="0" cellspacing="0" border="0" style="width:600px;"><tr style="background-color: #e5eaf5;"><![endif]-->
462
+
463
+ <!--[if (mso)|(IE)]><td align="center" width="600" style="width: 600px;padding: 0px;border-top: 0px solid transparent;border-left: 0px solid transparent;border-right: 0px solid transparent;border-bottom: 0px solid transparent;" valign="top"><![endif]-->
464
+ <div
465
+ class="u-col u-col-100"
466
+ style="
467
+ max-width: 320px;
468
+ min-width: 600px;
469
+ display: table-cell;
470
+ vertical-align: top;
471
+ "
472
+ >
473
+ <div style="height: 100%; width: 100% !important">
474
+ <!--[if (!mso)&(!IE)]><!-->
475
+ <div
476
+ style="
477
+ box-sizing: border-box;
478
+ height: 100%;
479
+ padding: 0px;
480
+ border-top: 0px solid transparent;
481
+ border-left: 0px solid transparent;
482
+ border-right: 0px solid transparent;
483
+ border-bottom: 0px solid transparent;
484
+ "
485
+ >
486
+ <!--<![endif]-->
487
+
488
+ <table
489
+ style="font-family: 'Cabin', sans-serif"
490
+ role="presentation"
491
+ cellpadding="0"
492
+ cellspacing="0"
493
+ width="100%"
494
+ border="0"
495
+ >
496
+ <tbody>
497
+ <tr>
498
+ <td
499
+ style="
500
+ overflow-wrap: break-word;
501
+ word-break: break-word;
502
+ padding: 41px 55px 18px;
503
+ font-family: 'Cabin', sans-serif;
504
+ "
505
+ align="left"
506
+ >
507
+ <div
508
+ style="
509
+ font-size: 14px;
510
+ color: #003399;
511
+ line-height: 160%;
512
+ text-align: center;
513
+ word-wrap: break-word;
514
+ "
515
+ >
516
+ <p style="font-size: 14px; line-height: 160%">
517
+ <span
518
+ style="font-size: 20px; line-height: 32px"
519
+ ><strong>Get in touch</strong></span
520
+ >
521
+ </p>
522
+ <p style="font-size: 14px; line-height: 160%">
523
+ <span
524
+ style="
525
+ font-size: 16px;
526
+ line-height: 25.6px;
527
+ color: #000000;
528
+ "
529
+ ></span
530
+ >
531
+ </p>
532
+ <p style="font-size: 14px; line-height: 160%">
533
+ <span
534
+ style="
535
+ font-size: 16px;
536
+ line-height: 25.6px;
537
+ color: #000000;
538
+ "
539
+ >devnamdevcse@gmail.com</span
540
+ >
541
+ </p>
542
+ </div>
543
+ </td>
544
+ </tr>
545
+ </tbody>
546
+ </table>
547
+
548
+ <table
549
+ style="font-family: 'Cabin', sans-serif"
550
+ role="presentation"
551
+ cellpadding="0"
552
+ cellspacing="0"
553
+ width="100%"
554
+ border="0"
555
+ >
556
+ <tbody>
557
+ <tr>
558
+ <td
559
+ style="
560
+ overflow-wrap: break-word;
561
+ word-break: break-word;
562
+ padding: 10px 10px 33px;
563
+ font-family: 'Cabin', sans-serif;
564
+ "
565
+ align="left"
566
+ >
567
+ <div align="center">
568
+ <div style="display: table; max-width: 293px">
569
+ <!--[if (mso)|(IE)]><table width="293" cellpadding="0" cellspacing="0" border="0"><tr><td style="border-collapse:collapse;" align="center"><table width="100%" cellpadding="0" cellspacing="0" border="0" style="border-collapse:collapse; mso-table-lspace: 0pt;mso-table-rspace: 0pt; width:293px;"><tr><![endif]-->
570
+
571
+ <!--[if (mso)|(IE)]><td width="32" style="width:32px; padding-right: 17px;" valign="top"><![endif]-->
572
+ <table
573
+ align="left"
574
+ border="0"
575
+ cellspacing="0"
576
+ cellpadding="0"
577
+ width="32"
578
+ height="32"
579
+ style="
580
+ width: 32px !important;
581
+ height: 32px !important;
582
+ display: inline-block;
583
+ border-collapse: collapse;
584
+ table-layout: fixed;
585
+ border-spacing: 0;
586
+ mso-table-lspace: 0pt;
587
+ mso-table-rspace: 0pt;
588
+ vertical-align: top;
589
+ margin-right: 17px;
590
+ "
591
+ >
592
+ <tbody>
593
+ <tr style="vertical-align: top">
594
+ <td
595
+ align="left"
596
+ valign="middle"
597
+ style="
598
+ word-break: break-word;
599
+ border-collapse: collapse !important;
600
+ vertical-align: top;
601
+ "
602
+ >
603
+ <a
604
+ href="https://twitter.com/devnamdev813"
605
+ title="x"
606
+ target="_blank"
607
+ >
608
+ <img
609
+ src="https://cdn.tools.unlayer.com/social/icons/circle/x.png"
610
+ alt="x"
611
+ title="x"
612
+ width="32"
613
+ style="
614
+ outline: none;
615
+ text-decoration: none;
616
+ -ms-interpolation-mode: bicubic;
617
+ clear: both;
618
+ display: block !important;
619
+ border: none;
620
+ height: auto;
621
+ float: none;
622
+ max-width: 32px !important;
623
+ "
624
+ />
625
+ </a>
626
+ </td>
627
+ </tr>
628
+ </tbody>
629
+ </table>
630
+ <!--[if (mso)|(IE)]></td><![endif]-->
631
+
632
+ <!--[if (mso)|(IE)]><td width="32" style="width:32px; padding-right: 17px;" valign="top"><![endif]-->
633
+ <table
634
+ align="left"
635
+ border="0"
636
+ cellspacing="0"
637
+ cellpadding="0"
638
+ width="32"
639
+ height="32"
640
+ style="
641
+ width: 32px !important;
642
+ height: 32px !important;
643
+ display: inline-block;
644
+ border-collapse: collapse;
645
+ table-layout: fixed;
646
+ border-spacing: 0;
647
+ mso-table-lspace: 0pt;
648
+ mso-table-rspace: 0pt;
649
+ vertical-align: top;
650
+ margin-right: 17px;
651
+ "
652
+ >
653
+ <tbody>
654
+ <tr style="vertical-align: top">
655
+ <td
656
+ align="left"
657
+ valign="middle"
658
+ style="
659
+ word-break: break-word;
660
+ border-collapse: collapse !important;
661
+ vertical-align: top;
662
+ "
663
+ >
664
+ <a
665
+ href="https://www.facebook.com/dev.namdev813/"
666
+ title="Facebook"
667
+ target="_blank"
668
+ >
669
+ <img
670
+ src="https://cdn.tools.unlayer.com/social/icons/circle/facebook.png"
671
+ alt="Facebook"
672
+ title="Facebook"
673
+ width="32"
674
+ style="
675
+ outline: none;
676
+ text-decoration: none;
677
+ -ms-interpolation-mode: bicubic;
678
+ clear: both;
679
+ display: block !important;
680
+ border: none;
681
+ height: auto;
682
+ float: none;
683
+ max-width: 32px !important;
684
+ "
685
+ />
686
+ </a>
687
+ </td>
688
+ </tr>
689
+ </tbody>
690
+ </table>
691
+ <!--[if (mso)|(IE)]></td><![endif]-->
692
+
693
+ <!--[if (mso)|(IE)]><td width="32" style="width:32px; padding-right: 17px;" valign="top"><![endif]-->
694
+ <table
695
+ align="left"
696
+ border="0"
697
+ cellspacing="0"
698
+ cellpadding="0"
699
+ width="32"
700
+ height="32"
701
+ style="
702
+ width: 32px !important;
703
+ height: 32px !important;
704
+ display: inline-block;
705
+ border-collapse: collapse;
706
+ table-layout: fixed;
707
+ border-spacing: 0;
708
+ mso-table-lspace: 0pt;
709
+ mso-table-rspace: 0pt;
710
+ vertical-align: top;
711
+ margin-right: 17px;
712
+ "
713
+ >
714
+ <tbody>
715
+ <tr style="vertical-align: top">
716
+ <td
717
+ align="left"
718
+ valign="middle"
719
+ style="
720
+ word-break: break-word;
721
+ border-collapse: collapse !important;
722
+ vertical-align: top;
723
+ "
724
+ >
725
+ <a
726
+ href="https://www.linkedin.com/in/devnamdev/"
727
+ title="LinkedIn"
728
+ target="_blank"
729
+ >
730
+ <img
731
+ src="https://cdn.tools.unlayer.com/social/icons/circle/linkedin.png"
732
+ alt="LinkedIn"
733
+ title="LinkedIn"
734
+ width="32"
735
+ style="
736
+ outline: none;
737
+ text-decoration: none;
738
+ -ms-interpolation-mode: bicubic;
739
+ clear: both;
740
+ display: block !important;
741
+ border: none;
742
+ height: auto;
743
+ float: none;
744
+ max-width: 32px !important;
745
+ "
746
+ />
747
+ </a>
748
+ </td>
749
+ </tr>
750
+ </tbody>
751
+ </table>
752
+ <!--[if (mso)|(IE)]></td><![endif]-->
753
+
754
+ <!--[if (mso)|(IE)]><td width="32" style="width:32px; padding-right: 17px;" valign="top"><![endif]-->
755
+ <table
756
+ align="left"
757
+ border="0"
758
+ cellspacing="0"
759
+ cellpadding="0"
760
+ width="32"
761
+ height="32"
762
+ style="
763
+ width: 32px !important;
764
+ height: 32px !important;
765
+ display: inline-block;
766
+ border-collapse: collapse;
767
+ table-layout: fixed;
768
+ border-spacing: 0;
769
+ mso-table-lspace: 0pt;
770
+ mso-table-rspace: 0pt;
771
+ vertical-align: top;
772
+ margin-right: 17px;
773
+ "
774
+ >
775
+ <tbody>
776
+ <tr style="vertical-align: top">
777
+ <td
778
+ align="left"
779
+ valign="middle"
780
+ style="
781
+ word-break: break-word;
782
+ border-collapse: collapse !important;
783
+ vertical-align: top;
784
+ "
785
+ >
786
+ <a
787
+ href=" https://www.instagram.com/dev_namdev813/"
788
+ title="Instagram"
789
+ target="_blank"
790
+ >
791
+ <img
792
+ src="https://cdn.tools.unlayer.com/social/icons/circle/instagram.png"
793
+ alt="Instagram"
794
+ title="Instagram"
795
+ width="32"
796
+ style="
797
+ outline: none;
798
+ text-decoration: none;
799
+ -ms-interpolation-mode: bicubic;
800
+ clear: both;
801
+ display: block !important;
802
+ border: none;
803
+ height: auto;
804
+ float: none;
805
+ max-width: 32px !important;
806
+ "
807
+ />
808
+ </a>
809
+ </td>
810
+ </tr>
811
+ </tbody>
812
+ </table>
813
+ <!--[if (mso)|(IE)]></td><![endif]-->
814
+
815
+ <!--[if (mso)|(IE)]><td width="32" style="width:32px; padding-right: 17px;" valign="top"><![endif]-->
816
+ <table
817
+ align="left"
818
+ border="0"
819
+ cellspacing="0"
820
+ cellpadding="0"
821
+ width="32"
822
+ height="32"
823
+ style="
824
+ width: 32px !important;
825
+ height: 32px !important;
826
+ display: inline-block;
827
+ border-collapse: collapse;
828
+ table-layout: fixed;
829
+ border-spacing: 0;
830
+ mso-table-lspace: 0pt;
831
+ mso-table-rspace: 0pt;
832
+ vertical-align: top;
833
+ margin-right: 17px;
834
+ "
835
+ >
836
+ <tbody>
837
+ <tr style="vertical-align: top">
838
+ <td
839
+ align="left"
840
+ valign="middle"
841
+ style="
842
+ word-break: break-word;
843
+ border-collapse: collapse !important;
844
+ vertical-align: top;
845
+ "
846
+ >
847
+ <a
848
+ href="https://www.youtube.com/@decode813"
849
+ title="YouTube"
850
+ target="_blank"
851
+ >
852
+ <img
853
+ src="https://cdn.tools.unlayer.com/social/icons/circle/youtube.png"
854
+ alt="YouTube"
855
+ title="YouTube"
856
+ width="32"
857
+ style="
858
+ outline: none;
859
+ text-decoration: none;
860
+ -ms-interpolation-mode: bicubic;
861
+ clear: both;
862
+ display: block !important;
863
+ border: none;
864
+ height: auto;
865
+ float: none;
866
+ max-width: 32px !important;
867
+ "
868
+ />
869
+ </a>
870
+ </td>
871
+ </tr>
872
+ </tbody>
873
+ </table>
874
+ <!--[if (mso)|(IE)]></td><![endif]-->
875
+
876
+ <!--[if (mso)|(IE)]><td width="32" style="width:32px; padding-right: 0px;" valign="top"><![endif]-->
877
+ <table
878
+ align="left"
879
+ border="0"
880
+ cellspacing="0"
881
+ cellpadding="0"
882
+ width="32"
883
+ height="32"
884
+ style="
885
+ width: 32px !important;
886
+ height: 32px !important;
887
+ display: inline-block;
888
+ border-collapse: collapse;
889
+ table-layout: fixed;
890
+ border-spacing: 0;
891
+ mso-table-lspace: 0pt;
892
+ mso-table-rspace: 0pt;
893
+ vertical-align: top;
894
+ margin-right: 0px;
895
+ "
896
+ >
897
+ <tbody>
898
+ <tr style="vertical-align: top">
899
+ <td
900
+ align="left"
901
+ valign="middle"
902
+ style="
903
+ word-break: break-word;
904
+ border-collapse: collapse !important;
905
+ vertical-align: top;
906
+ "
907
+ >
908
+ <a
909
+ href=" https://github.com/devnamdev2003"
910
+ title="GitHub"
911
+ target="_blank"
912
+ >
913
+ <img
914
+ src="https://cdn.tools.unlayer.com/social/icons/circle/github.png"
915
+ alt="GitHub"
916
+ title="GitHub"
917
+ width="32"
918
+ style="
919
+ outline: none;
920
+ text-decoration: none;
921
+ -ms-interpolation-mode: bicubic;
922
+ clear: both;
923
+ display: block !important;
924
+ border: none;
925
+ height: auto;
926
+ float: none;
927
+ max-width: 32px !important;
928
+ "
929
+ />
930
+ </a>
931
+ </td>
932
+ </tr>
933
+ </tbody>
934
+ </table>
935
+ <!--[if (mso)|(IE)]></td><![endif]-->
936
+
937
+ <!--[if (mso)|(IE)]></tr></table></td></tr></table><![endif]-->
938
+ </div>
939
+ </div>
940
+ </td>
941
+ </tr>
942
+ </tbody>
943
+ </table>
944
+
945
+ <!--[if (!mso)&(!IE)]><!-->
946
+ </div>
947
+ <!--<![endif]-->
948
+ </div>
949
+ </div>
950
+ <!--[if (mso)|(IE)]></td><![endif]-->
951
+ <!--[if (mso)|(IE)]></tr></table></td></tr></table><![endif]-->
952
+ </div>
953
+ </div>
954
+ </div>
955
+
956
+ <!--[if (mso)|(IE)]></td></tr></table><![endif]-->
957
+ </td>
958
+ </tr>
959
+ </tbody>
960
+ </table>
961
+ <!--[if mso]></div><![endif]-->
962
+ <!--[if IE]></div><![endif]-->
963
+ </body>
964
+ </html>
965
+
966
+
967
+ """
968
+
969
+ class ContactList1(CreateAPIView):
970
+ queryset = Contact.objects.all()
971
+ serializer_class = ContactSerializer
972
+ def perform_create(self, serializer):
973
+ instance = serializer.save()
974
+ user_ip = self.get_client_ip(self.request)
975
+ email=instance.email
976
+ name=instance.name
977
+ message=instance.message
978
+ msg = MIMEMultipart()
979
+ msg['From'] = EMAIL_USER
980
+ msg['To'] = email
981
+ msg['Subject'] = "Confirmation: We've Received Your Message"
982
+ body=upper_body+name+lower_body
983
+ msg.attach(MIMEText(body, 'html'))
984
+ server = smtplib.SMTP(EMAIL_HOST, EMAIL_PORT)
985
+ server.starttls()
986
+ server.login(EMAIL_USER, EMAIL_PASSWORD)
987
+ server.sendmail(EMAIL_USER, email, msg.as_string())
988
+ text = f"Subject: Form Submission from {name}\n\nName: {name}\nEmail: {email}\nMessage: {message}\nIP Address: {user_ip}"
989
+ server.sendmail(EMAIL_USER, "devnamdevcse@gmail.com", text)
990
+ server.quit()
991
+ def get_client_ip(self, request):
992
+ x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
993
+ if x_forwarded_for:
994
+ ip = x_forwarded_for.split(',')[0]
995
+ else:
996
+ ip = request.META.get('REMOTE_ADDR')
997
+ return ip
998
+
999
+
1000
+ # class ContactList2(RetrieveUpdateDestroyAPIView):
1001
+ # queryset = Contact.objects.all()
1002
+ # serializer_class = ContactSerializer