diff --git a/.drone.yml b/.drone.yml
new file mode 100644
index 0000000..9c3cd1e
--- /dev/null
+++ b/.drone.yml
@@ -0,0 +1,23 @@
+kind: pipeline
+type: exec
+name: default
+
+
+platform:
+ os: linux
+ arch: amd64
+
+steps:
+ - name: install deps
+ commands:
+ - dnf install -y python3 python3-pip
+ - pip3 install -U Django coverage flake8 pylint django-coverage-plugin pylint-django django-bootstrap4
+ - name: run unittests
+ commands:
+ - coverage run --source='.' manage.py test --noinput --parallel
+ - name: run flake8
+ commands:
+ - flake8 --max-line-length=120
+ - name: run pylint
+ commands:
+ - DJANGO_SETTINGS_MODULE=nmgfitness.settings pylint --rcfile=.pylintrc -- **/*.py
diff --git a/.pylintrc b/.pylintrc
new file mode 100644
index 0000000..1cba4bf
--- /dev/null
+++ b/.pylintrc
@@ -0,0 +1,15 @@
+[MASTER]
+load-plugins=pylint_django
+django-settings-module=nmgfitness.settings
+ignore-paths=.*/migrations
+
+[FORMAT]
+max-line-length=120
+
+[MESSAGES CONTROL]
+
+[DESIGN]
+max-parents=13
+
+[TYPECHECK]
+generated-members=REQUEST,acl_users,aq_parent,"[a-zA-Z]+_set{1,2}",save,delete
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..3bd0dc6
--- /dev/null
+++ b/README.md
@@ -0,0 +1 @@
+[![Build Status](https://drone.caret.be/api/badges/jens/nmgfitness/status.svg)](https://drone.caret.be/jens/nmgfitness)
diff --git a/manage.py b/manage.py
index b4c37f2..5bdda86 100755
--- a/manage.py
+++ b/manage.py
@@ -3,18 +3,12 @@
import os
import sys
+from django.core.management import execute_from_command_line
+
def main():
"""Run administrative tasks."""
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'nmgfitness.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)
diff --git a/nmgfitness/admin.py b/nmgfitness/admin.py
index 31807c0..e11146e 100644
--- a/nmgfitness/admin.py
+++ b/nmgfitness/admin.py
@@ -1,3 +1,4 @@
+"""Admin module"""
from django.apps import apps
from django.contrib import admin
diff --git a/nmgfitness/base.html b/nmgfitness/base.html
new file mode 100644
index 0000000..fc5470b
--- /dev/null
+++ b/nmgfitness/base.html
@@ -0,0 +1,79 @@
+
+
+
+
+
+
+
+
+ NMG Fitness Registration
+
+
+
+
+
+ Calendar
+
+
+
+
+
+
+
+
+
+ {% block content %}
+ BASE TEMPLATE
+ {% endblock %}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/nmgfitness/calendar.html b/nmgfitness/calendar.html
index bfed48b..4206389 100644
--- a/nmgfitness/calendar.html
+++ b/nmgfitness/calendar.html
@@ -1,13 +1,7 @@
-
-
-
-
-
-
-
-
-
-
-
-
Klik op de gewenste plaats in de kalender om een nieuwe reservatie toe te voegen, vul je naam in in het dialoogvenster.
@@ -152,10 +129,6 @@
Je kan een event verschuiven of verlengen/verkorten door het vast te nemen en te verschuiven.
-
- Indien het niet lukt om op een reeds gerserveerd moment een nieuwe reservatie aan te maken,
-
-
-
+{% endblock %}
diff --git a/nmgfitness/migrations/0002_auto_20210805_2157.py b/nmgfitness/migrations/0002_auto_20210805_2157.py
new file mode 100644
index 0000000..cce821d
--- /dev/null
+++ b/nmgfitness/migrations/0002_auto_20210805_2157.py
@@ -0,0 +1,26 @@
+# Generated by Django 3.2.6 on 2021-08-05 21:57
+
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ('nmgfitness', '0001_initial'),
+ ]
+
+ operations = [
+ migrations.RemoveField(
+ model_name='events',
+ name='name',
+ ),
+ migrations.AddField(
+ model_name='events',
+ name='user',
+ field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='auth.user'),
+ preserve_default=False,
+ ),
+ ]
diff --git a/nmgfitness/models.py b/nmgfitness/models.py
index 4dab97e..2cc4580 100644
--- a/nmgfitness/models.py
+++ b/nmgfitness/models.py
@@ -1,11 +1,20 @@
+"""Nmgfitness Events model"""
from django.db import models
+from django.conf import settings
+
class Events(models.Model):
+ """
+ The events class
+ The main class used in this project
+ Events have an id (Autofield primary key)
+ Start and stop time
+ and are linked to a user
+ """
id = models.AutoField(primary_key=True)
- name = models.CharField(max_length=255,null=True,blank=True)
- start = models.DateTimeField(null=True,blank=True)
- end = models.DateTimeField(null=True,blank=True)
+ start = models.DateTimeField(null=True, blank=True)
+ end = models.DateTimeField(null=True, blank=True)
+ user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
def __str__(self):
- return self.name
-
+ return self.user.username
diff --git a/nmgfitness/settings.py b/nmgfitness/settings.py
index 2ab1d9f..690e7ba 100644
--- a/nmgfitness/settings.py
+++ b/nmgfitness/settings.py
@@ -27,17 +27,20 @@ DEBUG = True
ALLOWED_HOSTS = []
-
+LOGIN_URL = '/accounts/login/'
+LOGIN_REDIRECT_URL = '/'
# Application definition
INSTALLED_APPS = [
- 'django.contrib.admin',
+ 'users.apps.UsersConfig',
+ 'nmgfitness',
'django.contrib.auth',
+ 'django.contrib.admin',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
- 'nmgfitness',
+ 'bootstrap4',
]
MIDDLEWARE = [
@@ -112,8 +115,8 @@ USE_I18N = True
USE_L10N = True
-#USE_TZ = True
-#TURNED off for simplicity
+# USE_TZ = True
+# TURNED off for simplicity
USE_TZ = False
diff --git a/nmgfitness/urls.py b/nmgfitness/urls.py
index 99f8465..b4485cc 100644
--- a/nmgfitness/urls.py
+++ b/nmgfitness/urls.py
@@ -14,16 +14,22 @@ Including another URLconf
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
-from django.urls import path
+from django.urls import path, include
from django.conf.urls import url
-from .views import calendar, add_event, update, remove
+from users.views import register
+
+
+from .views import calendar, add_event, update, remove, all_events
urlpatterns = [
+ path('accounts/', include('django.contrib.auth.urls')),
path('admin/', admin.site.urls),
- url('^$', calendar, name='calendar'),
+ path('register/', register, name="register"),
+ url('^$', calendar, name='index'),
url('^add_event$', add_event, name='add_event'),
url('^update$', update, name='update'),
url('^remove', remove, name='remove'),
+ url('^all_events', all_events, name='all_events'),
]
diff --git a/nmgfitness/views.py b/nmgfitness/views.py
index 1ee740d..6a96bb2 100644
--- a/nmgfitness/views.py
+++ b/nmgfitness/views.py
@@ -1,42 +1,85 @@
-from .models import Events
-
+"""NMGFitness views"""
from django.shortcuts import render
from django.http import JsonResponse
+from django.contrib.auth.decorators import login_required
+from .models import Events
+
+
+@login_required
def calendar(request):
- all_events = Events.objects.all()
- context = {
- "events":all_events,
- }
- return render(request,'calendar.html',context)
+ """The main calendar view"""
+ return render(request, 'calendar.html')
+
+@login_required
+def all_events(request):
+ """
+ Json api that returns all events
+ """
+ events = Events.objects.all()
+ out = []
+ for event in events:
+ out.append({
+ 'title': event.user.username,
+ 'id': event.id,
+ 'start': event.start.strftime("%m/%d/%Y, %H:%M:%S"),
+ 'end': event.end.strftime("%m/%d/%Y, %H:%M:%S"),
+ })
+
+ return JsonResponse(out, safe=False)
+
+
+@login_required
def add_event(request):
+ """
+ Json api to add an event
+ given a start and end time in the request get parameters
+ """
+
start = request.GET.get("start", None)
end = request.GET.get("end", None)
- title = request.GET.get("title", None)
- event = Events(name=str(title), start=start, end=end)
+ event = Events(start=start, end=end, user=request.user)
event.save()
data = {}
return JsonResponse(data)
+@login_required
def update(request):
+ """
+ Json api to update an event
+ Given an event id, start and end time
+ Only events from the loged in user are accepted for updates
+ """
+ updateid = request.GET.get("id", None)
+
+ event = Events.objects.get(id=updateid)
+ if request.user != event.user:
+ return JsonResponse({'Unauthorized': 'wrong user'}, status=401)
+
start = request.GET.get("start", None)
end = request.GET.get("end", None)
- title = request.GET.get("title", None)
- id = request.GET.get("id", None)
- event = Events.objects.get(id=id)
event.start = start
event.end = end
- event.name = title
event.save()
data = {}
return JsonResponse(data)
+@login_required
def remove(request):
- id = request.GET.get("id", None)
- event = Events.objects.get(id=id)
+ """
+ Json api to remove an event
+ Given an event id
+ Only events from the loged in user are accepted for removal
+ """
+
+ updateid = request.GET.get("id", None)
+ event = Events.objects.get(id=updateid)
+
+ if request.user != event.user:
+ return JsonResponse({'Unauthorized': 'wrong user'}, status=401)
event.delete()
data = {}
return JsonResponse(data)
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..5284932
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1 @@
+django-bootstrap4
diff --git a/users/__init__.py b/users/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/users/apps.py b/users/apps.py
new file mode 100644
index 0000000..340d2a5
--- /dev/null
+++ b/users/apps.py
@@ -0,0 +1,7 @@
+"""Django app config for the Users app"""
+from django.apps import AppConfig
+
+
+class UsersConfig(AppConfig):
+ """Users App AppConfig"""
+ name = 'users'
diff --git a/users/forms.py b/users/forms.py
new file mode 100644
index 0000000..c236c41
--- /dev/null
+++ b/users/forms.py
@@ -0,0 +1,8 @@
+"""Users forms"""
+from django.contrib.auth.forms import UserCreationForm
+
+
+class CustomUserCreationForm(UserCreationForm):
+ """Custom user creation form that adds an email field"""
+ class Meta(UserCreationForm.Meta):
+ fields = UserCreationForm.Meta.fields + ("email",)
diff --git a/users/templates/registration/logged_out.html b/users/templates/registration/logged_out.html
new file mode 100644
index 0000000..fa69c3f
--- /dev/null
+++ b/users/templates/registration/logged_out.html
@@ -0,0 +1,8 @@
+{% extends "base.html" %}
+
+{% block content %}
+ Logged out!
+ Thanks for spending some quality time with the NMG fittness calendar site today.
+
+ Click here to login again.
+{% endblock %}
diff --git a/users/templates/registration/login.html b/users/templates/registration/login.html
new file mode 100644
index 0000000..b790574
--- /dev/null
+++ b/users/templates/registration/login.html
@@ -0,0 +1,29 @@
+{% extends 'base.html' %}
+
+{% load bootstrap4 %}
+{% block content %}
+
+{% endblock %}
diff --git a/users/templates/registration/password_change_done.html b/users/templates/registration/password_change_done.html
new file mode 100644
index 0000000..1d6f75b
--- /dev/null
+++ b/users/templates/registration/password_change_done.html
@@ -0,0 +1,7 @@
+{% extends 'base.html' %}
+
+{% block content %}
+Password changed
+
+Back to index
+{% endblock %}
diff --git a/users/templates/registration/password_change_form.html b/users/templates/registration/password_change_form.html
new file mode 100644
index 0000000..5b340e9
--- /dev/null
+++ b/users/templates/registration/password_change_form.html
@@ -0,0 +1,16 @@
+{% extends 'base.html' %}
+
+{% load bootstrap4 %}
+{% block content %}
+
+{% endblock %}
diff --git a/users/templates/registration/password_reset_complete.html b/users/templates/registration/password_reset_complete.html
new file mode 100644
index 0000000..27710da
--- /dev/null
+++ b/users/templates/registration/password_reset_complete.html
@@ -0,0 +1,8 @@
+
+{% extends 'base.html' %}
+
+{% block content %}
+Password reset complete
+
+Back to login
+{% endblock %}
diff --git a/users/templates/registration/password_reset_confirm.html b/users/templates/registration/password_reset_confirm.html
new file mode 100644
index 0000000..f647065
--- /dev/null
+++ b/users/templates/registration/password_reset_confirm.html
@@ -0,0 +1,23 @@
+{% extends 'base.html' %}
+
+{% load bootstrap4 %}
+{% block content %}
+
+
Confirm password reset
+
+
+{% if validlink %}
+
+
+
+{% else %}
+
+
The password reset link was invalid, possibly because it has already been used. Please request a new password reset.
+
+{% endif %}
+
+{% endblock %}
diff --git a/users/templates/registration/password_reset_done.html b/users/templates/registration/password_reset_done.html
new file mode 100644
index 0000000..a18db15
--- /dev/null
+++ b/users/templates/registration/password_reset_done.html
@@ -0,0 +1,7 @@
+{% extends 'base.html' %}
+
+{% block content %}
+Password reset done
+
+Back to login
+{% endblock %}
diff --git a/users/templates/registration/password_reset_form.html b/users/templates/registration/password_reset_form.html
new file mode 100644
index 0000000..ed14067
--- /dev/null
+++ b/users/templates/registration/password_reset_form.html
@@ -0,0 +1,19 @@
+{% extends 'base.html' %}
+
+{% load bootstrap4 %}
+{% block content %}
+
+{% endblock %}
diff --git a/users/templates/users/register.html b/users/templates/users/register.html
new file mode 100644
index 0000000..b4f5286
--- /dev/null
+++ b/users/templates/users/register.html
@@ -0,0 +1,25 @@
+{% extends 'base.html' %}
+
+{% load bootstrap4 %}
+
+{% block content %}
+
+
+
+Your username will be visible to other users of this platform
+
+
+After registration your account will need to be activated.
+Contact someone from the Fintess Commitee with your username to get your account activated.
+
+{% endblock %}
diff --git a/users/views.py b/users/views.py
new file mode 100644
index 0000000..b164c5e
--- /dev/null
+++ b/users/views.py
@@ -0,0 +1,24 @@
+"""Users views"""
+from django.shortcuts import redirect, render
+
+from django.urls import reverse
+
+from users.forms import CustomUserCreationForm
+
+
+def register(request):
+ """Register view, uses the CustomUserCreationForm to register a user"""
+ if request.method == "POST":
+ form = CustomUserCreationForm(request.POST)
+ if form.is_valid():
+ user = form.save()
+ user.is_active = False
+ user.save()
+ return redirect(reverse("index"))
+ else:
+ form = CustomUserCreationForm()
+
+ return render(
+ request, "users/register.html",
+ {"form": form}
+ )