Skip to content
Snippets Groups Projects
Commit 9a672985 authored by Neda Moeini's avatar Neda Moeini
Browse files

Initial commit.

parents
No related branches found
No related tags found
No related merge requests found
Showing
with 414 additions and 0 deletions
venv
.idea
*.pyc
\ No newline at end of file
from django.contrib import admin
# Register your models here.
from django.apps import AppConfig
class FileValidatorConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "file_validator"
# file_validator/forms.py
from django import forms
class CSVUploadForm(forms.Form):
file = forms.FileField(label='Select a CSV file')
def clean_file(self):
file = self.cleaned_data['file']
# Check if the file is a CSV
if not file.name.endswith('.csv'):
raise forms.ValidationError("Only CSV files are allowed")
return file
from django.db import models
# Create your models here.
{% extends 'base.html' %}
{% block title %}CSV Upload{% endblock %}
{% block content %}
<div class="bg-white p-10 rounded-lg shadow-lg w-11/12 md:w-1/2 lg:w-1/3 mx-auto">
<h2 class="text-2xl font-bold mb-6 text-gray-800 text-center">Upload CSV</h2>
<form id="uploadForm" enctype="multipart/form-data" class="space-y-6">
<div>
<label for="fileInput" class="block text-sm font-medium text-gray-700 mb-2">Choose CSV File</label>
<input type="file" name="file" id="fileInput" accept=".csv" class="w-full border border-gray-300 p-3 rounded-lg focus:outline-none focus:ring focus:ring-blue-400">
</div>
<button type="submit" class="w-full bg-blue-600 text-white py-3 rounded-lg hover:bg-blue-700 focus:outline-none focus:ring focus:ring-blue-400">Upload</button>
</form>
<!-- Error Display -->
<div id="errorSection" class="hidden mt-4 bg-red-100 border border-red-400 text-red-700 p-4 rounded-lg">
<strong class="font-bold">Error:</strong>
<ul id="errorList" class="mt-2 list-disc list-inside"></ul>
</div>
<!-- Success Message -->
<div id="successSection" class="hidden mt-4 bg-green-100 border border-green-400 text-green-700 p-4 rounded-lg">
<strong class="font-bold">Success:</strong>
<span id="successMessage" class="block mt-2"></span>
</div>
</div>
<script>
const form = document.getElementById('uploadForm');
const fileInput = document.getElementById('fileInput');
const errorSection = document.getElementById('errorSection');
const errorList = document.getElementById('errorList');
const successSection = document.getElementById('successSection');
const successMessage = document.getElementById('successMessage');
form.addEventListener('submit', async function (e) {
e.preventDefault();
const formData = new FormData();
formData.append('file', fileInput.files[0]);
const response = await fetch('', {
method: 'POST',
body: formData,
headers: {
'X-CSRFToken': '{{ csrf_token }}',
}
});
const result = await response.json();
// Clear previous messages
errorList.innerHTML = '';
successMessage.innerHTML = '';
errorSection.classList.add('hidden');
successSection.classList.add('hidden');
if (response.ok && result.status === 'success') {
// Show success message
successMessage.innerText = result.message;
successSection.classList.remove('hidden');
} else if (response.status === 400 && result.status === 'error') {
// Show errors
result.errors.forEach(error => {
const li = document.createElement('li');
li.textContent = error;
errorList.appendChild(li);
});
errorSection.classList.remove('hidden');
}
});
</script>
{% endblock %}
from django.test import TestCase
# Create your tests here.
from django.urls import path
from .views import CSVUploadView
urlpatterns = [
path('upload/', CSVUploadView.as_view(), name='upload-file'),
]
\ No newline at end of file
import csv
from django.views.generic.edit import FormView
from django.urls import reverse_lazy
from django.http import JsonResponse
from .forms import CSVUploadForm
class CSVUploadView(FormView):
template_name = 'templates/upload.html'
form_class = CSVUploadForm
success_url = reverse_lazy('upload-file')
def get_context_data(self, **kwargs):
"""
This method is called when rendering the form (GET request).
"""
context = super().get_context_data(**kwargs)
context['error'] = None # No error message on GET request
context['message'] = None # No success message on GET request
return context
def form_valid(self, form):
"""
This method is called when the form is valid (POST request).
It handles the CSV validation and passes appropriate error or success messages to the template.
"""
file_obj = form.cleaned_data['file']
try:
# Read and decode the CSV file
csv_file = file_obj.read().decode('utf-8').splitlines()
reader = csv.DictReader(csv_file)
# Example validation: Check for required columns
# TODO: Add the validation logic here. This is just a sample.
required_columns = ['name']
missing_columns = [col for col in required_columns if col not in reader.fieldnames]
if missing_columns:
# If there are missing columns, return error message as JSON
return JsonResponse(
{'status': 'error', 'errors': [f"Missing columns: {', '.join(missing_columns)}"]}, status=400
)
return JsonResponse({'status': 'success', 'message': "CSV file is valid"})
except Exception as e:
# If there's an error (e.g., invalid file content), return the error message as JSON
return JsonResponse({'status': 'error', 'errors': [str(e)]}, status=400)
def form_invalid(self, form):
"""
This method is called when the form is invalid (e.g., wrong file type).
It renders the form again with errors.
"""
return JsonResponse({'status': 'error', 'errors': [form.errors]}, status=400)
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys
def main():
"""Run administrative tasks."""
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'src.sage_validation.settings')
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)
if __name__ == "__main__":
main()
Django==5.1.1
django-tailwind
ruff
mypy
tox
\ No newline at end of file
"""
ASGI config for sage_validation project.
It exposes the ASGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/5.1/howto/deployment/asgi/
"""
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "sage_validation.settings")
application = get_asgi_application()
"""
Django settings for sage_validation project.
Generated by 'django-admin startproject' using Django 5.1.1.
For more information on this file, see
https://docs.djangoproject.com/en/5.1/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/5.1/ref/settings/
"""
from pathlib import Path
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/5.1/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = "django-insecure-9tdba&yktxzclzokj^=uxfsmisgeo8(6!p3koa8ndy8s^3x@@y"
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
]
THIRD_PARTY_APPS = [
"tailwind",
"theme",
]
LOCAL_APPS = [
"file_validator",
]
INSTALLED_APPS += THIRD_PARTY_APPS + LOCAL_APPS
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
]
ROOT_URLCONF = "sage_validation.urls"
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [BASE_DIR / 'templates'],
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.debug",
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
],
},
},
]
WSGI_APPLICATION = "sage_validation.wsgi.application"
# Database
# https://docs.djangoproject.com/en/5.1/ref/settings/#databases
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": BASE_DIR / "db.sqlite3",
}
}
# Password validation
# https://docs.djangoproject.com/en/5.1/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
},
{
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
},
{
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
},
{
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
},
]
# Internationalization
# https://docs.djangoproject.com/en/5.1/topics/i18n/
LANGUAGE_CODE = "en-us"
TIME_ZONE = "UTC"
USE_I18N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/5.1/howto/static-files/
STATIC_URL = "static/"
# Default primary key field type
# https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
INTERNAL_IPS = [
"127.0.0.1",
]
TAILWIND_APP_NAME = "theme"
"""
URL configuration for sage_validation project.
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/5.1/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'))
"""
from django.contrib import admin
from django.urls import path
from django.urls.conf import include
urlpatterns = [
path("admin/", admin.site.urls),
path("file-validator/", include("file_validator.urls")),
]
"""
WSGI config for sage_validation project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/5.1/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "sage_validation.settings")
application = get_wsgi_application()
<!DOCTYPE html>
<html lang="en">
{% load static tailwind_tags %} <!-- Load Tailwind CSS template tags -->
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}CSV Upload{% endblock %}</title>
{% tailwind_css %}
</head>
<body class="bg-gray-100">
<header class="fixed top-0 left-0 w-full bg-blue-900 p-4 z-10">
<div class="container mx-auto flex items-center justify-between">
<!-- GÉANT Logo -->
<img src="https://geant.org/wp-content/uploads/2022/01/geant_logo_f2020_new.svg" alt="GÉANT Logo" class="h-12">
<div class="flex-grow text-center">
<span class="text-white text-2xl font-bold tracking-wide">Sage Validation</span>
</div>
</div>
</header>
<main class="mt-24 p-10">
{% block content %}
{% endblock %}
</main>
<script>
// Global JavaScript code
</script>
</body>
</html>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment