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.
This commit is contained in:
commit
d6f549d5be
23 changed files with 515 additions and 0 deletions
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
config.ini
|
||||
venv/
|
||||
*.pyc
|
||||
__pycache__/
|
||||
db.sqlite3
|
0
dbjsubmissions/__init__.py
Normal file
0
dbjsubmissions/__init__.py
Normal file
16
dbjsubmissions/asgi.py
Normal file
16
dbjsubmissions/asgi.py
Normal file
|
@ -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()
|
110
dbjsubmissions/settings.py
Normal file
110
dbjsubmissions/settings.py
Normal file
|
@ -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'
|
0
dbjsubmissions/submissions/__init__.py
Normal file
0
dbjsubmissions/submissions/__init__.py
Normal file
3
dbjsubmissions/submissions/admin.py
Normal file
3
dbjsubmissions/submissions/admin.py
Normal file
|
@ -0,0 +1,3 @@
|
|||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
6
dbjsubmissions/submissions/apps.py
Normal file
6
dbjsubmissions/submissions/apps.py
Normal file
|
@ -0,0 +1,6 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class SubmissionsConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'dbjsubmissions.submissions'
|
14
dbjsubmissions/submissions/forms.py
Normal file
14
dbjsubmissions/submissions/forms.py
Normal file
|
@ -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",
|
||||
]
|
0
dbjsubmissions/submissions/migrations/__init__.py
Normal file
0
dbjsubmissions/submissions/migrations/__init__.py
Normal file
29
dbjsubmissions/submissions/models.py
Normal file
29
dbjsubmissions/submissions/models.py
Normal file
|
@ -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
|
106
dbjsubmissions/submissions/templates/base.html
Normal file
106
dbjsubmissions/submissions/templates/base.html
Normal file
|
@ -0,0 +1,106 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>{% block title %}Duck Behavior Journal{% endblock %}</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
background-color: #e0e0e0;
|
||||
color: #333;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.container {
|
||||
width: 80%;
|
||||
margin: 0 auto;
|
||||
background-color: #fff;
|
||||
padding: 20px;
|
||||
border: 1px solid #ccc;
|
||||
box-shadow: 2px 2px 12px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
header {
|
||||
background-color: #004d80;
|
||||
color: #fff;
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
nav {
|
||||
background-color: #003366;
|
||||
overflow: hidden;
|
||||
}
|
||||
nav a {
|
||||
float: left;
|
||||
display: block;
|
||||
color: white;
|
||||
text-align: center;
|
||||
padding: 14px 16px;
|
||||
text-decoration: none;
|
||||
}
|
||||
nav a:hover {
|
||||
background-color: #002244;
|
||||
}
|
||||
footer {
|
||||
background-color: #004d80;
|
||||
color: #fff;
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
}
|
||||
table.form-table {
|
||||
width: 100%;
|
||||
margin: 20px 0;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
table.form-table td {
|
||||
padding: 10px;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
table.form-table td label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
table.form-table td input[type="text"],
|
||||
table.form-table td input[type="file"],
|
||||
table.form-table td select {
|
||||
width: 100%;
|
||||
padding: 8px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
}
|
||||
button {
|
||||
background-color: #004d80;
|
||||
color: #fff;
|
||||
padding: 10px 20px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
button:hover {
|
||||
background-color: #003366;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1>Duck Behavior Journal</h1>
|
||||
</header>
|
||||
<nav>
|
||||
<a href="/">Home</a>
|
||||
<a href="/submit/">Submit Manuscript</a>
|
||||
{% if user.is_authenticated %}
|
||||
<a href="{% url 'logout' %}">Logout</a>
|
||||
{% else %}
|
||||
<a href="{% url 'login' %}">Login</a>
|
||||
{% endif %}
|
||||
</nav>
|
||||
<div class="container">
|
||||
{% block content %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
<footer>
|
||||
<p>© 2023 Duck Behavior Journal</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
13
dbjsubmissions/submissions/templates/registration/login.html
Normal file
13
dbjsubmissions/submissions/templates/registration/login.html
Normal file
|
@ -0,0 +1,13 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Login{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h2>Login</h2>
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p }}
|
||||
<button type="submit">Login</button>
|
||||
</form>
|
||||
<p>Don't have an account? <a href="{% url 'register' %}">Register here</a>.</p>
|
||||
{% endblock %}
|
|
@ -0,0 +1,13 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Register{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h2>Register</h2>
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p }}
|
||||
<button type="submit">Register</button>
|
||||
</form>
|
||||
<p>Already have an account? <a href="{% url 'login' %}">Login here</a>.</p>
|
||||
{% endblock %}
|
31
dbjsubmissions/submissions/templates/submissions/index.html
Normal file
31
dbjsubmissions/submissions/templates/submissions/index.html
Normal file
|
@ -0,0 +1,31 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}My Submissions{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h2>My Submissions</h2>
|
||||
<table class="form-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Title</th>
|
||||
<th>Submission Date</th>
|
||||
<th>Status</th>
|
||||
<th>Unique Code</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for submission in submissions %}
|
||||
<tr>
|
||||
<td>{{ submission.title }}</td>
|
||||
<td>{{ submission.submission_date }}</td>
|
||||
<td>{{ submission.get_status_display }}</td>
|
||||
<td>{{ submission.unique_code }}</td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr>
|
||||
<td colspan="4">No submissions found.</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endblock %}
|
|
@ -0,0 +1,8 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Submission Success{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h2>Submission Successful!</h2>
|
||||
<p>Your manuscript has been successfully submitted.</p>
|
||||
{% endblock %}
|
|
@ -0,0 +1,47 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Submit Manuscript{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h2>Submit Your Manuscript</h2>
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
<table class="form-table">
|
||||
<tr>
|
||||
<td><label for="id_title">Title</label></td>
|
||||
<td>{{ form.title }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label for="id_author_full_name">Author Full Name</label></td>
|
||||
<td>{{ form.author_full_name }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label for="id_institution_affiliation">Institution Affiliation</label></td>
|
||||
<td>{{ form.institution_affiliation }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label for="id_corresponding_author_contact">Corresponding Author Contact</label></td>
|
||||
<td>{{ form.corresponding_author_contact }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label for="id_pdf_file">PDF File</label></td>
|
||||
<td>{{ form.pdf_file }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label for="id_mother_maiden_name">Mother's Maiden Name</label></td>
|
||||
<td>{{ form.mother_maiden_name }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label for="id_favorite_duck_species">Favorite Species of Duck</label></td>
|
||||
<td>{{ form.favorite_duck_species }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label for="id_quack_count">Number of Times "Quack" Appears</label></td>
|
||||
<td>{{ form.quack_count }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div style="text-align: center;">
|
||||
<button type="submit">Submit</button>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
3
dbjsubmissions/submissions/tests.py
Normal file
3
dbjsubmissions/submissions/tests.py
Normal file
|
@ -0,0 +1,3 @@
|
|||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
11
dbjsubmissions/submissions/urls.py
Normal file
11
dbjsubmissions/submissions/urls.py
Normal file
|
@ -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'),
|
||||
]
|
51
dbjsubmissions/submissions/views.py
Normal file
51
dbjsubmissions/submissions/views.py
Normal file
|
@ -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
|
8
dbjsubmissions/urls.py
Normal file
8
dbjsubmissions/urls.py
Normal file
|
@ -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')),
|
||||
]
|
16
dbjsubmissions/wsgi.py
Normal file
16
dbjsubmissions/wsgi.py
Normal file
|
@ -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()
|
22
manage.py
Executable file
22
manage.py
Executable file
|
@ -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()
|
3
requirements.txt
Normal file
3
requirements.txt
Normal file
|
@ -0,0 +1,3 @@
|
|||
Django
|
||||
psycopg2-binary
|
||||
django-autosecretkey
|
Loading…
Reference in a new issue