From 5362fe2b874a6779a9b6d4383227a1c5f176e228 Mon Sep 17 00:00:00 2001
From: Neda Moeini <neda.moeini@geant.org>
Date: Mon, 3 Mar 2025 11:00:44 +0100
Subject: [PATCH] Add activity log

---
 sage_validation/accounts/__init__.py          |  0
 sage_validation/accounts/admin.py             |  8 +++
 sage_validation/accounts/apps.py              |  6 ++
 .../accounts/migrations/0001_initial.py       | 55 +++++++++++++++++++
 .../accounts/migrations/__init__.py           |  0
 sage_validation/accounts/views.py             |  3 +
 sage_validation/file_validator/views.py       | 11 +++-
 sage_validation/settings.py                   |  1 +
 8 files changed, 83 insertions(+), 1 deletion(-)
 create mode 100644 sage_validation/accounts/__init__.py
 create mode 100644 sage_validation/accounts/admin.py
 create mode 100644 sage_validation/accounts/apps.py
 create mode 100644 sage_validation/accounts/migrations/0001_initial.py
 create mode 100644 sage_validation/accounts/migrations/__init__.py
 create mode 100644 sage_validation/accounts/views.py

diff --git a/sage_validation/accounts/__init__.py b/sage_validation/accounts/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/sage_validation/accounts/admin.py b/sage_validation/accounts/admin.py
new file mode 100644
index 0000000..8d326a8
--- /dev/null
+++ b/sage_validation/accounts/admin.py
@@ -0,0 +1,8 @@
+from django.contrib import admin
+from .models import UserActivityLog
+
+@admin.register(UserActivityLog)
+class UserActivityLogAdmin(admin.ModelAdmin):
+    list_display = ("user", "action", "name", "input_file_hash", "output_file_hash", "timestamp")
+    search_fields = ("user__username", "name", "action")
+    list_filter = ("action", "timestamp")
\ No newline at end of file
diff --git a/sage_validation/accounts/apps.py b/sage_validation/accounts/apps.py
new file mode 100644
index 0000000..3b83649
--- /dev/null
+++ b/sage_validation/accounts/apps.py
@@ -0,0 +1,6 @@
+from django.apps import AppConfig
+
+
+class AccountsConfig(AppConfig):
+    default_auto_field = "django.db.models.BigAutoField"
+    name = "sage_validation.accounts"
diff --git a/sage_validation/accounts/migrations/0001_initial.py b/sage_validation/accounts/migrations/0001_initial.py
new file mode 100644
index 0000000..163c095
--- /dev/null
+++ b/sage_validation/accounts/migrations/0001_initial.py
@@ -0,0 +1,55 @@
+# Generated by Django 5.0.11 on 2025-03-03 09:09
+
+import django.db.models.deletion
+from django.conf import settings
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+    initial = True
+
+    dependencies = [
+        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name="UserActivityLog",
+            fields=[
+                (
+                    "id",
+                    models.BigAutoField(
+                        auto_created=True,
+                        primary_key=True,
+                        serialize=False,
+                        verbose_name="ID",
+                    ),
+                ),
+                (
+                    "action",
+                    models.CharField(
+                        choices=[("upload", "Upload"), ("download", "Download")],
+                        max_length=10,
+                    ),
+                ),
+                ("name", models.CharField(max_length=255)),
+                (
+                    "input_file_hash",
+                    models.CharField(blank=True, max_length=64, null=True),
+                ),
+                (
+                    "output_file_hash",
+                    models.CharField(blank=True, max_length=64, null=True),
+                ),
+                ("timestamp", models.DateTimeField(auto_now_add=True)),
+                (
+                    "user",
+                    models.ForeignKey(
+                        on_delete=django.db.models.deletion.CASCADE,
+                        related_name="activity_logs",
+                        to=settings.AUTH_USER_MODEL,
+                    ),
+                ),
+            ],
+        ),
+    ]
diff --git a/sage_validation/accounts/migrations/__init__.py b/sage_validation/accounts/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/sage_validation/accounts/views.py b/sage_validation/accounts/views.py
new file mode 100644
index 0000000..91ea44a
--- /dev/null
+++ b/sage_validation/accounts/views.py
@@ -0,0 +1,3 @@
+from django.shortcuts import render
+
+# Create your views here.
diff --git a/sage_validation/file_validator/views.py b/sage_validation/file_validator/views.py
index bfa80c2..e7c4002 100644
--- a/sage_validation/file_validator/views.py
+++ b/sage_validation/file_validator/views.py
@@ -11,6 +11,7 @@ from rest_framework.request import Request
 from rest_framework.response import Response
 from rest_framework.views import APIView
 
+from sage_validation.accounts.models import UserActivityLog
 from sage_validation.file_validator.forms import CSVUploadForm
 from sage_validation.file_validator.models import MeoCostCentres, XxData
 
@@ -49,7 +50,15 @@ class CSVUploadAPIView(APIView):
         updated_data = self.update_fields(csv_data)
         request.session["validated_csv"] = updated_data
         request.session.modified = True
-
+        # Log the user activity
+        UserActivityLog.objects.create(
+            user=request.user,
+            action="upload",
+            name=csv_file.name,
+            input_file_hash=UserActivityLog.generate_file_hash(csv_file),
+            output_file_hash=UserActivityLog.generate_file_hash(updated_data),
+            timestamp=timezone.now()
+        )
         return Response({
             "status": "success",
             "message": "File successfully uploaded and processed.",
diff --git a/sage_validation/settings.py b/sage_validation/settings.py
index 353594e..8e1a0ff 100644
--- a/sage_validation/settings.py
+++ b/sage_validation/settings.py
@@ -36,6 +36,7 @@ INSTALLED_APPS = [
 ]
 LOCAL_APPS = [
     "sage_validation.file_validator",
+    "sage_validation.accounts",
 ]
 THIRD_PARTY_APPS: list[str] = []
 
-- 
GitLab