Compare commits
14 Commits
7e978dd657
...
595e0a47b9
Author | SHA1 | Date |
---|---|---|
Luca | 595e0a47b9 | |
Luca | 36d75dc50d | |
Luca | 71fc7ed07e | |
Luca | 468f68c2cb | |
Luca | 3e75b76ac9 | |
Luca | adbb5685a0 | |
Luca | 818e478353 | |
Luca | 0dd2c8f31a | |
Luca | 59644b7b4b | |
Luca | 54296ebcf7 | |
Luca | cfbc4ef61c | |
Luca | fdc74bbf9e | |
Luca | 5ac11e16e8 | |
Luca | c3f2c0bcfa |
|
@ -1,10 +1,15 @@
|
||||||
**/__pycache__
|
**/__pycache__
|
||||||
|
*.bkp
|
||||||
.dockerignore
|
.dockerignore
|
||||||
|
.drone.yml
|
||||||
|
.editorconfig
|
||||||
.git*
|
.git*
|
||||||
|
.idea
|
||||||
Dockerfile
|
Dockerfile
|
||||||
Dockerfile-dev
|
Dockerfile-dev
|
||||||
README.md
|
README.md
|
||||||
db.sqlite3
|
db.sqlite3
|
||||||
docker-compose.yml
|
docker-compose.yml
|
||||||
env
|
env
|
||||||
|
setup.cfg
|
||||||
storage
|
storage
|
||||||
|
|
16
.drone.yml
16
.drone.yml
|
@ -4,10 +4,15 @@ kind: pipeline
|
||||||
type: docker
|
type: docker
|
||||||
name: default
|
name: default
|
||||||
|
|
||||||
clone:
|
|
||||||
disable: yes
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
- name: check style
|
||||||
|
image: python:3.12-alpine
|
||||||
|
commands:
|
||||||
|
- apk add --no-cache git # required by isort to skip files in .gitignore
|
||||||
|
- pip install black isort
|
||||||
|
- black --check .
|
||||||
|
- isort -c .
|
||||||
|
|
||||||
- name: deploy staging
|
- name: deploy staging
|
||||||
image: ghcr.io/appleboy/drone-ssh
|
image: ghcr.io/appleboy/drone-ssh
|
||||||
environment:
|
environment:
|
||||||
|
@ -26,6 +31,8 @@ steps:
|
||||||
when:
|
when:
|
||||||
branch:
|
branch:
|
||||||
- main
|
- main
|
||||||
|
event:
|
||||||
|
- push
|
||||||
|
|
||||||
- name: deploy production
|
- name: deploy production
|
||||||
image: ghcr.io/appleboy/drone-ssh
|
image: ghcr.io/appleboy/drone-ssh
|
||||||
|
@ -35,7 +42,10 @@ steps:
|
||||||
when:
|
when:
|
||||||
branch:
|
branch:
|
||||||
- live
|
- live
|
||||||
|
event:
|
||||||
|
- push
|
||||||
|
|
||||||
trigger:
|
trigger:
|
||||||
event:
|
event:
|
||||||
|
- pull_request
|
||||||
- push
|
- push
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*.html]
|
||||||
|
indent_size = 4
|
||||||
|
indent_style = space
|
|
@ -158,3 +158,6 @@ cython_debug/
|
||||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||||
#.idea/
|
#.idea/
|
||||||
|
|
||||||
|
# E.g. copies of old dev database
|
||||||
|
*.bkp
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
FROM python:3.10-alpine3.17
|
FROM python:3.12-alpine3.19
|
||||||
|
|
||||||
RUN apk add --no-cache git
|
|
||||||
|
|
||||||
RUN adduser -h /opt/shiftregister -D shiftregister
|
RUN adduser -h /opt/shiftregister -D shiftregister
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
FROM python:3.10-alpine3.17
|
FROM python:3.12-alpine3.19
|
||||||
|
|
||||||
RUN apk add --no-cache git
|
|
||||||
|
|
||||||
RUN adduser -h /home/shiftregister -D shiftregister
|
RUN adduser -h /home/shiftregister -D shiftregister
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# shiftregister
|
# shiftregister
|
||||||
|
|
||||||
![kontakt logo with its left half rotated 180 degrees, resembling the left shift operator](assets/tonkakt.svg)
|
![kontakt logo with its left half rotated 180 degrees, resembling the left shift operator](shiftregister/core/static/tonkakt.svg)
|
||||||
|
|
||||||
## [CI Mirror](https://git.luj0ga.de/kontakt/shiftregister) / [Drone CI](https://ci.luj0ga.de/kontakt/shiftregister)
|
## [CI Mirror](https://git.luj0ga.de/kontakt/shiftregister) / [Drone CI](https://ci.luj0ga.de/kontakt/shiftregister)
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
amqp==5.1.1
|
amqp==5.1.1
|
||||||
asgiref==3.5.0
|
asgiref==3.8.1
|
||||||
async-timeout==4.0.2
|
async-timeout==4.0.2
|
||||||
beautifulsoup4==4.12.2
|
beautifulsoup4==4.12.3
|
||||||
billiard==3.6.4.0
|
billiard==4.2.0
|
||||||
celery==5.2.6
|
celery==5.4.0
|
||||||
certifi==2021.10.8
|
certifi==2021.10.8
|
||||||
charset-normalizer==2.0.12
|
charset-normalizer==2.0.12
|
||||||
click==8.1.2
|
click==8.1.2
|
||||||
|
@ -11,31 +11,31 @@ click-didyoumean==0.3.0
|
||||||
click-plugins==1.1.1
|
click-plugins==1.1.1
|
||||||
click-repl==0.2.0
|
click-repl==0.2.0
|
||||||
Deprecated==1.2.13
|
Deprecated==1.2.13
|
||||||
Django==4.0.4
|
Django==5.0.4
|
||||||
django-dynamic-preferences==1.15.0
|
django-dynamic-preferences==1.16.0
|
||||||
django-phonenumber-field==6.1.0
|
django-phonenumber-field==7.3.0
|
||||||
icalendar==4.0.9
|
icalendar==5.0.12
|
||||||
idna==3.3
|
idna==3.3
|
||||||
kombu==5.2.4
|
kombu==5.3.7
|
||||||
librabbitmq==2.0.0
|
|
||||||
packaging==21.3
|
packaging==21.3
|
||||||
persisting-theory==1.0
|
persisting-theory==1.0
|
||||||
phonenumbers==8.12.47
|
phonenumbers==8.12.47
|
||||||
prompt-toolkit==3.0.29
|
prompt-toolkit==3.0.29
|
||||||
psycopg2-binary==2.9.3
|
psycopg2-binary==2.9.9
|
||||||
pyparsing==3.0.8
|
pyparsing==3.0.8
|
||||||
pypng==0.20220715.0
|
pypng==0.20220715.0
|
||||||
python-dateutil==2.8.2
|
python-dateutil==2.8.2
|
||||||
pytz==2022.1
|
pytz==2022.1
|
||||||
qrcode==7.4.2
|
qrcode==7.4.2
|
||||||
redis==4.2.2
|
redis==5.0.4
|
||||||
requests==2.27.1
|
requests==2.31.0
|
||||||
sentry-sdk==1.5.10
|
sentry-sdk==2.0.1
|
||||||
six==1.16.0
|
six==1.16.0
|
||||||
soupsieve==2.4.1
|
soupsieve==2.4.1
|
||||||
sqlparse==0.4.2
|
sqlparse==0.4.2
|
||||||
typing_extensions==4.5.0
|
typing_extensions==4.11.0
|
||||||
urllib3==1.26.9
|
tzdata==2024.1
|
||||||
vine==5.0.0
|
urllib3==2.2.1
|
||||||
|
vine==5.1.0
|
||||||
wcwidth==0.2.5
|
wcwidth==0.2.5
|
||||||
wrapt==1.14.0
|
wrapt==1.14.0
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
[isort]
|
||||||
|
line_length=88
|
||||||
|
profile=black
|
||||||
|
skip_gitignore=True
|
|
@ -1,7 +1,7 @@
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.contrib.admin import DateFieldListFilter
|
from django.contrib.admin import DateFieldListFilter
|
||||||
|
|
||||||
from .models import Room, Shift, Helper, ShiftRegistration, Message, LoginToken
|
from .models import Helper, LoginToken, Message, Room, Shift, ShiftRegistration
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Room)
|
@admin.register(Room)
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
from .models import LoginToken
|
from .models import LoginToken
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
from dynamic_preferences.registries import global_preferences_registry
|
|
||||||
from dynamic_preferences import types
|
|
||||||
import phonenumbers
|
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
|
import phonenumbers
|
||||||
|
from dynamic_preferences import types
|
||||||
|
from dynamic_preferences.registries import global_preferences_registry
|
||||||
|
|
||||||
helper = types.Section("helper")
|
helper = types.Section("helper")
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
from django import forms
|
from django import forms
|
||||||
from .models import Helper
|
|
||||||
from phonenumber_field.formfields import PhoneNumberField
|
|
||||||
from phonenumber_field.validators import validate_international_phonenumber
|
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from dynamic_preferences.registries import global_preferences_registry
|
from dynamic_preferences.registries import global_preferences_registry
|
||||||
|
from phonenumber_field.formfields import PhoneNumberField
|
||||||
|
from phonenumber_field.validators import validate_international_phonenumber
|
||||||
|
|
||||||
|
from .models import Helper
|
||||||
|
|
||||||
global_preferences = global_preferences_registry.manager()
|
global_preferences = global_preferences_registry.manager()
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
# Generated by Django 4.0.4 on 2022-04-27 14:11
|
# Generated by Django 4.0.4 on 2022-04-27 14:11
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
import phonenumber_field.modelfields
|
import phonenumber_field.modelfields
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
import shiftregister.app.models
|
import shiftregister.app.models
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
from django.db import models
|
|
||||||
import secrets
|
import secrets
|
||||||
from django.shortcuts import reverse
|
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from django.utils import timezone
|
|
||||||
from django.db.models import F, Count, Q, ExpressionWrapper, Case, When
|
from django.db import models
|
||||||
|
from django.db.models import Case, Count, ExpressionWrapper, F, Q, When
|
||||||
|
from django.shortcuts import reverse
|
||||||
from django.template import Context, Template
|
from django.template import Context, Template
|
||||||
from phonenumber_field.modelfields import PhoneNumberField
|
from django.utils import timezone
|
||||||
from dynamic_preferences.registries import global_preferences_registry
|
from dynamic_preferences.registries import global_preferences_registry
|
||||||
|
from phonenumber_field.modelfields import PhoneNumberField
|
||||||
|
|
||||||
global_preferences = global_preferences_registry.manager()
|
global_preferences = global_preferences_registry.manager()
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,9 @@ from django.db.models.signals import pre_save
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
from django.shortcuts import reverse
|
from django.shortcuts import reverse
|
||||||
from django.template import Context, Template
|
from django.template import Context, Template
|
||||||
|
|
||||||
from shiftregister.core.signals import populate_nav
|
from shiftregister.core.signals import populate_nav
|
||||||
|
|
||||||
from .models import Message, Shift
|
from .models import Message, Shift
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from datetime import timezone
|
from datetime import timezone
|
||||||
from django.conf import settings
|
|
||||||
import requests
|
|
||||||
|
|
||||||
|
import requests
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
BASE_URL = "https://api.sipgate.com/v2"
|
BASE_URL = "https://api.sipgate.com/v2"
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
|
import requests
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from phonenumber_field.phonenumber import PhoneNumber
|
from phonenumber_field.phonenumber import PhoneNumber
|
||||||
import requests
|
|
||||||
|
|
||||||
|
|
||||||
BASE_URL = "https://api.sipgate.com/v2"
|
BASE_URL = "https://api.sipgate.com/v2"
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
|
import sentry_sdk
|
||||||
from celery import shared_task
|
from celery import shared_task
|
||||||
from .models import Message, ShiftRegistration
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from dynamic_preferences.registries import global_preferences_registry
|
from dynamic_preferences.registries import global_preferences_registry
|
||||||
|
|
||||||
|
from .models import Message, ShiftRegistration
|
||||||
from .sipgate.sms import send as send_sms
|
from .sipgate.sms import send as send_sms
|
||||||
import sentry_sdk
|
|
||||||
|
|
||||||
global_preferences = global_preferences_registry.manager()
|
global_preferences = global_preferences_registry.manager()
|
||||||
|
|
||||||
|
|
|
@ -1,18 +1,20 @@
|
||||||
from django.shortcuts import render, redirect, get_object_or_404
|
import datetime
|
||||||
from .models import Shift, LoginToken, Helper, ShiftRegistration
|
import math
|
||||||
from django.db import transaction
|
|
||||||
from django.db.models import F, Count, Q, ExpressionWrapper
|
|
||||||
from django.core.cache import cache
|
|
||||||
from .forms import RegisterForm, EmptyForm, AstaForm
|
|
||||||
from django.db.models.fields import DateTimeField
|
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from django.utils import timezone
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
import datetime
|
from django.core.cache import cache
|
||||||
from .decorators import event_state
|
from django.db import transaction
|
||||||
|
from django.db.models import Count, ExpressionWrapper, F, Q
|
||||||
|
from django.db.models.fields import DateTimeField
|
||||||
|
from django.shortcuts import get_object_or_404, redirect, render
|
||||||
|
from django.utils import timezone
|
||||||
from dynamic_preferences.registries import global_preferences_registry
|
from dynamic_preferences.registries import global_preferences_registry
|
||||||
import math
|
|
||||||
|
from .decorators import event_state
|
||||||
|
from .forms import AstaForm, EmptyForm, RegisterForm
|
||||||
|
from .models import Helper, LoginToken, Shift, ShiftRegistration
|
||||||
|
|
||||||
global_preferences = global_preferences_registry.manager()
|
global_preferences = global_preferences_registry.manager()
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from .signals import populate_nav
|
from .signals import populate_footer_nav, populate_nav
|
||||||
|
|
||||||
|
|
||||||
def nav(request):
|
def nav(request):
|
||||||
|
@ -9,6 +9,15 @@ def nav(request):
|
||||||
for item in items
|
for item in items
|
||||||
]
|
]
|
||||||
|
|
||||||
return {
|
return {"nav_items": nav_items}
|
||||||
"nav_items": nav_items,
|
|
||||||
}
|
|
||||||
|
def footer_nav(request):
|
||||||
|
nav_items = [
|
||||||
|
item
|
||||||
|
for _, items in populate_footer_nav.send(sender=request)
|
||||||
|
if isinstance(items, list)
|
||||||
|
for item in items
|
||||||
|
]
|
||||||
|
|
||||||
|
return {"footer_nav_items": nav_items}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
from django.dispatch import Signal
|
from django.dispatch import Signal
|
||||||
|
|
||||||
populate_nav = Signal()
|
populate_nav = Signal()
|
||||||
|
|
||||||
|
populate_footer_nav = Signal()
|
||||||
|
|
Before Width: | Height: | Size: 903 B After Width: | Height: | Size: 903 B |
|
@ -110,9 +110,13 @@
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
<div class="breadcrumb has-dot-separator is-flex-grow-1 is-right ml-5">
|
<div class="breadcrumb has-dot-separator is-flex-grow-1 is-right ml-5">
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="{% url 'pages:view' 'map' %}">Karte</a></li>
|
{% for item in footer_nav_items %}
|
||||||
<li><a href="{% url 'pages:view' 'faq' %}">Häufig gestellte Fragen</a></li>
|
<li>
|
||||||
<li><a href="{% url 'pages:view' 'about' %}">Über diese Seite/Impressum</a></li>
|
<{% if item.link %}a{% else %}p{% endif %}{% if item.class %} class="{{ item.class }}"{% endif %}{% if item.link %} href="{{ item.link }}"{% endif %}>
|
||||||
|
{{ item.text }}
|
||||||
|
</{% if item.link %}a{% else %}p{% endif %}>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.shortcuts import reverse
|
from django.shortcuts import reverse
|
||||||
|
|
||||||
from .models import *
|
from .models import *
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# Generated by Django 4.0.4 on 2023-05-07 16:00
|
# Generated by Django 4.0.4 on 2023-05-07 16:00
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
# Generated by Django 4.0.4 on 2023-05-13 17:28
|
# Generated by Django 4.0.4 on 2023-05-13 17:28
|
||||||
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
import shiftregister.fallback.models
|
import shiftregister.fallback.models
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
from shiftregister.importer.models import *
|
|
||||||
from django.db.models import Max, Sum
|
|
||||||
from django.db.models import Count, Exists, OuterRef, ExpressionWrapper
|
|
||||||
from django.db.models.lookups import LessThan
|
|
||||||
from django.db.models.fields import DateTimeField
|
|
||||||
from base64 import urlsafe_b64encode
|
|
||||||
import math
|
import math
|
||||||
import secrets
|
import secrets
|
||||||
|
from base64 import urlsafe_b64encode
|
||||||
|
|
||||||
|
from django.db.models import Count, Exists, ExpressionWrapper, Max, OuterRef, Sum
|
||||||
|
from django.db.models.fields import DateTimeField
|
||||||
|
from django.db.models.lookups import LessThan
|
||||||
|
|
||||||
|
from shiftregister.importer.models import *
|
||||||
|
|
||||||
night_shift_query = Q(start_at__hour__gte=21) | Q(start_at__hour__lte=10)
|
night_shift_query = Q(start_at__hour__gte=21) | Q(start_at__hour__lte=10)
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
from celery import shared_task
|
from celery import shared_task
|
||||||
from .models import FallbackAssignment
|
|
||||||
from shiftregister.app.models import ShiftRegistration
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
|
from django.db.models import Case, Count, ExpressionWrapper, F, Q, When
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from dynamic_preferences.registries import global_preferences_registry
|
from dynamic_preferences.registries import global_preferences_registry
|
||||||
from django.db.models import F, Count, Q, ExpressionWrapper, Case, When
|
|
||||||
from datetime import datetime
|
|
||||||
from django.utils import timezone
|
|
||||||
|
|
||||||
|
from shiftregister.app.models import ShiftRegistration
|
||||||
|
|
||||||
|
from .models import FallbackAssignment
|
||||||
|
|
||||||
global_preferences = global_preferences_registry.manager()
|
global_preferences = global_preferences_registry.manager()
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
from base64 import urlsafe_b64decode
|
from base64 import urlsafe_b64decode
|
||||||
|
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.db.models import Count
|
from django.db.models import Count
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
from django.shortcuts import render, get_object_or_404
|
from django.shortcuts import get_object_or_404, render
|
||||||
|
|
||||||
from shiftregister.fallback.models import TeamMember
|
from shiftregister.fallback.models import TeamMember
|
||||||
|
|
||||||
# Create your views here.
|
# Create your views here.
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
from .models import Feedback
|
|
||||||
from django.forms import ModelForm
|
|
||||||
from django import forms
|
from django import forms
|
||||||
|
from django.forms import ModelForm
|
||||||
|
|
||||||
|
from .models import Feedback
|
||||||
|
|
||||||
|
|
||||||
class FeedbackForm(ModelForm):
|
class FeedbackForm(ModelForm):
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# Generated by Django 4.0.4 on 2023-05-25 14:16
|
# Generated by Django 4.0.4 on 2023-05-25 14:16
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
# Generated by Django 4.0.4 on 2023-05-27 17:48
|
# Generated by Django 4.0.4 on 2023-05-27 17:48
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
import secrets
|
import secrets
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
from django.db import models
|
|
||||||
from secrets import token_urlsafe
|
from secrets import token_urlsafe
|
||||||
|
|
||||||
|
from django.db import models
|
||||||
|
|
||||||
from shiftregister.app.models import Helper
|
from shiftregister.app.models import Helper
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
from django.shortcuts import reverse
|
from django.shortcuts import reverse
|
||||||
from dynamic_preferences.registries import global_preferences_registry
|
from dynamic_preferences.registries import global_preferences_registry
|
||||||
|
|
||||||
from shiftregister.core.signals import populate_nav
|
from shiftregister.core.signals import populate_nav
|
||||||
|
|
||||||
global_preferences = global_preferences_registry.manager()
|
global_preferences = global_preferences_registry.manager()
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
from django.shortcuts import render, get_object_or_404
|
|
||||||
from .forms import FeedbackForm
|
|
||||||
from .models import Feedback, ShareToken
|
|
||||||
from shiftregister.app.models import LoginToken
|
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
|
from django.shortcuts import get_object_or_404, render
|
||||||
|
|
||||||
|
from shiftregister.app.models import LoginToken
|
||||||
|
|
||||||
|
from .forms import FeedbackForm
|
||||||
|
from .models import Feedback, ShareToken
|
||||||
|
|
||||||
|
|
||||||
def feedback(request, token):
|
def feedback(request, token):
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
|
||||||
from .models import Calendar
|
from .models import Calendar
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
from datetime import timezone
|
from datetime import timezone
|
||||||
|
|
||||||
|
import requests
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
from icalendar import Calendar
|
from icalendar import Calendar
|
||||||
|
|
||||||
from .models import Event, Room, Shift
|
from .models import Event, Room, Shift
|
||||||
import requests
|
|
||||||
|
|
||||||
|
|
||||||
def import_calendar(calendar):
|
def import_calendar(calendar):
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# Generated by Django 4.0.4 on 2022-04-27 14:11
|
# Generated by Django 4.0.4 on 2022-04-27 14:11
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
from shiftregister.app.models import *
|
from shiftregister.app.models import *
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
from celery import shared_task
|
from celery import shared_task
|
||||||
|
|
||||||
from .importer import import_calendar
|
from .importer import import_calendar
|
||||||
from .models import Calendar
|
from .models import Calendar
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models import Count, Case, F, When, Sum
|
from django.db.models import Case, Count, F, Sum, When
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
from shiftregister.app.models import Helper, Room, Shift, ShiftRegistration, Message
|
|
||||||
|
from shiftregister.app.models import Helper, Message, Room, Shift, ShiftRegistration
|
||||||
from shiftregister.fallback.models import FallbackAssignment
|
from shiftregister.fallback.models import FallbackAssignment
|
||||||
from shiftregister.importer.models import Event
|
from shiftregister.importer.models import Event
|
||||||
|
|
||||||
|
@ -159,9 +160,11 @@ def metrics(request):
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"worked_seconds_total",
|
"worked_seconds_total",
|
||||||
worked_seconds_total.total_seconds()
|
(
|
||||||
if worked_seconds_total
|
worked_seconds_total.total_seconds()
|
||||||
else 0.0,
|
if worked_seconds_total
|
||||||
|
else 0.0
|
||||||
|
),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"worked_shifts_total",
|
"worked_shifts_total",
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
from django.contrib import admin
|
|
||||||
from .models import Page
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
from .models import Page
|
||||||
|
|
||||||
|
|
||||||
def reimport(modeladmin, request, queryset):
|
def reimport(modeladmin, request, queryset):
|
||||||
for page in queryset:
|
for page in queryset:
|
||||||
|
@ -13,6 +15,21 @@ def reimport(modeladmin, request, queryset):
|
||||||
|
|
||||||
@admin.register(Page)
|
@admin.register(Page)
|
||||||
class PageAdmin(admin.ModelAdmin):
|
class PageAdmin(admin.ModelAdmin):
|
||||||
fields = ("url", "content", "title", "visible", "kind")
|
fields = (
|
||||||
list_display = ("url", "title", "visible", "kind")
|
"url",
|
||||||
|
"content",
|
||||||
|
"title",
|
||||||
|
"visible",
|
||||||
|
"kind",
|
||||||
|
"show_in_footer_nav",
|
||||||
|
"show_in_main_nav",
|
||||||
|
)
|
||||||
|
list_display = (
|
||||||
|
"url",
|
||||||
|
"title",
|
||||||
|
"visible",
|
||||||
|
"kind",
|
||||||
|
"show_in_footer_nav",
|
||||||
|
"show_in_main_nav",
|
||||||
|
)
|
||||||
actions = (reimport,)
|
actions = (reimport,)
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
from django.apps import AppConfig
|
from django.apps import AppConfig
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
|
|
||||||
class PagesConfig(AppConfig):
|
class PagesConfig(AppConfig):
|
||||||
default_auto_field = "django.db.models.BigAutoField"
|
default_auto_field = "django.db.models.BigAutoField"
|
||||||
name = "shiftregister.pages"
|
name = "shiftregister.pages"
|
||||||
|
|
||||||
|
def ready(self):
|
||||||
|
from . import signals
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
from django.core.management.base import BaseCommand, CommandError
|
from django.core.management.base import BaseCommand, CommandError
|
||||||
|
|
||||||
from ...models import Page
|
from ...models import Page
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
|
|
||||||
class Command(BaseCommand):
|
class Command(BaseCommand):
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
# Generated by Django 5.0.4 on 2024-05-03 21:31
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("pages", "0002_page_kind_alter_page_title"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="page",
|
||||||
|
name="show_in_footer_nav",
|
||||||
|
field=models.BooleanField(default=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="page",
|
||||||
|
name="show_in_main_nav",
|
||||||
|
field=models.BooleanField(default=False),
|
||||||
|
),
|
||||||
|
]
|
|
@ -16,6 +16,8 @@ class Page(models.Model):
|
||||||
visible = models.BooleanField(default=True)
|
visible = models.BooleanField(default=True)
|
||||||
title = models.CharField(blank=True, max_length=200)
|
title = models.CharField(blank=True, max_length=200)
|
||||||
kind = models.CharField(choices=KIND_CHOICES, default=REGULAR, max_length=8)
|
kind = models.CharField(choices=KIND_CHOICES, default=REGULAR, max_length=8)
|
||||||
|
show_in_footer_nav = models.BooleanField(default=True)
|
||||||
|
show_in_main_nav = models.BooleanField(default=False)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
from django.dispatch import receiver
|
||||||
|
from django.urls import reverse
|
||||||
|
|
||||||
|
from shiftregister.core.signals import populate_footer_nav, populate_nav
|
||||||
|
|
||||||
|
from .models import Page
|
||||||
|
|
||||||
|
|
||||||
|
@receiver(populate_footer_nav, dispatch_uid="populate_pages_footer_nav")
|
||||||
|
def populate_pages_footer_nav(sender, **kwargs):
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
"link": reverse("pages:view", args=(page.url,)),
|
||||||
|
"text": page.title or page.url,
|
||||||
|
}
|
||||||
|
for page in Page.objects.filter(visible=True)
|
||||||
|
if page.visible and page.show_in_footer_nav
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@receiver(populate_nav, dispatch_uid="populate_pages_nav")
|
||||||
|
def populate_pages_nav(sender, **kwargs):
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
"link": reverse("pages:view", args=(page.url,)),
|
||||||
|
"text": page.title or page.url,
|
||||||
|
}
|
||||||
|
for page in Page.objects.filter(visible=True)
|
||||||
|
if page.visible and page.show_in_main_nav
|
||||||
|
]
|
|
@ -1,8 +1,9 @@
|
||||||
from django.views.generic import DetailView
|
|
||||||
from django.shortcuts import redirect
|
|
||||||
from django.core.validators import URLValidator
|
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
|
from django.core.validators import URLValidator
|
||||||
from django.http import HttpResponseNotFound
|
from django.http import HttpResponseNotFound
|
||||||
|
from django.shortcuts import redirect
|
||||||
|
from django.views.generic import DetailView
|
||||||
|
|
||||||
from .models import Page
|
from .models import Page
|
||||||
|
|
||||||
# Create your views here.
|
# Create your views here.
|
||||||
|
|
|
@ -10,12 +10,13 @@ For the full list of settings and their values, see
|
||||||
https://docs.djangoproject.com/en/4.0/ref/settings/
|
https://docs.djangoproject.com/en/4.0/ref/settings/
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from pathlib import Path
|
|
||||||
from os import getenv
|
from os import getenv
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
import sentry_sdk
|
import sentry_sdk
|
||||||
|
from django.contrib.messages import constants as messages
|
||||||
from sentry_sdk.integrations.celery import CeleryIntegration
|
from sentry_sdk.integrations.celery import CeleryIntegration
|
||||||
from sentry_sdk.integrations.django import DjangoIntegration
|
from sentry_sdk.integrations.django import DjangoIntegration
|
||||||
from django.contrib.messages import constants as messages
|
|
||||||
|
|
||||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||||
|
@ -39,15 +40,15 @@ ALLOWED_HOSTS = list(filter(lambda s: s != "", getenv("ALLOWED_HOSTS", "").split
|
||||||
|
|
||||||
INSTALLED_APPS = [
|
INSTALLED_APPS = [
|
||||||
"dynamic_preferences",
|
"dynamic_preferences",
|
||||||
"shiftregister.app.apps.AppConfig",
|
"shiftregister.app",
|
||||||
"shiftregister.core.apps.CoreConfig",
|
"shiftregister.core",
|
||||||
"shiftregister.fallback.apps.FallbackConfig",
|
"shiftregister.fallback",
|
||||||
"shiftregister.importer.apps.ImporterConfig",
|
"shiftregister.importer",
|
||||||
"shiftregister.metrics.apps.MetricsConfig",
|
"shiftregister.metrics",
|
||||||
"shiftregister.pages.apps.PagesConfig",
|
"shiftregister.pages",
|
||||||
"shiftregister.signage.apps.SignageConfig",
|
"shiftregister.signage",
|
||||||
"shiftregister.team.apps.TeamConfig",
|
"shiftregister.team",
|
||||||
"shiftregister.feedback.apps.FeedbackConfig",
|
"shiftregister.feedback",
|
||||||
"django.contrib.admin",
|
"django.contrib.admin",
|
||||||
"django.contrib.auth",
|
"django.contrib.auth",
|
||||||
"django.contrib.contenttypes",
|
"django.contrib.contenttypes",
|
||||||
|
@ -85,6 +86,7 @@ TEMPLATES = [
|
||||||
"django.contrib.auth.context_processors.auth",
|
"django.contrib.auth.context_processors.auth",
|
||||||
"django.contrib.messages.context_processors.messages",
|
"django.contrib.messages.context_processors.messages",
|
||||||
"shiftregister.app.context_processors.proc",
|
"shiftregister.app.context_processors.proc",
|
||||||
|
"shiftregister.core.context_processors.footer_nav",
|
||||||
"shiftregister.core.context_processors.nav",
|
"shiftregister.core.context_processors.nav",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -146,10 +148,6 @@ USE_TZ = True
|
||||||
STATIC_ROOT = "/opt/shiftregister/static"
|
STATIC_ROOT = "/opt/shiftregister/static"
|
||||||
STATIC_URL = "static/"
|
STATIC_URL = "static/"
|
||||||
|
|
||||||
STATICFILES_DIRS = [
|
|
||||||
BASE_DIR / "assets",
|
|
||||||
]
|
|
||||||
|
|
||||||
# Default primary key field type
|
# Default primary key field type
|
||||||
# https://docs.djangoproject.com/en/4.0/ref/settings/#default-auto-field
|
# https://docs.djangoproject.com/en/4.0/ref/settings/#default-auto-field
|
||||||
|
|
||||||
|
@ -178,7 +176,7 @@ CELERY_BEAT_SCHEDULE = {
|
||||||
},
|
},
|
||||||
"deactivate-fallbacks-every-300-seconds": {
|
"deactivate-fallbacks-every-300-seconds": {
|
||||||
"task": "shiftregister.fallback.tasks.deactivate_fallbacks",
|
"task": "shiftregister.fallback.tasks.deactivate_fallbacks",
|
||||||
"schedule": float(getenv("FALLBACK_DEACTIVAtE_INTERVAL", 300.0)), # seconds
|
"schedule": float(getenv("FALLBACK_DEACTIVATE_INTERVAL", 300.0)), # seconds
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# Generated by Django 4.0.4 on 2022-05-18 13:10
|
# Generated by Django 4.0.4 on 2022-05-18 13:10
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
from shiftregister.app.models import *
|
from shiftregister.app.models import *
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models import Case, Count, F, ExpressionWrapper, Q, Sum, When
|
from django.db.models import Case, Count, ExpressionWrapper, F, Q, Sum, When
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
from .models import Helper, Shift, ShiftRegistration
|
from .models import Helper, Shift, ShiftRegistration
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
|
||||||
from .models import IncomingMessage, RoomViewToken
|
from .models import IncomingMessage, RoomViewToken
|
||||||
|
|
||||||
# Register your models here.
|
# Register your models here.
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from django import forms
|
from django import forms
|
||||||
from .models import ShiftRegistration, Helper
|
|
||||||
|
from .models import Helper, ShiftRegistration
|
||||||
|
|
||||||
|
|
||||||
# placeholder form for simple submit button use cases so we get csrf protection
|
# placeholder form for simple submit button use cases so we get csrf protection
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# Generated by Django 4.0.4 on 2023-05-06 23:27
|
# Generated by Django 4.0.4 on 2023-05-06 23:27
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
import phonenumber_field.modelfields
|
import phonenumber_field.modelfields
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
# Generated by Django 4.0.4 on 2023-05-18 15:15
|
# Generated by Django 4.0.4 on 2023-05-18 15:15
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
import shiftregister.team.models
|
import shiftregister.team.models
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
|
import secrets
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from phonenumber_field.modelfields import PhoneNumberField
|
from phonenumber_field.modelfields import PhoneNumberField
|
||||||
|
|
||||||
from shiftregister.app.models import *
|
from shiftregister.app.models import *
|
||||||
import secrets
|
|
||||||
|
|
||||||
# Create your models here.
|
# Create your models here.
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
from django.shortcuts import reverse
|
from django.shortcuts import reverse
|
||||||
from dynamic_preferences.registries import global_preferences_registry
|
from dynamic_preferences.registries import global_preferences_registry
|
||||||
|
|
||||||
from shiftregister.core.signals import populate_nav
|
from shiftregister.core.signals import populate_nav
|
||||||
|
|
||||||
from .models import IncomingMessage
|
from .models import IncomingMessage
|
||||||
|
|
||||||
global_preferences = global_preferences_registry.manager()
|
global_preferences = global_preferences_registry.manager()
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
|
import sentry_sdk
|
||||||
from celery import shared_task
|
from celery import shared_task
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
from shiftregister.app.sipgate.history import list_incoming_sms
|
from shiftregister.app.sipgate.history import list_incoming_sms
|
||||||
|
|
||||||
from .models import IncomingMessage
|
from .models import IncomingMessage
|
||||||
import sentry_sdk
|
|
||||||
|
|
||||||
|
|
||||||
@shared_task
|
@shared_task
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
from django import template
|
|
||||||
from re import ASCII, sub
|
from re import ASCII, sub
|
||||||
|
|
||||||
|
from django import template
|
||||||
|
|
||||||
register = template.Library()
|
register = template.Library()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,26 +1,27 @@
|
||||||
from django.shortcuts import render, get_object_or_404, redirect
|
|
||||||
from django.contrib.auth.decorators import login_required
|
|
||||||
from django.utils import timezone
|
|
||||||
from django.db.models.fields import DateTimeField
|
|
||||||
from django.db.models import F, Count, Q, ExpressionWrapper, Case, When
|
|
||||||
from .models import (
|
|
||||||
ShiftRegistration,
|
|
||||||
Room,
|
|
||||||
Shift,
|
|
||||||
Helper,
|
|
||||||
Message,
|
|
||||||
IncomingMessage,
|
|
||||||
RoomViewToken,
|
|
||||||
)
|
|
||||||
from django.views.generic import DetailView, ListView
|
|
||||||
from django.views.generic.edit import FormMixin
|
|
||||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
|
||||||
from django.contrib import messages
|
|
||||||
from django.db import models, transaction
|
|
||||||
from django.core.paginator import Paginator
|
|
||||||
from .forms import BulkMessage, HelperShift, HelperMessage
|
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
|
||||||
|
from django.contrib import messages
|
||||||
|
from django.contrib.auth.decorators import login_required
|
||||||
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
|
from django.core.paginator import Paginator
|
||||||
|
from django.db import models, transaction
|
||||||
|
from django.db.models import Case, Count, ExpressionWrapper, F, Q, When
|
||||||
|
from django.db.models.fields import DateTimeField
|
||||||
|
from django.shortcuts import get_object_or_404, redirect, render
|
||||||
|
from django.utils import timezone
|
||||||
|
from django.views.generic import DetailView, ListView
|
||||||
|
from django.views.generic.edit import FormMixin
|
||||||
|
|
||||||
|
from .forms import BulkMessage, HelperMessage, HelperShift
|
||||||
|
from .models import (
|
||||||
|
Helper,
|
||||||
|
IncomingMessage,
|
||||||
|
Message,
|
||||||
|
Room,
|
||||||
|
RoomViewToken,
|
||||||
|
Shift,
|
||||||
|
ShiftRegistration,
|
||||||
|
)
|
||||||
|
|
||||||
# Create your views here.
|
# Create your views here.
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ Including another URLconf
|
||||||
1. Import the include() function: from django.urls import include, path
|
1. Import the include() function: from django.urls import include, path
|
||||||
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 include, path
|
from django.urls import include, path
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue