commit d6f549d5beb77c908343afd313e712c1afaf24bc Author: Kumi Date: Tue Sep 3 20:57:52 2024 +0200 feat: create initial Django project for submissions Initialized a new Django project named "dbjsubmissions" with essential configuration and initial app setup. Added .gitignore to ignore common unwanted files. Implemented models, views, forms, templates, and urls for managing manuscript submissions. Configured settings for basic functionality, including required third-party packages in requirements.txt. Supports user registration, login, and manuscript submission workflows. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..46282c2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +config.ini +venv/ +*.pyc +__pycache__/ +db.sqlite3 \ No newline at end of file diff --git a/dbjsubmissions/__init__.py b/dbjsubmissions/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/dbjsubmissions/asgi.py b/dbjsubmissions/asgi.py new file mode 100644 index 0000000..c31fac4 --- /dev/null +++ b/dbjsubmissions/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for dbjsubmissions 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', 'dbjsubmissions.settings') + +application = get_asgi_application() diff --git a/dbjsubmissions/settings.py b/dbjsubmissions/settings.py new file mode 100644 index 0000000..44e3a55 --- /dev/null +++ b/dbjsubmissions/settings.py @@ -0,0 +1,110 @@ +from pathlib import Path +from autosecretkey import AutoSecretKey + +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent + +ASK = AutoSecretKey('config.ini') + +SECRET_KEY = ASK.secret_key + +# 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', + 'dbjsubmissions.submissions', +] + +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 = 'dbjsubmissions.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + '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 = 'dbjsubmissions.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' diff --git a/dbjsubmissions/submissions/__init__.py b/dbjsubmissions/submissions/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/dbjsubmissions/submissions/admin.py b/dbjsubmissions/submissions/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/dbjsubmissions/submissions/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/dbjsubmissions/submissions/apps.py b/dbjsubmissions/submissions/apps.py new file mode 100644 index 0000000..e5880b1 --- /dev/null +++ b/dbjsubmissions/submissions/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class SubmissionsConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'dbjsubmissions.submissions' diff --git a/dbjsubmissions/submissions/forms.py b/dbjsubmissions/submissions/forms.py new file mode 100644 index 0000000..94c5312 --- /dev/null +++ b/dbjsubmissions/submissions/forms.py @@ -0,0 +1,14 @@ +from django import forms +from .models import Submission + + +class SubmissionForm(forms.ModelForm): + class Meta: + model = Submission + fields = [ + "title", + "author_full_name", + "institution_affiliation", + "corresponding_author_contact", + "pdf_file", + ] diff --git a/dbjsubmissions/submissions/migrations/__init__.py b/dbjsubmissions/submissions/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/dbjsubmissions/submissions/models.py b/dbjsubmissions/submissions/models.py new file mode 100644 index 0000000..abce1f6 --- /dev/null +++ b/dbjsubmissions/submissions/models.py @@ -0,0 +1,29 @@ +import uuid +from django.db import models +from django.contrib.auth.models import User + +class Submission(models.Model): + STATUS_CHOICES = [ + ('submitted', 'Submitted'), + ('under_review', 'Under Review'), + ('accepted', 'Accepted'), + ('rejected', 'Rejected'), + ] + + user = models.ForeignKey(User, on_delete=models.CASCADE) + title = models.CharField(max_length=100) + author_full_name = models.CharField(max_length=255) + institution_affiliation = models.TextField() + corresponding_author_contact = models.TextField() + pdf_file = models.FileField(upload_to='submissions/') + submission_date = models.DateTimeField(auto_now_add=True) + status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='submitted') + unique_code = models.CharField(max_length=27, unique=True, editable=False) + + def save(self, *args, **kwargs): + if not self.unique_code: + self.unique_code = uuid.uuid4().hex[:27].upper() + super().save(*args, ** kwargs) + + def __str__(self): + return self.title diff --git a/dbjsubmissions/submissions/templates/base.html b/dbjsubmissions/submissions/templates/base.html new file mode 100644 index 0000000..8179c6d --- /dev/null +++ b/dbjsubmissions/submissions/templates/base.html @@ -0,0 +1,106 @@ + + + + {% block title %}Duck Behavior Journal{% endblock %} + + + +
+

Duck Behavior Journal

+
+ +
+ {% block content %} + {% endblock %} +
+ + + diff --git a/dbjsubmissions/submissions/templates/registration/login.html b/dbjsubmissions/submissions/templates/registration/login.html new file mode 100644 index 0000000..f93591e --- /dev/null +++ b/dbjsubmissions/submissions/templates/registration/login.html @@ -0,0 +1,13 @@ +{% extends "base.html" %} + +{% block title %}Login{% endblock %} + +{% block content %} +

Login

+
+ {% csrf_token %} + {{ form.as_p }} + +
+

Don't have an account? Register here.

+{% endblock %} diff --git a/dbjsubmissions/submissions/templates/registration/register.html b/dbjsubmissions/submissions/templates/registration/register.html new file mode 100644 index 0000000..d17e464 --- /dev/null +++ b/dbjsubmissions/submissions/templates/registration/register.html @@ -0,0 +1,13 @@ +{% extends "base.html" %} + +{% block title %}Register{% endblock %} + +{% block content %} +

Register

+
+ {% csrf_token %} + {{ form.as_p }} + +
+

Already have an account? Login here.

+{% endblock %} diff --git a/dbjsubmissions/submissions/templates/submissions/index.html b/dbjsubmissions/submissions/templates/submissions/index.html new file mode 100644 index 0000000..182d59b --- /dev/null +++ b/dbjsubmissions/submissions/templates/submissions/index.html @@ -0,0 +1,31 @@ +{% extends "base.html" %} + +{% block title %}My Submissions{% endblock %} + +{% block content %} +

My Submissions

+ + + + + + + + + + + {% for submission in submissions %} + + + + + + + {% empty %} + + + + {% endfor %} + +
TitleSubmission DateStatusUnique Code
{{ submission.title }}{{ submission.submission_date }}{{ submission.get_status_display }}{{ submission.unique_code }}
No submissions found.
+{% endblock %} diff --git a/dbjsubmissions/submissions/templates/submissions/submission_success.html b/dbjsubmissions/submissions/templates/submissions/submission_success.html new file mode 100644 index 0000000..2dadf84 --- /dev/null +++ b/dbjsubmissions/submissions/templates/submissions/submission_success.html @@ -0,0 +1,8 @@ +{% extends "base.html" %} + +{% block title %}Submission Success{% endblock %} + +{% block content %} +

Submission Successful!

+

Your manuscript has been successfully submitted.

+{% endblock %} diff --git a/dbjsubmissions/submissions/templates/submissions/submit_manuscript.html b/dbjsubmissions/submissions/templates/submissions/submit_manuscript.html new file mode 100644 index 0000000..a2a7982 --- /dev/null +++ b/dbjsubmissions/submissions/templates/submissions/submit_manuscript.html @@ -0,0 +1,47 @@ +{% extends "base.html" %} + +{% block title %}Submit Manuscript{% endblock %} + +{% block content %} +

Submit Your Manuscript

+
+ {% csrf_token %} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
{{ form.title }}
{{ form.author_full_name }}
{{ form.institution_affiliation }}
{{ form.corresponding_author_contact }}
{{ form.pdf_file }}
{{ form.mother_maiden_name }}
{{ form.favorite_duck_species }}
{{ form.quack_count }}
+
+ +
+
+{% endblock %} diff --git a/dbjsubmissions/submissions/tests.py b/dbjsubmissions/submissions/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/dbjsubmissions/submissions/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/dbjsubmissions/submissions/urls.py b/dbjsubmissions/submissions/urls.py new file mode 100644 index 0000000..ac45579 --- /dev/null +++ b/dbjsubmissions/submissions/urls.py @@ -0,0 +1,11 @@ +from django.contrib import admin +from django.urls import path, include +from dbjsubmissions.submissions.views import IndexView, SubmissionCreateView, SubmissionSuccessView, RegisterView + +urlpatterns = [ + path('admin/', admin.site.urls), + path('', IndexView.as_view(), name='index'), + path('submit/', SubmissionCreateView.as_view(), name='submit_manuscript'), + path('submission_success/', SubmissionSuccessView.as_view(), name='submission_success'), + path('accounts/register/', RegisterView.as_view(), name='register'), +] diff --git a/dbjsubmissions/submissions/views.py b/dbjsubmissions/submissions/views.py new file mode 100644 index 0000000..80a94a4 --- /dev/null +++ b/dbjsubmissions/submissions/views.py @@ -0,0 +1,51 @@ +from django.urls import reverse_lazy +from django.views.generic import ListView, CreateView, TemplateView +from django.contrib.auth.mixins import LoginRequiredMixin +from django.contrib.auth.forms import UserCreationForm +from django.contrib.auth.models import User +from django.contrib.auth import authenticate, login +from django.shortcuts import redirect +from .models import Submission +from .forms import SubmissionForm + +class IndexView(LoginRequiredMixin, ListView): + model = Submission + template_name = 'submissions/index.html' + context_object_name = 'submissions' + + def get_queryset(self): + return Submission.objects.filter(user=self.request.user) + +class SubmissionCreateView(LoginRequiredMixin, CreateView): + model = Submission + form_class = SubmissionForm + template_name = 'submissions/submit_manuscript.html' + success_url = reverse_lazy('submission_success') + + def form_valid(self, form): + form.instance.user = self.request.user + response = super().form_valid(form) + self.request.session['unique_code'] = form.instance.unique_code + return response + +class SubmissionSuccessView(LoginRequiredMixin, TemplateView): + template_name = 'submissions/submission_success.html' + + def get_context_data(self, **kwargs): + context = super().get_context_data(** kwargs) + context['unique_code'] = self.request.session.get('unique_code', '') + return context + +class RegisterView(CreateView): + model = User + form_class = UserCreationForm + template_name = 'registration/register.html' + success_url = reverse_lazy('login') + + def form_valid(self, form): + valid = super(RegisterView, self).form_valid(form) + username = form.cleaned_data.get('username') + password = form.cleaned_data.get('password1') + user = authenticate(username=username, password=password) + login(self.request, user) + return valid diff --git a/dbjsubmissions/urls.py b/dbjsubmissions/urls.py new file mode 100644 index 0000000..33073ac --- /dev/null +++ b/dbjsubmissions/urls.py @@ -0,0 +1,8 @@ +from django.contrib import admin +from django.urls import path, include + +urlpatterns = [ + path('admin/', admin.site.urls), + path('accounts/', include('django.contrib.auth.urls')), + path('', include('dbjsubmissions.submissions.urls')), +] diff --git a/dbjsubmissions/wsgi.py b/dbjsubmissions/wsgi.py new file mode 100644 index 0000000..0af97cd --- /dev/null +++ b/dbjsubmissions/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for dbjsubmissions 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', 'dbjsubmissions.settings') + +application = get_wsgi_application() diff --git a/manage.py b/manage.py new file mode 100755 index 0000000..704037f --- /dev/null +++ b/manage.py @@ -0,0 +1,22 @@ +#!/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', 'dbjsubmissions.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() diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..df1ae50 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +Django +psycopg2-binary +django-autosecretkey \ No newline at end of file