Merge branch 'kybo' of github.com:flifloo/nuitdelinfo_2021 into kybo
This commit is contained in:
commit
aa48208d29
73 changed files with 831 additions and 11 deletions
30
.github/workflows/django.yml
vendored
Normal file
30
.github/workflows/django.yml
vendored
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
name: Django CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ master, flifloo, kybo ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ master, flifloo, kybo ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
max-parallel: 4
|
||||||
|
matrix:
|
||||||
|
python-version: [3.7, 3.8, 3.9]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Set up Python ${{ matrix.python-version }}
|
||||||
|
uses: actions/setup-python@v2
|
||||||
|
with:
|
||||||
|
python-version: ${{ matrix.python-version }}
|
||||||
|
- name: Install Dependencies
|
||||||
|
run: |
|
||||||
|
python -m pip install --upgrade pip
|
||||||
|
pip install -r requirements.txt
|
||||||
|
- name: Run Tests
|
||||||
|
run: |
|
||||||
|
python manage.py test
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -109,3 +109,4 @@ GitHub.sublime-settings
|
||||||
!.vscode/launch.json
|
!.vscode/launch.json
|
||||||
!.vscode/extensions.json
|
!.vscode/extensions.json
|
||||||
.history
|
.history
|
||||||
|
/nuitdelinfo_2021/settings.py
|
||||||
|
|
9
Dockerfile
Normal file
9
Dockerfile
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
FROM python:3.9.9-alpine
|
||||||
|
WORKDIR /nuitdelinfo_2021
|
||||||
|
COPY . .
|
||||||
|
RUN apk add --no-cache postgresql-libs && \
|
||||||
|
apk add --no-cache --virtual .build-deps gcc musl-dev postgresql-dev && \
|
||||||
|
pip install --no-cache-dir -r requirements.txt && \
|
||||||
|
apk --purge del .build-deps
|
||||||
|
RUN cp /nuitdelinfo_2021/nuitdelinfo_2021/settings.py.exemple /nuitdelinfo_2021/nuitdelinfo_2021/settings.py
|
||||||
|
CMD [ "python", "./manage.py", "runserver", "0.0.0.0:8000"]
|
0
crew/__init__.py
Normal file
0
crew/__init__.py
Normal file
3
crew/admin.py
Normal file
3
crew/admin.py
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
# Register your models here.
|
6
crew/apps.py
Normal file
6
crew/apps.py
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class CrewConfig(AppConfig):
|
||||||
|
default_auto_field = 'django.db.models.BigAutoField'
|
||||||
|
name = 'crew'
|
0
crew/migrations/__init__.py
Normal file
0
crew/migrations/__init__.py
Normal file
10
crew/models.py
Normal file
10
crew/models.py
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
from django.db.models import Model, CharField, ManyToManyField, TextField
|
||||||
|
|
||||||
|
from nuitdelinfo_2021.models import People
|
||||||
|
|
||||||
|
|
||||||
|
class Crew(Model):
|
||||||
|
name = CharField()
|
||||||
|
members = ManyToManyField(People)
|
||||||
|
|
||||||
|
description = TextField()
|
3
crew/tests.py
Normal file
3
crew/tests.py
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
7
crew/urls.py
Normal file
7
crew/urls.py
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
from django.urls import path
|
||||||
|
|
||||||
|
from . import views
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
path('<int:crew_id>', views.index, name='index'),
|
||||||
|
]
|
6
crew/views.py
Normal file
6
crew/views.py
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
from django.shortcuts import render
|
||||||
|
|
||||||
|
|
||||||
|
def index(request, crew_id: int):
|
||||||
|
context = {}
|
||||||
|
return render(request, "crew.html", context)
|
25
docker-compose.yml
Normal file
25
docker-compose.yml
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
version: "3"
|
||||||
|
|
||||||
|
services:
|
||||||
|
django:
|
||||||
|
container_name: "nuitdelinfo_2021"
|
||||||
|
build: ./
|
||||||
|
image: nuitdelinfo_2021
|
||||||
|
ports:
|
||||||
|
- "8001:8000"
|
||||||
|
volumes:
|
||||||
|
- "django:/nuitdelinfo_2021/"
|
||||||
|
|
||||||
|
postgres:
|
||||||
|
container_name: "nuitdelinfo_2021_db"
|
||||||
|
image: postgres
|
||||||
|
environment:
|
||||||
|
POSTGRES_PASSWORD: nuitdelinfo_2021
|
||||||
|
POSTGRES_USER: nuitdelinfo_2021
|
||||||
|
POSTGRES_DB: nuitdelinfo_2021
|
||||||
|
volumes:
|
||||||
|
- "db:/var/lib/postgresql/data"
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
django:
|
||||||
|
db:
|
0
error/__init__.py
Normal file
0
error/__init__.py
Normal file
3
error/admin.py
Normal file
3
error/admin.py
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
# Register your models here.
|
6
error/apps.py
Normal file
6
error/apps.py
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class ErrorConfig(AppConfig):
|
||||||
|
default_auto_field = 'django.db.models.BigAutoField'
|
||||||
|
name = 'error'
|
21
error/migrations/0001_initial.py
Normal file
21
error/migrations/0001_initial.py
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
# Generated by Django 3.2.9 on 2021-12-02 20:32
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='ThomasPesquetQuotes',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('text', models.TextField()),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
0
error/migrations/__init__.py
Normal file
0
error/migrations/__init__.py
Normal file
5
error/models.py
Normal file
5
error/models.py
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
from django.db.models import Model, TextField
|
||||||
|
|
||||||
|
|
||||||
|
class ThomasPesquetQuotes(Model):
|
||||||
|
text = TextField()
|
3
error/tests.py
Normal file
3
error/tests.py
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
3
error/urls.py
Normal file
3
error/urls.py
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
from django.urls import path
|
||||||
|
|
||||||
|
from . import views
|
22
error/views.py
Normal file
22
error/views.py
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
from django.http import Http404
|
||||||
|
from django.shortcuts import render
|
||||||
|
|
||||||
|
from error.models import ThomasPesquetQuotes
|
||||||
|
|
||||||
|
|
||||||
|
def index(request, exception=None):
|
||||||
|
try:
|
||||||
|
quote = ThomasPesquetQuotes.objects.order_by("?")[0].text
|
||||||
|
except:
|
||||||
|
quote = None
|
||||||
|
|
||||||
|
response = render(request, "error.html", {
|
||||||
|
"quote": quote
|
||||||
|
})
|
||||||
|
|
||||||
|
response.status_code = 500
|
||||||
|
|
||||||
|
if isinstance(exception, Http404):
|
||||||
|
response.status_code = 404
|
||||||
|
|
||||||
|
return response
|
|
@ -1,6 +0,0 @@
|
||||||
from django.db.models import Model, CharField, TextField
|
|
||||||
|
|
||||||
|
|
||||||
class Rescue(Model):
|
|
||||||
name = CharField(max_length="256")
|
|
||||||
text = TextField()
|
|
|
@ -31,12 +31,16 @@ ALLOWED_HOSTS = ["3cab-134-214-214-199.ngrok.io", "localhost", "4125-134-214-214
|
||||||
# Application definition
|
# Application definition
|
||||||
|
|
||||||
INSTALLED_APPS = [
|
INSTALLED_APPS = [
|
||||||
|
"rescue.apps.RescueConfig",
|
||||||
|
"people.apps.PeopleConfig",
|
||||||
|
"error.apps.ErrorConfig",
|
||||||
'django.contrib.admin',
|
'django.contrib.admin',
|
||||||
'django.contrib.auth',
|
'django.contrib.auth',
|
||||||
'django.contrib.contenttypes',
|
'django.contrib.contenttypes',
|
||||||
'django.contrib.sessions',
|
'django.contrib.sessions',
|
||||||
'django.contrib.messages',
|
'django.contrib.messages',
|
||||||
'django.contrib.staticfiles',
|
'django.contrib.staticfiles',
|
||||||
|
"django_quill"
|
||||||
]
|
]
|
||||||
|
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
|
@ -76,9 +80,12 @@ WSGI_APPLICATION = 'nuitdelinfo_2021.wsgi.application'
|
||||||
|
|
||||||
DATABASES = {
|
DATABASES = {
|
||||||
'default': {
|
'default': {
|
||||||
'ENGINE': 'django.db.backends.sqlite3',
|
'ENGINE': 'django.db.backends.postgresql',
|
||||||
'NAME': BASE_DIR / 'db.sqlite3',
|
'HOST': 'localhost',
|
||||||
}
|
'USER': 'nuitdelinfo_2021',
|
||||||
|
'NAME': 'nuitdelinfo_2021',
|
||||||
|
'PASSWORD': 'nuitdelinfo_2021'
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -128,3 +135,12 @@ STATICFILES_DIRS = (path.join('static'),)
|
||||||
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field
|
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field
|
||||||
|
|
||||||
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
||||||
|
|
||||||
|
ACCOUNT_ACTIVATION_DAYS = 7
|
||||||
|
LOGIN_REDIRECT_URL = '/'
|
||||||
|
|
||||||
|
EMAIL_USE_TLS = True
|
||||||
|
EMAIL_HOST = 'smtp.gmail.com'
|
||||||
|
EMAIL_PORT = 587
|
||||||
|
EMAIL_HOST_USER = 'me@gmail.com'
|
||||||
|
EMAIL_HOST_PASSWORD = 'password'
|
|
@ -14,11 +14,19 @@ Including another URLconf
|
||||||
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
||||||
"""
|
"""
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.urls import path
|
from django.urls import path, include
|
||||||
|
|
||||||
from nuitdelinfo_2021 import views
|
from nuitdelinfo_2021 import views
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('', views.index, name="index"),
|
path('', views.index, name="index"),
|
||||||
|
path("a/", include("rescue.urls")),
|
||||||
|
path("p/", include("people.urls")),
|
||||||
path('admin/', admin.site.urls),
|
path('admin/', admin.site.urls),
|
||||||
|
path('accounts/', include('django_registration.backends.activation.urls')),
|
||||||
|
path('accounts/', include('django.contrib.auth.urls'))
|
||||||
]
|
]
|
||||||
|
|
||||||
|
handler400 = "error.views.index"
|
||||||
|
handler404 = "error.views.index"
|
||||||
|
handler500 = "error.views.index"
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
from .index import index
|
|
0
people/__init__.py
Normal file
0
people/__init__.py
Normal file
3
people/admin.py
Normal file
3
people/admin.py
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
# Register your models here.
|
6
people/apps.py
Normal file
6
people/apps.py
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class PeopleConfig(AppConfig):
|
||||||
|
default_auto_field = 'django.db.models.BigAutoField'
|
||||||
|
name = 'people'
|
18
people/forms.py
Normal file
18
people/forms.py
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
from django.forms import ModelForm, DateInput
|
||||||
|
|
||||||
|
from people.models import People
|
||||||
|
|
||||||
|
|
||||||
|
class DateInput(DateInput):
|
||||||
|
input_type = "date"
|
||||||
|
|
||||||
|
|
||||||
|
class SubmitPeople(ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = People
|
||||||
|
fields = ["first_name", "last_name", "title", "description", "birth", "death", "history", "genealogy", "awards",
|
||||||
|
"pro_life", "testimonials", "sources"]
|
||||||
|
widgets = {
|
||||||
|
"birth": DateInput(),
|
||||||
|
"death": DateInput()
|
||||||
|
}
|
32
people/migrations/0001_initial.py
Normal file
32
people/migrations/0001_initial.py
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
# Generated by Django 3.2.9 on 2021-12-02 20:32
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='People',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('first_name', models.CharField(max_length=40)),
|
||||||
|
('last_name', models.CharField(max_length=60)),
|
||||||
|
('title', models.CharField(max_length=70)),
|
||||||
|
('description', models.TextField()),
|
||||||
|
('birth', models.DateField()),
|
||||||
|
('death', models.DateField()),
|
||||||
|
('history', models.TextField()),
|
||||||
|
('genealogy', models.TextField()),
|
||||||
|
('awards', models.TextField()),
|
||||||
|
('pro_life', models.TextField()),
|
||||||
|
('testimonials', models.TextField()),
|
||||||
|
('sources', models.TextField()),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
59
people/migrations/0002_auto_20211202_2127.py
Normal file
59
people/migrations/0002_auto_20211202_2127.py
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
# Generated by Django 3.2.9 on 2021-12-02 21:27
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django_quill.fields
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('people', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='people',
|
||||||
|
name='awards',
|
||||||
|
field=django_quill.fields.QuillField(null=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='people',
|
||||||
|
name='death',
|
||||||
|
field=models.DateField(null=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='people',
|
||||||
|
name='description',
|
||||||
|
field=django_quill.fields.QuillField(),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='people',
|
||||||
|
name='genealogy',
|
||||||
|
field=django_quill.fields.QuillField(null=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='people',
|
||||||
|
name='history',
|
||||||
|
field=django_quill.fields.QuillField(null=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='people',
|
||||||
|
name='pro_life',
|
||||||
|
field=django_quill.fields.QuillField(null=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='people',
|
||||||
|
name='sources',
|
||||||
|
field=django_quill.fields.QuillField(),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='people',
|
||||||
|
name='testimonials',
|
||||||
|
field=django_quill.fields.QuillField(null=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='people',
|
||||||
|
name='title',
|
||||||
|
field=models.CharField(max_length=70, null=True),
|
||||||
|
),
|
||||||
|
]
|
60
people/migrations/0003_auto_20211202_2225.py
Normal file
60
people/migrations/0003_auto_20211202_2225.py
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
# Generated by Django 3.2.9 on 2021-12-02 22:25
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
import django_quill.fields
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('people', '0002_auto_20211202_2127'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='people',
|
||||||
|
name='pending_edit_of',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='people.people'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='people',
|
||||||
|
name='validated',
|
||||||
|
field=models.BooleanField(default=False),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='people',
|
||||||
|
name='awards',
|
||||||
|
field=django_quill.fields.QuillField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='people',
|
||||||
|
name='death',
|
||||||
|
field=models.DateField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='people',
|
||||||
|
name='genealogy',
|
||||||
|
field=django_quill.fields.QuillField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='people',
|
||||||
|
name='history',
|
||||||
|
field=django_quill.fields.QuillField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='people',
|
||||||
|
name='pro_life',
|
||||||
|
field=django_quill.fields.QuillField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='people',
|
||||||
|
name='testimonials',
|
||||||
|
field=django_quill.fields.QuillField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='people',
|
||||||
|
name='title',
|
||||||
|
field=models.CharField(blank=True, max_length=70, null=True),
|
||||||
|
),
|
||||||
|
]
|
0
people/migrations/__init__.py
Normal file
0
people/migrations/__init__.py
Normal file
27
people/models.py
Normal file
27
people/models.py
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
from django.db.models import Model, CharField, DateField, BooleanField, ForeignKey, CASCADE
|
||||||
|
from django_quill.fields import QuillField
|
||||||
|
|
||||||
|
|
||||||
|
class People(Model):
|
||||||
|
first_name = CharField(max_length=40)
|
||||||
|
last_name = CharField(max_length=60)
|
||||||
|
|
||||||
|
title = CharField(max_length=70, null=True, blank=True)
|
||||||
|
description = QuillField()
|
||||||
|
|
||||||
|
birth = DateField()
|
||||||
|
death = DateField(null=True, blank=True)
|
||||||
|
|
||||||
|
history = QuillField(null=True, blank=True)
|
||||||
|
genealogy = QuillField(null=True, blank=True)
|
||||||
|
awards = QuillField(null=True, blank=True)
|
||||||
|
pro_life = QuillField(null=True, blank=True)
|
||||||
|
|
||||||
|
testimonials = QuillField(null=True, blank=True)
|
||||||
|
sources = QuillField()
|
||||||
|
|
||||||
|
validated = BooleanField(default=False)
|
||||||
|
pending_edit_of = ForeignKey("self", on_delete=CASCADE, null=True, blank=True)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.first_name} {self.last_name}"
|
3
people/tests.py
Normal file
3
people/tests.py
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
9
people/urls.py
Normal file
9
people/urls.py
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
from django.urls import path
|
||||||
|
|
||||||
|
from . import views
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
path("<int:people_id>/", views.index, name='index'),
|
||||||
|
path("submit/", views.submit, name="submit"),
|
||||||
|
path("edit/<int:people_id>/", views.edit, name="edit")
|
||||||
|
]
|
54
people/views.py
Normal file
54
people/views.py
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
from django.contrib.auth.decorators import login_required
|
||||||
|
from django.http import Http404, HttpResponseRedirect, HttpResponseBadRequest
|
||||||
|
from django.shortcuts import render
|
||||||
|
from django.urls import reverse
|
||||||
|
|
||||||
|
from people.forms import SubmitPeople
|
||||||
|
from people.models import People
|
||||||
|
|
||||||
|
|
||||||
|
def get_people(people_id: int) -> People:
|
||||||
|
try:
|
||||||
|
return People.objects.get(pk=people_id)
|
||||||
|
except People.DoesNotExist:
|
||||||
|
raise Http404("People does not exist")
|
||||||
|
|
||||||
|
|
||||||
|
def index(request, people_id: int):
|
||||||
|
return render(request, "people/people.html", {
|
||||||
|
"people": get_people(people_id)
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def submit(request):
|
||||||
|
if request.method == "POST":
|
||||||
|
form = SubmitPeople(request.POST)
|
||||||
|
if form.is_valid():
|
||||||
|
people = form.save()
|
||||||
|
return HttpResponseRedirect(reverse(index, args=[people.pk]))
|
||||||
|
else:
|
||||||
|
form = SubmitPeople()
|
||||||
|
|
||||||
|
return render(request, "people/submit.html", {"form": form})
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def edit(request, people_id: int):
|
||||||
|
edited_people = get_people(people_id)
|
||||||
|
if not edited_people.validated:
|
||||||
|
return HttpResponseBadRequest("This entry is not validated, you can't edit it")
|
||||||
|
|
||||||
|
if request.method == "POST":
|
||||||
|
form = SubmitPeople(request.POST)
|
||||||
|
if form.is_valid():
|
||||||
|
people = form.save()
|
||||||
|
people.pending_edit_of = edited_people
|
||||||
|
people.save()
|
||||||
|
|
||||||
|
return HttpResponseRedirect(reverse(index, args=[people.pk]))
|
||||||
|
else:
|
||||||
|
edited_people.pk = None
|
||||||
|
form = SubmitPeople(instance=edited_people)
|
||||||
|
|
||||||
|
return render(request, "people/edit.html", {"form": form, "edit_id": people_id})
|
8
requirements.txt
Normal file
8
requirements.txt
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
asgiref==3.4.1
|
||||||
|
confusable-homoglyphs==3.2.0
|
||||||
|
Django==3.2.9
|
||||||
|
django-quill-editor==0.1.22
|
||||||
|
django-registration==3.2
|
||||||
|
psycopg2==2.9.2
|
||||||
|
pytz==2021.3
|
||||||
|
sqlparse==0.4.2
|
0
rescue/__init__.py
Normal file
0
rescue/__init__.py
Normal file
3
rescue/admin.py
Normal file
3
rescue/admin.py
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
# Register your models here.
|
6
rescue/apps.py
Normal file
6
rescue/apps.py
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class RescueConfig(AppConfig):
|
||||||
|
default_auto_field = 'django.db.models.BigAutoField'
|
||||||
|
name = 'rescue'
|
17
rescue/forms.py
Normal file
17
rescue/forms.py
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
from django.forms import ModelForm, DateInput
|
||||||
|
|
||||||
|
from rescue.models import Rescue
|
||||||
|
|
||||||
|
|
||||||
|
class DateInput(DateInput):
|
||||||
|
input_type = "date"
|
||||||
|
|
||||||
|
|
||||||
|
class SubmitRescue(ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = Rescue
|
||||||
|
fields = ["name", "date", "location_long", "location_lat", "resume", "saved", "rescuers", "description",
|
||||||
|
"sources"]
|
||||||
|
widgets = {
|
||||||
|
"date": DateInput()
|
||||||
|
}
|
30
rescue/migrations/0001_initial.py
Normal file
30
rescue/migrations/0001_initial.py
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
# Generated by Django 3.2.9 on 2021-12-02 20:32
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('people', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Rescue',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=70)),
|
||||||
|
('date', models.DateField()),
|
||||||
|
('location_long', models.DecimalField(decimal_places=6, max_digits=9)),
|
||||||
|
('location_lat', models.DecimalField(decimal_places=6, max_digits=9)),
|
||||||
|
('resume', models.CharField(max_length=125)),
|
||||||
|
('description', models.TextField()),
|
||||||
|
('sources', models.TextField()),
|
||||||
|
('rescuers', models.ManyToManyField(related_name='rescued', to='people.People')),
|
||||||
|
('saved', models.ManyToManyField(related_name='saved', to='people.People')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
24
rescue/migrations/0002_auto_20211202_2301.py
Normal file
24
rescue/migrations/0002_auto_20211202_2301.py
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
# Generated by Django 3.2.9 on 2021-12-02 23:01
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
import django_quill.fields
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('rescue', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='rescue',
|
||||||
|
name='description',
|
||||||
|
field=django_quill.fields.QuillField(),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='rescue',
|
||||||
|
name='sources',
|
||||||
|
field=django_quill.fields.QuillField(),
|
||||||
|
),
|
||||||
|
]
|
0
rescue/migrations/__init__.py
Normal file
0
rescue/migrations/__init__.py
Normal file
21
rescue/models.py
Normal file
21
rescue/models.py
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
from django.db.models import Model, CharField, DateField, ManyToManyField, DecimalField
|
||||||
|
from django_quill.fields import QuillField
|
||||||
|
|
||||||
|
from people.models import People
|
||||||
|
|
||||||
|
|
||||||
|
class Rescue(Model):
|
||||||
|
name = CharField(max_length=70)
|
||||||
|
date = DateField()
|
||||||
|
|
||||||
|
location_long = DecimalField(max_digits=9, decimal_places=6)
|
||||||
|
location_lat = DecimalField(max_digits=9, decimal_places=6)
|
||||||
|
|
||||||
|
resume = CharField(max_length=125)
|
||||||
|
|
||||||
|
saved = ManyToManyField(People, related_name="saved")
|
||||||
|
rescuers = ManyToManyField(People, related_name="rescued")
|
||||||
|
|
||||||
|
description = QuillField()
|
||||||
|
|
||||||
|
sources = QuillField()
|
3
rescue/tests.py
Normal file
3
rescue/tests.py
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
9
rescue/urls.py
Normal file
9
rescue/urls.py
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
from django.urls import path
|
||||||
|
|
||||||
|
from . import views
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
path('<int:rescue_id>', views.index, name='index'),
|
||||||
|
path("submit/", views.submit, name="submit"),
|
||||||
|
path("edit/<int:rescue_id>/", views.edit, name="edit")
|
||||||
|
]
|
52
rescue/views.py
Normal file
52
rescue/views.py
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
from django.contrib.auth.decorators import login_required
|
||||||
|
from django.http import Http404, HttpResponseRedirect, HttpResponseBadRequest
|
||||||
|
from django.shortcuts import render
|
||||||
|
from django.urls import reverse
|
||||||
|
|
||||||
|
from rescue.forms import SubmitRescue
|
||||||
|
from rescue.models import Rescue
|
||||||
|
|
||||||
|
|
||||||
|
def get_rescue(rescue_id: int) -> Rescue:
|
||||||
|
try:
|
||||||
|
return Rescue.objects.get(pk=rescue_id)
|
||||||
|
except Rescue.DoesNotExist:
|
||||||
|
raise Http404("Rescue does not exist")
|
||||||
|
|
||||||
|
|
||||||
|
def index(request, rescue_id: int):
|
||||||
|
return render(request, "article/article.html", {"rescue": get_rescue(rescue_id)})
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def submit(request):
|
||||||
|
if request.method == "POST":
|
||||||
|
form = SubmitRescue(request.POST)
|
||||||
|
if form.is_valid():
|
||||||
|
rescue = form.save()
|
||||||
|
return HttpResponseRedirect(reverse(index, args=[rescue.pk]))
|
||||||
|
else:
|
||||||
|
form = SubmitRescue()
|
||||||
|
|
||||||
|
return render(request, "article/submit.html", {"form": form})
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def edit(request, rescue_id: int):
|
||||||
|
edited_rescue = get_rescue(rescue_id)
|
||||||
|
if not edited_rescue.validated:
|
||||||
|
return HttpResponseBadRequest("This entry is not validated, you can't edit it")
|
||||||
|
|
||||||
|
if request.method == "POST":
|
||||||
|
form = SubmitRescue(request.POST)
|
||||||
|
if form.is_valid():
|
||||||
|
rescue = form.save()
|
||||||
|
rescue.pending_edit_of = edited_rescue
|
||||||
|
rescue.save()
|
||||||
|
|
||||||
|
return HttpResponseRedirect(reverse(index, args=[rescue.pk]))
|
||||||
|
else:
|
||||||
|
edited_rescue.pk = None
|
||||||
|
form = SubmitRescue(instance=edited_rescue)
|
||||||
|
|
||||||
|
return render(request, "article/edit.html", {"form": form, "edit_id": edited_rescue})
|
28
templates/article/article.html
Normal file
28
templates/article/article.html
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
{% if not rescue.validated %}
|
||||||
|
{% if rescue.pending_edit_of %}
|
||||||
|
<h1>This edit is not validated !</h1>
|
||||||
|
{% else %}
|
||||||
|
<h1>This new entry is not validated !</h1>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{{ rescue.name }} <br />
|
||||||
|
{{ rescue.date }} <br />
|
||||||
|
<br />
|
||||||
|
{{ rescue.location_long }} {{ rescue.location_lat }} <br />
|
||||||
|
<br />
|
||||||
|
{{ rescue.resume.html | safe }} <br />
|
||||||
|
{{ rescue.description.html | safe }} <br />
|
||||||
|
<br />
|
||||||
|
{{ rescue.testimonials.html | safe }} <br />
|
||||||
|
{{ rescue.sources.html | safe }}
|
||||||
|
|
||||||
|
<h3>Saved</h3>
|
||||||
|
{% for people in rescue.saved.all %}
|
||||||
|
<a href="/p/{{ people.pk }}">{{ people }}</a>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
<h3>Rescuers</h3>
|
||||||
|
{% for people in rescue.rescuers.all %}
|
||||||
|
<a href="/p/{{ people.pk }}">{{ people }}</a>
|
||||||
|
{% endfor %}
|
10
templates/article/edit.html
Normal file
10
templates/article/edit.html
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<head>
|
||||||
|
{{ form.media }}
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<form action="/a/edit/{{ edit_id }}/" method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ form }}
|
||||||
|
<input type="submit" value="Submit">
|
||||||
|
</form>
|
||||||
|
</body>
|
10
templates/article/submit.html
Normal file
10
templates/article/submit.html
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<head>
|
||||||
|
{{ form.media }}
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<form action="/a/submit/" method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ form }}
|
||||||
|
<input type="submit" value="Submit">
|
||||||
|
</form>
|
||||||
|
</body>
|
0
templates/crew.html
Normal file
0
templates/crew.html
Normal file
1
templates/django_registration/activation_complete.html
Normal file
1
templates/django_registration/activation_complete.html
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Activation complete :/
|
2
templates/django_registration/activation_email_body.txt
Normal file
2
templates/django_registration/activation_email_body.txt
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
activation URL: {{site}}/accounts/activate/{{ activation_key }}/
|
||||||
|
The number of days remaining during which the account may be activated: {{ expiration_days }}
|
|
@ -0,0 +1 @@
|
||||||
|
Activation email for {{ user }}
|
1
templates/django_registration/activation_failed.html
Normal file
1
templates/django_registration/activation_failed.html
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Activation failed :/
|
1
templates/django_registration/registration_closed.html
Normal file
1
templates/django_registration/registration_closed.html
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Registration closed :/
|
1
templates/django_registration/registration_complete.html
Normal file
1
templates/django_registration/registration_complete.html
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Registration complete !
|
5
templates/django_registration/registration_form.html
Normal file
5
templates/django_registration/registration_form.html
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<form method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ form }}
|
||||||
|
<input type="submit" value="login" />
|
||||||
|
</form>
|
6
templates/error.html
Normal file
6
templates/error.html
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<h1>Oups, une erreur est survenue :/</h1>
|
||||||
|
|
||||||
|
{% if quote %}
|
||||||
|
<h2>Pour nous faire pardonner voici une citation de Thomas Pesquet:</h2>
|
||||||
|
<p>{{ quote }}</p>
|
||||||
|
{% endif %}
|
10
templates/people/edit.html
Normal file
10
templates/people/edit.html
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<head>
|
||||||
|
{{ form.media }}
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<form action="/p/edit/{{ edit_id }}/" method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ form }}
|
||||||
|
<input type="submit" value="Submit">
|
||||||
|
</form>
|
||||||
|
</body>
|
23
templates/people/people.html
Normal file
23
templates/people/people.html
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
{% if not people.validated %}
|
||||||
|
{% if people.pending_edit_of %}
|
||||||
|
<h1>This edit is not validated !</h1>
|
||||||
|
{% else %}
|
||||||
|
<h1>This new entry is not validated !</h1>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{{ people.first_name }} {{ people.last_name }} <br />
|
||||||
|
{{ people.title }} <br />
|
||||||
|
<br />
|
||||||
|
{{ people.description.html | safe }} <br />
|
||||||
|
<br />
|
||||||
|
{{ people.birth }} <br />
|
||||||
|
{{ people.death }} <br />
|
||||||
|
<br />
|
||||||
|
{{ people.history.html | safe }} <br />
|
||||||
|
{{ people.genealogy.html | safe }} <br />
|
||||||
|
{{ people.awards.html | safe }} <br />
|
||||||
|
{{ people.pro_life.html | safe }} <br />
|
||||||
|
<br />
|
||||||
|
{{ people.testimonials.html | safe }} <br />
|
||||||
|
{{ people.sources.html | safe }}
|
10
templates/people/submit.html
Normal file
10
templates/people/submit.html
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<head>
|
||||||
|
{{ form.media }}
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<form action="/p/submit/" method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ form }}
|
||||||
|
<input type="submit" value="Submit">
|
||||||
|
</form>
|
||||||
|
</body>
|
4
templates/registration/logged_out.html
Normal file
4
templates/registration/logged_out.html
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
{% block content %}
|
||||||
|
<p>Logged out!</p>
|
||||||
|
<a href="{% url 'login'%}">Click here to login again.</a>
|
||||||
|
{% endblock %}
|
37
templates/registration/login.html
Normal file
37
templates/registration/login.html
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
{% if form.errors %}
|
||||||
|
<p>Your username and password didn't match. Please try again.</p>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if next %}
|
||||||
|
{% if user.is_authenticated %}
|
||||||
|
<p>Your account doesn't have access to this page. To proceed,
|
||||||
|
please login with an account that has access.</p>
|
||||||
|
{% else %}
|
||||||
|
<p>Please login to see this page.</p>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<form method="post" action="{% url 'login' %}">
|
||||||
|
{% csrf_token %}
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td>{{ form.username.label_tag }}</td>
|
||||||
|
<td>{{ form.username }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>{{ form.password.label_tag }}</td>
|
||||||
|
<td>{{ form.password }}</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<input type="submit" value="login" />
|
||||||
|
<input type="hidden" name="next" value="{{ next }}" />
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{# Assumes you setup the password_reset view in your URLconf #}
|
||||||
|
<p><a href="{% url 'password_reset' %}">Lost password?</a></p>
|
||||||
|
|
||||||
|
<p><a href="{% url 'django_registration_register' %}">Register</a></p>
|
||||||
|
|
||||||
|
{% endblock %}
|
4
templates/registration/password_reset_complete.html
Normal file
4
templates/registration/password_reset_complete.html
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
{% block content %}
|
||||||
|
<h1>The password has been changed!</h1>
|
||||||
|
<p><a href="{% url 'login' %}">log in again?</a></p>
|
||||||
|
{% endblock %}
|
27
templates/registration/password_reset_confirm.html
Normal file
27
templates/registration/password_reset_confirm.html
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{% block content %}
|
||||||
|
{% if validlink %}
|
||||||
|
<p>Please enter (and confirm) your new password.</p>
|
||||||
|
<form action="" method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td>{{ form.new_password1.errors }}
|
||||||
|
<label for="id_new_password1">New password:</label></td>
|
||||||
|
<td>{{ form.new_password1 }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>{{ form.new_password2.errors }}
|
||||||
|
<label for="id_new_password2">Confirm password:</label></td>
|
||||||
|
<td>{{ form.new_password2 }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td></td>
|
||||||
|
<td><input type="submit" value="Change my password" /></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</form>
|
||||||
|
{% else %}
|
||||||
|
<h1>Password reset failed</h1>
|
||||||
|
<p>The password reset link was invalid, possibly because it has already been used. Please request a new password reset.</p>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
3
templates/registration/password_reset_done.html
Normal file
3
templates/registration/password_reset_done.html
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{% block content %}
|
||||||
|
<p>We've emailed you instructions for setting your password. If they haven't arrived in a few minutes, check your spam folder.</p>
|
||||||
|
{% endblock %}
|
2
templates/registration/password_reset_email.html
Normal file
2
templates/registration/password_reset_email.html
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
Someone asked for password reset for email {{ email }}. Follow the link below:
|
||||||
|
{{ protocol}}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %}
|
10
templates/registration/password_reset_form.html
Normal file
10
templates/registration/password_reset_form.html
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
{% block content %}
|
||||||
|
<form action="" method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
{% if form.email.errors %}
|
||||||
|
{{ form.email.errors }}
|
||||||
|
{% endif %}
|
||||||
|
<p>{{ form.email }}</p>
|
||||||
|
<input type="submit" class="btn btn-default btn-lg" value="Reset password">
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
Loading…
Reference in a new issue