From b6a417f40b4f3273015118d788ee5c25e3fdb690 Mon Sep 17 00:00:00 2001
From: Troy <troynovsak@gmail.com>
Date: Fri, 16 Feb 2024 23:08:21 -0500
Subject: [PATCH] adjusted breaches

---
 backend/breaches/__init__.py                |   0
 backend/breaches/admin.py                   |   6 ++
 backend/breaches/apps.py                    |   6 ++
 backend/breaches/migrations/0001_initial.py |  27 +++++
 backend/breaches/migrations/__init__.py     |   0
 backend/breaches/models.py                  |   8 ++
 backend/breaches/tests.py                   |   3 +
 backend/breaches/urls.py                    |   6 ++
 backend/breaches/views.py                   |  80 ++++++++++++++
 backend/db.sqlite3                          | Bin 131072 -> 147456 bytes
 backend/watchstone_backend/settings.py      |   1 +
 backend/watchstone_backend/urls.py          |  21 +---
 frontend/src/views/modules/Breaches.js      | 109 +++++++++++++++-----
 13 files changed, 224 insertions(+), 43 deletions(-)
 create mode 100644 backend/breaches/__init__.py
 create mode 100644 backend/breaches/admin.py
 create mode 100644 backend/breaches/apps.py
 create mode 100644 backend/breaches/migrations/0001_initial.py
 create mode 100644 backend/breaches/migrations/__init__.py
 create mode 100644 backend/breaches/models.py
 create mode 100644 backend/breaches/tests.py
 create mode 100644 backend/breaches/urls.py
 create mode 100644 backend/breaches/views.py

diff --git a/backend/breaches/__init__.py b/backend/breaches/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/backend/breaches/admin.py b/backend/breaches/admin.py
new file mode 100644
index 000000000..b85e51012
--- /dev/null
+++ b/backend/breaches/admin.py
@@ -0,0 +1,6 @@
+from django.contrib import admin
+from .models import MonitoredEmail
+
+@admin.register(MonitoredEmail)
+class MonitoredEmailAdmin(admin.ModelAdmin):
+    list_display = ('email', 'added_on')
diff --git a/backend/breaches/apps.py b/backend/breaches/apps.py
new file mode 100644
index 000000000..d6eb14128
--- /dev/null
+++ b/backend/breaches/apps.py
@@ -0,0 +1,6 @@
+from django.apps import AppConfig
+
+
+class BreachesConfig(AppConfig):
+    default_auto_field = "django.db.models.BigAutoField"
+    name = "breaches"
diff --git a/backend/breaches/migrations/0001_initial.py b/backend/breaches/migrations/0001_initial.py
new file mode 100644
index 000000000..dd19cac13
--- /dev/null
+++ b/backend/breaches/migrations/0001_initial.py
@@ -0,0 +1,27 @@
+# Generated by Django 4.2.9 on 2024-02-16 23:50
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+    initial = True
+
+    dependencies = []
+
+    operations = [
+        migrations.CreateModel(
+            name="Account",
+            fields=[
+                (
+                    "id",
+                    models.BigAutoField(
+                        auto_created=True,
+                        primary_key=True,
+                        serialize=False,
+                        verbose_name="ID",
+                    ),
+                ),
+                ("email", models.EmailField(max_length=254, unique=True)),
+            ],
+        ),
+    ]
diff --git a/backend/breaches/migrations/__init__.py b/backend/breaches/migrations/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/backend/breaches/models.py b/backend/breaches/models.py
new file mode 100644
index 000000000..e9c6d574b
--- /dev/null
+++ b/backend/breaches/models.py
@@ -0,0 +1,8 @@
+from django.db import models
+
+class MonitoredEmail(models.Model):
+    email = models.EmailField(unique=True)
+    added_on = models.DateTimeField(auto_now_add=True)
+
+    def __str__(self):
+        return self.email
diff --git a/backend/breaches/tests.py b/backend/breaches/tests.py
new file mode 100644
index 000000000..7ce503c2d
--- /dev/null
+++ b/backend/breaches/tests.py
@@ -0,0 +1,3 @@
+from django.test import TestCase
+
+# Create your tests here.
diff --git a/backend/breaches/urls.py b/backend/breaches/urls.py
new file mode 100644
index 000000000..462f72fdf
--- /dev/null
+++ b/backend/breaches/urls.py
@@ -0,0 +1,6 @@
+from django.urls import path
+from . import views
+
+urlpatterns = [
+    path('upload/', views.upload_breaches, name='upload_breaches'),
+]
diff --git a/backend/breaches/views.py b/backend/breaches/views.py
new file mode 100644
index 000000000..14bdf4324
--- /dev/null
+++ b/backend/breaches/views.py
@@ -0,0 +1,80 @@
+from django.http import JsonResponse
+from .models import MonitoredEmail
+from django.views.decorators.http import require_http_methods
+import csv
+from io import StringIO
+from rest_framework.decorators import api_view, permission_classes
+from rest_framework.permissions import IsAuthenticated
+from django.http import JsonResponse
+from django.views.decorators.http import require_http_methods
+from django.views.decorators.csrf import csrf_exempt
+from rest_framework.decorators import api_view, permission_classes
+from rest_framework.permissions import IsAuthenticated
+import csv
+from io import StringIO
+from .models import MonitoredEmail
+from rest_framework.parsers import JSONParser
+
+@require_http_methods(["POST"])
+@permission_classes([IsAuthenticated])
+@csrf_exempt
+def upload_breaches(request):
+    # Initialize a list to hold emails
+    emails = []
+
+    # Extracting emails sent as 'email'
+    email = request.POST.get('email')
+    if email:
+        emails.append(email)
+
+    # Extracting emails sent as 'emails[index]'
+    for key in request.POST.keys():
+        if key.startswith('emails['):
+            emails.append(request.POST[key])
+
+    # Handle file if it's uploaded
+    file = request.FILES.get('file')
+    if file:
+        file_data = file.read().decode('utf-8')
+        csv_data = csv.reader(StringIO(file_data))
+        next(csv_data, None)  # Skip the header row
+        for row in csv_data:
+            if row:  # Ensure row is not empty
+                emails.append(row[0])
+
+    # Process each email
+    for email in emails:
+        MonitoredEmail.objects.get_or_create(email=email)
+
+    if emails:
+        return JsonResponse({'message': f'{len(emails)} emails added for monitoring.'}, status=201)
+    else:
+        return JsonResponse({'error': 'No emails provided.'}, status=400)
+
+
+@require_http_methods(["POST"])
+def check_email_breaches(request):
+    email = request.POST.get('email')
+    file = request.FILES.get('file')
+    results = {}
+
+    if email:
+        # Check the single email against breaches
+        results[email] = check_breach(email)
+
+    if file:
+        # Check each email in the CSV against breaches
+        file_data = file.read().decode('utf-8')
+        csv_data = csv.reader(StringIO(file_data))
+        for row in csv_data:
+            email = row[0]
+            results[email] = check_breach(email)
+
+    return JsonResponse({'results': results}, status=200)
+
+
+def check_breach(email):
+    # Placeholder for breach checking logic
+    # This could involve querying your own database or calling an external API
+    # For demonstration, it returns a dummy response
+    return "Not breached"  # or "Breached" based on actual check
diff --git a/backend/db.sqlite3 b/backend/db.sqlite3
index 41edd444f67de71615187c74d2c0db5a4f1d0dac..39a81d346f3fd73efa2982e4f5fbf9b9663658d6 100644
GIT binary patch
delta 7351
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
Th%~VSk;b+l(#Qrx8d?JY0LBh=

delta 762
zcmZo@;B08%m>?~v%)r2)z<>Z&6LpLkl{Y5L=jRaSWnf?s;trV1E}*(uQ9*@!bAa>~
z79lqNG6w#a{8#vQ^Ox~=^RMBr*sNHPz^^9E!mQ1hSXz=1Uyxdqn^|0(nV%=Y%gL<B
z0TxUz$}cToV3<5dUyhAcoSE5}aq>YPVKz2lCT3lZ$v5@YM1{B*7#P_2yBYZ3@t@|u
z#lM$-0e|;q#e#DF$=&vq%o02ali3{%H!CV=@N7=-S;EXL!6!eNJpd%~oOiQ)+#^Oo
z1_lOJUVaAtOuox}w!F)D`8O*n{N-V36k+9^yee05vPo_cOQQ%2h%=d`QJ9%`vSZ#P
zmPTPF-pSWN3=u}&$+`Jcz~=CuW#E6s|Aqf7|3m)kn*|$o^BZ$Ai!+wwnV6Wef>}lR
zl}0Qa%%Y4XdHH3`Afckv#N-ktZf04|lGNgo(&E&jO&eGgI2Z)L0nD{kkm(Emq5}e(
z4zLI?OYoOYX1`##S+T&De|q75Mw!hM?-wU1aj{Hg;8)?h#CetN5N|n87n=xcILlP-
z?=Z;pce|Pc<3h&i_gop-H=koX&b0A@F4OiyZj7dkOpFgU|76!?1_k6raYaSO#_Z{g
z$&8YdJ-JtKae~~?)F>d#KHbrQal-a)AI36aU1oO%VTR8P{8@Yjyjyu*a6RX;;atga
zmqUo{6`KfaF4Jb_Nah1f4UAn(&J3R?8w&JTGP^VG5!cjYY||}COv*{kOD&I&2gfkT
zyQn;N=O9<d5Lbl|M<*Xwh3)2vj3G=y%zX?(f!d4=nR#sbY#=u=Oz%!+GzBq@T;-=v
zOlFkj2N@OLY@*8!wn%yVfn-K?c9!NkY4+`}vl!nnZ(rlVsL9C4wVCn3fB#7nSOnPk
uyBPT2^55h?#lMGtK7ZF{#ey>a>0Rd;t2VPdU>DfV{ebZ&|7MnkKl}jlJJ<{W

diff --git a/backend/watchstone_backend/settings.py b/backend/watchstone_backend/settings.py
index c48b24f23..ba29334f2 100644
--- a/backend/watchstone_backend/settings.py
+++ b/backend/watchstone_backend/settings.py
@@ -41,6 +41,7 @@ INSTALLED_APPS = [
     "rest_framework",
     "rest_framework_simplejwt",
     "corsheaders",
+    "breaches",
 ]
 
 MIDDLEWARE = [
diff --git a/backend/watchstone_backend/urls.py b/backend/watchstone_backend/urls.py
index 1cc09dbf9..d98ae5086 100644
--- a/backend/watchstone_backend/urls.py
+++ b/backend/watchstone_backend/urls.py
@@ -1,26 +1,9 @@
-"""
-URL configuration for watchstone_backend project.
-
-The `urlpatterns` list routes URLs to views. For more information please see:
-    https://docs.djangoproject.com/en/4.2/topics/http/urls/
-Examples:
-Function views
-    1. Add an import:  from my_app import views
-    2. Add a URL to urlpatterns:  path('', views.home, name='home')
-Class-based views
-    1. Add an import:  from other_app.views import Home
-    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
-Including another URLconf
-    1. Import the include() function: from django.urls import include, path
-    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
-"""
-# watchstone_backend/urls.py
-
 from django.contrib import admin
 from django.urls import include, path
 
 urlpatterns = [
     path('admin/', admin.site.urls),
-    path('api/', include('core.urls')),  # This line includes your app URLs
+    path('api/', include('core.urls')),  # Core app URLs
     path('api/auth/', include('auth_app.urls')),
+    path('api/breaches/', include('breaches.urls')),  # Include breaches app URLs
 ]
diff --git a/frontend/src/views/modules/Breaches.js b/frontend/src/views/modules/Breaches.js
index 46daf8c99..68af94267 100644
--- a/frontend/src/views/modules/Breaches.js
+++ b/frontend/src/views/modules/Breaches.js
@@ -12,42 +12,94 @@ import {
   CRow,
 } from '@coreui/react'
 import CIcon from '@coreui/icons-react'
-import { cilTrash, cilPlus } from '@coreui/icons'
+import { cilTrash, cilPlus, cilCloudDownload } from '@coreui/icons'
+import axios from 'axios'
 
 const Breaches = () => {
   const [email, setEmail] = useState('')
   const [file, setFile] = useState(null)
   const [accounts, setAccounts] = useState([{ email: '' }])
 
+  // Function to handle email change
   const handleEmailChange = (e) => setEmail(e.target.value)
 
-  const handleFileChange = (e) => {
-    setFile(e.target.files[0])
-  }
+  // Function to handle file change
+  const handleFileChange = (e) => setFile(e.target.files[0])
 
-  const handleAccountChange = (index, event) => {
+  // Function to handle account email changes
+  const handleAccountChange = (index, e) => {
     const newAccounts = [...accounts]
-    newAccounts[index][event.target.name] = event.target.value
+    newAccounts[index].email = e.target.value
     setAccounts(newAccounts)
   }
 
+  // Function to add a new account input field
   const handleAddAccount = () => {
     setAccounts([...accounts, { email: '' }])
   }
 
+  // Function to remove an account input field
   const handleRemoveAccount = (index) => {
     const newAccounts = [...accounts]
     newAccounts.splice(index, 1)
     setAccounts(newAccounts)
   }
 
-  const handleSubmit = (e) => {
+  // Function to handle the download of a CSV template
+  const handleDownloadTemplate = () => {
+    const templateData = 'Email\nexample@example.com'
+    const blob = new Blob([templateData], { type: 'text/csv;charset=utf-8;' })
+    const link = document.createElement('a')
+    link.href = URL.createObjectURL(blob)
+    link.download = 'email_template.csv'
+    document.body.appendChild(link)
+    link.click()
+    document.body.removeChild(link)
+  }
+
+  // Function to handle form submission for adding to database
+  const handleAddToDatabase = async (e) => {
+    e.preventDefault()
+    const formData = new FormData()
+
+    // Add single email to formData if provided
+    if (email) formData.append('email', email)
+
+    // Add file to formData if provided
+    if (file) formData.append('file', file)
+
+    // Add manually added accounts to formData
+    accounts.forEach((account, index) => {
+      if (account.email) formData.append(`emails[${index}]`, account.email)
+    })
+
+    // Retrieve the token from localStorage
+    const token = localStorage.getItem('token')
+
+    try {
+      await axios.post('http://localhost:8000/api/breaches/upload/', formData, {
+        headers: {
+          Authorization: `Bearer ${token}`,
+          'Content-Type': 'multipart/form-data',
+        },
+      })
+      alert('Data submitted successfully')
+
+      // Reset form fields
+      setEmail('')
+      setFile(null)
+      setAccounts([{ email: '' }])
+    } catch (error) {
+      console.error('Error uploading data:', error)
+      alert('Error submitting data')
+    }
+  }
+
+  // Function for quick check (stubbed, not implemented)
+  const handleSubmitCheck = async (e) => {
     e.preventDefault()
-    // Integration with backend to handle the form data goes here
-    console.log('Email:', email, 'File:', file, 'Accounts:', accounts)
-    setEmail('')
-    setFile(null)
-    setAccounts([{ email: '' }])
+    // Implement the quick check functionality here
+    alert('Quick check functionality not implemented yet')
   }
 
   return (
@@ -56,7 +108,9 @@ const Breaches = () => {
         <CCard>
           <CCardHeader>Check for Breaches</CCardHeader>
           <CCardBody>
-            <CForm onSubmit={handleSubmit}>
+            <CForm>
+              {/* Quick Check Section */}
+              <CCardHeader>Quick Check</CCardHeader>
               <CInputGroup className="mb-3">
                 <CInputGroupText>@</CInputGroupText>
                 <CFormInput
@@ -64,15 +118,11 @@ const Breaches = () => {
                   type="email"
                   value={email}
                   onChange={handleEmailChange}
-                  required
                 />
               </CInputGroup>
 
-              <CInputGroup className="mb-3">
-                <CFormInput type="file" id="fileInput" onChange={handleFileChange} accept=".csv" />
-              </CInputGroup>
-
-              <CCardHeader>Add Accounts Manually</CCardHeader>
+              {/* Add Monitored Emails Section */}
+              <CCardHeader>Add Monitored Emails</CCardHeader>
               {accounts.map((account, index) => (
                 <CInputGroup key={index} className="mb-3">
                   <CFormInput
@@ -80,8 +130,7 @@ const Breaches = () => {
                     placeholder="Account Email"
                     name="email"
                     value={account.email}
-                    onChange={(event) => handleAccountChange(index, event)}
-                    required
+                    onChange={(e) => handleAccountChange(index, e)}
                   />
                   <CButton
                     type="button"
@@ -96,9 +145,21 @@ const Breaches = () => {
               <CButton color="primary" className="mb-3" onClick={handleAddAccount}>
                 <CIcon icon={cilPlus} /> Add Another Account
               </CButton>
-              <div className="d-grid">
-                <CButton type="submit" color="success">
-                  Submit
+
+              {/* File Upload Section */}
+              <CInputGroup className="mb-3">
+                <CFormInput type="file" id="fileInput" onChange={handleFileChange} accept=".csv" />
+              </CInputGroup>
+              <CButton color="secondary" className="mb-3" onClick={handleDownloadTemplate}>
+                <CIcon icon={cilCloudDownload} /> Download CSV Template
+              </CButton>
+
+              <div className="d-grid gap-2">
+                <CButton color="success" onClick={handleSubmitCheck}>
+                  Check
+                </CButton>
+                <CButton color="info" onClick={handleAddToDatabase}>
+                  Add to Database
                 </CButton>
               </div>
             </CForm>
-- 
GitLab