From 34601f019e2b42f5af1c802c49038e90c9d130ef Mon Sep 17 00:00:00 2001
From: James2Tulloch <146088090+James2Tulloch@users.noreply.github.com>
Date: Fri, 21 Feb 2025 11:12:03 +0000
Subject: [PATCH] Working basic user registration

---
 Dockerfile                                    |  52 +++++++-----
 django_project/myapp/.DS_Store                | Bin 6148 -> 6148 bytes
 django_project/myapp/entrypoint.sh            |  11 +++
 .../myapp/management/commands/initdb.py       |  17 ++++
 .../myapp/templates/myapp/login.html          |  22 +++--
 .../myapp/templates/myapp/register.html       |  28 +++++--
 django_project/myapp/views.py                 |  75 ++++++++++++------
 7 files changed, 145 insertions(+), 60 deletions(-)
 create mode 100755 django_project/myapp/entrypoint.sh
 create mode 100644 django_project/myapp/management/commands/initdb.py

diff --git a/Dockerfile b/Dockerfile
index 162d11b..f99ad09 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,57 +1,67 @@
 # Stage 1: Build the Rust extension using maturin
 FROM rust:latest as builder
 
-# Install Python and system dependencies required for maturin
+# Install Python, venv, and build dependencies
 RUN apt-get update && apt-get install -y \
     python3 \
-    python3-pip \
+    python3-venv \
+    python3-dev \
     build-essential \
-    libssl-dev
+    libssl-dev && \
+    rm -rf /var/lib/apt/lists/*
+
+# Create and activate a virtual environment
+RUN python3 -m venv /venv
+ENV PATH="/venv/bin:$PATH"
+
+# Upgrade pip (no need for --break-system-packages in a venv)
+RUN pip install --upgrade pip
 
 # Install maturin
-RUN pip3 install --break-system-packages maturin
+RUN pip install maturin
 
 WORKDIR /build
 
-# Copy the Rust project folder into the builder stage.
-# This assumes the folder "rust_crud_api" is in the build context.
+# Copy the rust_crud_api project folder into the builder stage
 COPY rust_crud_api/ ./rust_crud_api/
 
-# Change directory into the Rust project and build the wheel.
+# Change into the rust_crud_api directory and build the wheel
 WORKDIR /build/rust_crud_api
 RUN maturin build --release
 
 # Stage 2: Build the final Django container
 FROM python:3.11-slim
 
-# Install system dependencies needed for Django and Postgres
-RUN apt-get update && apt-get install -y libpq-dev gcc && rm -rf /var/lib/apt/lists/*
+# Install system dependencies for Django and PostgreSQL client
+RUN apt-get update && apt-get install -y \
+    libpq-dev \
+    gcc && \
+    rm -rf /var/lib/apt/lists/*
 
 WORKDIR /app
 
-# Copy the built Rust extension wheel from the builder stage.
-# This assumes maturin built the wheel into rust_crud_api/target/wheels/
+# Copy the built wheel from the builder stage
 COPY --from=builder /build/rust_crud_api/target/wheels/*.whl .
 
-# Install the Rust extension into the Python environment.
+# Install the Rust extension
 RUN pip install --no-cache-dir *.whl
 
-# Copy your Django project into the container.
-# In this example, we assume the Django project (including manage.py) is inside the "django_project" folder.
+# Copy the Django project into the container
 COPY django_project/ ./django_project/
 
-# Set the working directory to your Django project folder.
+# Change working directory to the Django project folder
 WORKDIR /app/django_project
 
-# Install Django and other Python dependencies (adjust as needed).
+# Install Django and the PostgreSQL adapter
 RUN pip install --no-cache-dir django psycopg2-binary
 
-# Set environment variables (adjust the DATABASE_URL as needed).
-ENV DATABASE_URL=postgres://postgres:postgres@db:5432/postgres
+# Copy the entrypoint script from your app directory and ensure it's executable
+COPY django_project/myapp/entrypoint.sh ./myapp/entrypoint.sh
+RUN chmod +x ./myapp/entrypoint.sh
 
-# Expose the port that Django will run on.
+# Expose the port Django will run on
 EXPOSE 8000
 
-# Run the Django development server (for production use a proper WSGI/ASGI server).
-CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]
+# Run the entrypoint script (which should run migrations, init the database, and start the server)
+CMD ["/app/django_project/myapp/entrypoint.sh"]
 
diff --git a/django_project/myapp/.DS_Store b/django_project/myapp/.DS_Store
index 98099036d71ed48c5219617645a892d80e5a4bae..674394648b1cfb241b58e57b2016a69134322d6d 100644
GIT binary patch
delta 266
zcmZoMXfc@J&&aniU^g=(-((&Z4L(L$1_lPb|6sttFxiPkS-cxrgn@y9ogtB-fT3Wr
z1G{+rPc%7RhE#?;h7yJ%hDwG4hJ1!hFi(%6m?6V6CqFqUCqIdSfkA+Qfe~ctJg_zY
z89;!GA(tVMA&()EA)O(WAs1o}njVnbQ1nc`!6LGG2a5yaWGyz8$uewwObqKc>#%7t
jN-;PxFfbsi<zOgd$Ye-mD4*=WF2=*K9wEJngGB%U8Ddj0

delta 184
zcmZoMXfc@J&&abeU^g=(&tx7J4H<^T3=9kt|3d)-0|N&`B0~y8E<+|m-ed(9QE?##
z28Q`i>HiE24D1Yv3<V4YlLOeq_!t`)7#Oy~BscT1MlkX*1T!!&OooX~ZeSOi+{MN>
zIgL$a^By)1Mk&Vk3=9mrVe()L%NQ~lQW?r82e66rMlmoj%z?>HEG*v4&heKY01b~#
A9{>OV

diff --git a/django_project/myapp/entrypoint.sh b/django_project/myapp/entrypoint.sh
new file mode 100755
index 0000000..9de6c62
--- /dev/null
+++ b/django_project/myapp/entrypoint.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+set -e
+
+# Apply database migrations
+python manage.py migrate --noinput
+
+# Run the custom database initialization command
+python manage.py initdb
+
+# Start the Django development server (or your production server)
+exec python manage.py runserver 0.0.0.0:8000
diff --git a/django_project/myapp/management/commands/initdb.py b/django_project/myapp/management/commands/initdb.py
new file mode 100644
index 0000000..8ceabcf
--- /dev/null
+++ b/django_project/myapp/management/commands/initdb.py
@@ -0,0 +1,17 @@
+# myapp/management/commands/initdb.py
+
+from django.core.management.base import BaseCommand
+from django.conf import settings
+import rust_crud_api
+
+class Command(BaseCommand):
+    help = 'Initializes the database by creating necessary tables via the Rust extension'
+
+    def handle(self, *args, **options):
+        db_url = settings.DATABASE_URL
+        try:
+            rust_crud_api.init_db(db_url)
+            self.stdout.write(self.style.SUCCESS('Database initialized successfully.'))
+        except Exception as e:
+            self.stderr.write(self.style.ERROR(f'Error initializing database: {e}'))
+
diff --git a/django_project/myapp/templates/myapp/login.html b/django_project/myapp/templates/myapp/login.html
index 36e1ee9..1b2e6f2 100644
--- a/django_project/myapp/templates/myapp/login.html
+++ b/django_project/myapp/templates/myapp/login.html
@@ -1,21 +1,29 @@
 <!DOCTYPE html>
-<html>
+<html lang="en">
 <head>
+    <meta charset="UTF-8">
     <title>Login</title>
+    <style>
+        body { font-family: Arial, sans-serif; margin: 2em; }
+        .error { color: red; }
+    </style>
 </head>
 <body>
     <h1>Login</h1>
-    {% if messages %}
-        {% for message in messages %}
-            <p>{{ message }}</p>
-        {% endfor %}
+    {% if error %}
+      <p class="error">{{ error }}</p>
     {% endif %}
     <form method="post">
         {% csrf_token %}
-        {{ form.as_p }}
+        <label for="email">Email:</label>
+        <input type="email" name="email" id="email" required>
+        <br><br>
         <button type="submit">Login</button>
     </form>
-    <p>Don't have an account? <a href="{% url 'register' %}">Register here</a>.</p>
+    <p>
+        Don't have an account?
+        <a href="{% url 'register' %}">Register here</a>
+    </p>
 </body>
 </html>
 
diff --git a/django_project/myapp/templates/myapp/register.html b/django_project/myapp/templates/myapp/register.html
index 35a9694..97e890f 100644
--- a/django_project/myapp/templates/myapp/register.html
+++ b/django_project/myapp/templates/myapp/register.html
@@ -1,21 +1,35 @@
 <!DOCTYPE html>
-<html>
+<html lang="en">
 <head>
+    <meta charset="UTF-8">
     <title>Register</title>
+    <style>
+        body { font-family: Arial, sans-serif; margin: 2em; }
+        .error { color: red; }
+    </style>
 </head>
 <body>
     <h1>Register</h1>
-    {% if messages %}
-        {% for message in messages %}
-            <p>{{ message }}</p>
-        {% endfor %}
+    
+    {% if error %}
+      <p class="error">{{ error }}</p>
     {% endif %}
+    
     <form method="post">
         {% csrf_token %}
-        {{ form.as_p }}
+        <label for="id_name">Name:</label>
+        <input type="text" name="name" id="id_name" required><br><br>
+        
+        <label for="id_email">Email:</label>
+        <input type="email" name="email" id="id_email" required><br><br>
+        
         <button type="submit">Register</button>
     </form>
-    <p>Already have an account? <a href="{% url 'login' %}">Login here</a>.</p>
+    
+    <p>
+        Already have an account?
+        <a href="{% url 'login' %}">Login here</a>.
+    </p>
 </body>
 </html>
 
diff --git a/django_project/myapp/views.py b/django_project/myapp/views.py
index a29ed48..63c9eba 100644
--- a/django_project/myapp/views.py
+++ b/django_project/myapp/views.py
@@ -16,59 +16,84 @@ def init_db_view(request):
 
 def register_view(request):
     """
-    Register a new user using the Rust extension.
-    Expects POST with 'name' and 'email'.
-    After registration, it simulates a login by storing the user's info in session.
+    Handle user registration:
+      - Display the registration form on GET.
+      - On POST, create a new user via the Rust extension.
+      - If successful, simulate login by storing the user in the session,
+        then redirect to an account page.
     """
-    db_url = settings.DATABASE_URL
+    db_url = settings.DATABASE_URL  # Make sure this is defined in settings.py
+    context = {}
+    
     if request.method == 'POST':
         name = request.POST.get('name')
         email = request.POST.get('email')
+        
         if not name or not email:
-            return JsonResponse({'error': 'Name and email are required.'}, status=400)
+            context['error'] = "Both name and email are required."
+            return render(request, 'myapp/register.html', context)
+        
         try:
-            # Create user in the database via the Rust extension.
+            # Create the user via the Rust extension.
             rust_crud_api.create_user(db_url, name, email)
-            # Since our extension does not return the new user’s id directly,
-            # we retrieve all users and find the one with the matching email.
+            
+            # Optionally, simulate login by retrieving all users and finding the new one.
+            # (In a production system, you'd have proper password handling.)
             users = rust_crud_api.get_all_users(db_url)
-            user = next((u for u in users if u.email == email), None)
+            user = next((u for u in users if u.email.lower() == email.lower()), None)
+            
             if user is None:
-                return JsonResponse({'error': 'Registration failed.'}, status=500)
-            # Simulate login by storing user info in session.
+                context['error'] = "Registration failed. Please try again."
+                return render(request, 'myapp/register.html', context)
+            
+            # Store user information in the session to simulate login.
             request.session['user_id'] = user.id
-            request.session['user_email'] = user.email
             request.session['user_name'] = user.name
+            request.session['user_email'] = user.email
+            
             return redirect('account')
         except Exception as e:
-            return JsonResponse({'error': str(e)}, status=500)
-    return render(request, 'myapp/register.html')
-
+            context['error'] = f"An error occurred: {str(e)}"
+            return render(request, 'myapp/register.html', context)
+    
+    # For GET requests, just display the registration form.
+    return render(request, 'myapp/register.html', context)
 
 def login_view(request):
     """
-    Login a user by looking up their email in the database.
-    (Since our Rust extension doesn't handle passwords, we simply check if the email exists.)
+    Handles user login by checking for the user's email in the database using the Rust extension.
+    If a matching user is found, their info is stored in the session.
     """
-    db_url = settings.DATABASE_URL
+    db_url = settings.DATABASE_URL  # This should be defined in your settings.py
+    context = {}
+    
     if request.method == 'POST':
         email = request.POST.get('email')
         if not email:
-            return JsonResponse({'error': 'Email is required.'}, status=400)
+            context['error'] = "Email is required."
+            return render(request, 'myapp/login.html', context)
+        
         try:
-            # Retrieve all users and try to find one with the given email.
+            # Retrieve all users from the database via the Rust extension
             users = rust_crud_api.get_all_users(db_url)
-            user = next((u for u in users if u.email == email), None)
+            # Find a user with the matching email
+            user = next((u for u in users if u.email.lower() == email.lower()), None)
             if user is None:
-                return JsonResponse({'error': 'User not found.'}, status=404)
-            # Simulate login by storing user info in session.
+                context['error'] = "User not found. Please register first."
+                return render(request, 'myapp/login.html', context)
+            
+            # Simulate a login by storing user information in the session.
             request.session['user_id'] = user.id
             request.session['user_email'] = user.email
             request.session['user_name'] = user.name
+            
+            # Redirect to the account page or another dashboard.
             return redirect('account')
         except Exception as e:
-            return JsonResponse({'error': str(e)}, status=500)
-    return render(request, 'myapp/login.html')
+            context['error'] = f"An error occurred: {str(e)}"
+            return render(request, 'myapp/login.html', context)
+    
+    return render(request, 'myapp/login.html', context)
 
 
 def account_view(request):
-- 
GitLab