diff --git a/Pipfile b/Pipfile index 6f1b3be..da3e4c9 100644 --- a/Pipfile +++ b/Pipfile @@ -9,6 +9,7 @@ name = "pypi" django = "*" djangorestframework = "*" +"django-bootstrap4" = "*" [dev-packages] diff --git a/Pipfile.lock b/Pipfile.lock index 9c5b5e3..425954d 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "1f3d4cc7027911c0d5599450f18f080ccf209827c665920bad7fc6e832bb3b38" + "sha256": "c3ee9bacf90669123493994e4f194606cd953134dd819c73684629335c5a7ee6" }, "host-environment-markers": { "implementation_name": "cpython", @@ -34,6 +34,12 @@ ], "version": "==2.0.2" }, + "django-bootstrap4": { + "hashes": [ + "sha256:6db4a27b33851833e68b96344f9df063150dcace8d4787ebfc21eceb55196945" + ], + "version": "==0.0.6" + }, "djangorestframework": { "hashes": [ "sha256:1f6baf40ed456ed2af6bd1a4ff8bbc3503cebea16509993aea2b7085bc097766", diff --git a/gym/admin.py b/gym/admin.py index 8c38f3f..5d256f9 100644 --- a/gym/admin.py +++ b/gym/admin.py @@ -1,3 +1,28 @@ from django.contrib import admin -# Register your models here. +from gym.models import Room, Equipment, Setting, TheoreticalMax, Session, Round + + +@admin.register(Room) +class RoomAdmin(admin.ModelAdmin): + pass + + +@admin.register(Equipment) +class EquipmentAdmin(admin.ModelAdmin): + pass + + +@admin.register(TheoreticalMax) +class TheoreticalMaxAdmin(admin.ModelAdmin): + pass + + +@admin.register(Session) +class SessionAdmin(admin.ModelAdmin): + pass + + +@admin.register(Round) +class RoundAdmin(admin.ModelAdmin): + pass diff --git a/gym/migrations/0003_auto_20180303_1801.py b/gym/migrations/0003_auto_20180303_1801.py new file mode 100644 index 0000000..f11a14d --- /dev/null +++ b/gym/migrations/0003_auto_20180303_1801.py @@ -0,0 +1,18 @@ +# Generated by Django 2.0.2 on 2018-03-03 17:01 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('gym', '0002_auto_20180303_1201'), + ] + + operations = [ + migrations.AlterField( + model_name='session', + name='date', + field=models.DateTimeField(verbose_name='date et heure de début'), + ), + ] diff --git a/gym/migrations/0004_auto_20180303_1801.py b/gym/migrations/0004_auto_20180303_1801.py new file mode 100644 index 0000000..9799ee8 --- /dev/null +++ b/gym/migrations/0004_auto_20180303_1801.py @@ -0,0 +1,18 @@ +# Generated by Django 2.0.2 on 2018-03-03 17:01 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('gym', '0003_auto_20180303_1801'), + ] + + operations = [ + migrations.RenameField( + model_name='session', + old_name='date', + new_name='start', + ), + ] diff --git a/gym/models.py b/gym/models.py index 991980b..b1c329f 100644 --- a/gym/models.py +++ b/gym/models.py @@ -11,6 +11,9 @@ class Room(models.Model): longitude = models.DecimalField('longitude', max_digits=11, decimal_places=8, blank=True) notes = models.TextField('notes', blank=True) + def __str__(self): + return self.name + class Equipment(models.Model): class Meta: @@ -26,6 +29,13 @@ class Equipment(models.Model): null=True ) + @property + def last_theoretical_max(self): + return self.theoretical_maxs.order_by('-start').first() + + def __str__(self): + return f'{self.name} ({self.room.name})' + class Setting(models.Model): class Meta: @@ -41,6 +51,9 @@ class Setting(models.Model): name = models.CharField('nom', max_length=200) value = models.CharField('valeur', max_length=200) + def __str__(self): + return f'{self.name}={self.value}' + class TheoreticalMax(models.Model): class Meta: @@ -56,13 +69,16 @@ class TheoreticalMax(models.Model): date = models.DateField('date') value = models.FloatField('valeur') + def __str__(self): + return f'{self.value}kg le {self.date}' + class Session(models.Model): class Meta: verbose_name = 'séance' verbose_name_plural = 'séances' - date = models.DateField('date') + start = models.DateTimeField('date et heure de début') room = models.ForeignKey( verbose_name='salle', to=Room, diff --git a/gym/serializers.py b/gym/serializers.py deleted file mode 100644 index fe4ab71..0000000 --- a/gym/serializers.py +++ /dev/null @@ -1,22 +0,0 @@ -from django.contrib.auth.models import User -from rest_framework import serializers - -from gym.models import Room, Equipment - - -class UserSerializer(serializers.ModelSerializer): - class Meta: - model = User - fields = ('id', 'username', 'email', 'first_name', 'last_name') - - -class RoomSerializer(serializers.HyperlinkedModelSerializer): - class Meta: - model = Room - fields = ('url', 'name', 'latitude', 'longitude', 'notes', 'equipments') - - -class EquipmentSerializer(serializers.HyperlinkedModelSerializer): - class Meta: - model = Equipment - fields = ('url', 'name', 'room') diff --git a/gym/templates/gym/base.html b/gym/templates/gym/base.html new file mode 100644 index 0000000..db8a458 --- /dev/null +++ b/gym/templates/gym/base.html @@ -0,0 +1,37 @@ + + + + + + + {% block add-head %} + {% endblock %} + + Gym · {% block title %}Home{% endblock %} + + +
+ {% for message in messages %} + + {% endfor %} + {% block content %} + {% endblock %} +
+ + + + + + \ No newline at end of file diff --git a/gym/templates/gym/equipment.html b/gym/templates/gym/equipment.html new file mode 100644 index 0000000..f6a93cf --- /dev/null +++ b/gym/templates/gym/equipment.html @@ -0,0 +1,26 @@ +{% extends 'gym/base.html' %} + +{% block content %} +
+
+

{% block title %}{{ equipment.name }} ({{ equipment.room.name }}){% endblock %}

+
+
+
+
+ Retourner à la salle + Ajouter un réglage +
+
+
+
+

Réglages

+ +
+
+{% endblock %} \ No newline at end of file diff --git a/gym/templates/gym/equipment_edit.html b/gym/templates/gym/equipment_edit.html new file mode 100644 index 0000000..1225189 --- /dev/null +++ b/gym/templates/gym/equipment_edit.html @@ -0,0 +1,22 @@ +{% extends 'gym/base.html' %} +{% load bootstrap4 %} + +{% block content %} +
+
+

{% block title %}Ajouter une machine{% endblock %}

+
+
+
+
+
+ {% csrf_token %} + {% bootstrap_form form %} + {% buttons %} + + {% endbuttons %} +
+ +
+
+{% endblock %} \ No newline at end of file diff --git a/gym/templates/gym/room.html b/gym/templates/gym/room.html new file mode 100644 index 0000000..0595a7d --- /dev/null +++ b/gym/templates/gym/room.html @@ -0,0 +1,38 @@ +{% extends 'gym/base.html' %} + +{% block content %} +
+
+

{% block title %}{{ room.name }}{% endblock %}

+
+
+
+
+ Liste des salles + Ajouter une machine + Commencer une séance +
+
+
+
+

Machines

+ +
+
+ {% if room.sessions.all %} +
+
+

Séances

+ +
+
+ {% endif %} +{% endblock %} \ No newline at end of file diff --git a/gym/templates/gym/rooms.html b/gym/templates/gym/rooms.html new file mode 100644 index 0000000..a49fee0 --- /dev/null +++ b/gym/templates/gym/rooms.html @@ -0,0 +1,18 @@ +{% extends 'gym/base.html' %} + +{% block content %} +
+
+

{% block title %}Salles{% endblock %}

+
+
+
+
+ +
+
+{% endblock %} \ No newline at end of file diff --git a/gym/templates/gym/session_detail.html b/gym/templates/gym/session_detail.html new file mode 100644 index 0000000..4ddf0e5 --- /dev/null +++ b/gym/templates/gym/session_detail.html @@ -0,0 +1,42 @@ +{% extends 'gym/base.html' %} +{% load bootstrap4 %} + +{% block content %} +
+
+

{% block title %}Séance en cours{% endblock %}

+
+
+
+
+ Retourner à la salle + Ajouter une machine +
+
+
+
+

Infos

+
+
+
+
+ +
+
+
+
+

Machines

+ +
+
+{% endblock %} \ No newline at end of file diff --git a/gym/templates/gym/session_edit.html b/gym/templates/gym/session_edit.html new file mode 100644 index 0000000..53dbecc --- /dev/null +++ b/gym/templates/gym/session_edit.html @@ -0,0 +1,29 @@ +{% extends 'gym/base.html' %} +{% load bootstrap4 %} + +{% block content %} +
+
+

{% block title %}{{ title }} une séance{% endblock %}

+
+
+
+
+ {% if room %} + Retourner à la salle + {% endif %} +
+
+
+
+
+ {% csrf_token %} + {% bootstrap_form form %} + {% buttons %} + + {% endbuttons %} +
+ +
+
+{% endblock %} \ No newline at end of file diff --git a/gym/templates/gym/setting_confirm_delete.html b/gym/templates/gym/setting_confirm_delete.html new file mode 100644 index 0000000..9036ab1 --- /dev/null +++ b/gym/templates/gym/setting_confirm_delete.html @@ -0,0 +1,19 @@ +{% extends 'gym/base.html' %} +{% load bootstrap4 %} + +{% block content %} +
+
+

{% block title %}Supprimer un réglage{% endblock %}

+
+
+
+
+
+ {% csrf_token %} +

Êtes-vous sûr de vouloir supprimer le réglage {{ setting }} pour la machine "{{ setting.equipment }}" ?

+ +
+
+
+{% endblock %} \ No newline at end of file diff --git a/gym/templates/gym/setting_edit.html b/gym/templates/gym/setting_edit.html new file mode 100644 index 0000000..cf80636 --- /dev/null +++ b/gym/templates/gym/setting_edit.html @@ -0,0 +1,31 @@ +{% extends 'gym/base.html' %} +{% load bootstrap4 %} + +{% block content %} +
+
+

{% block title %}{{ title }} un réglage{% endblock %}

+
+
+
+
+ {% if equipment %} + Retourner à la machine + {% endif %} +
+
+
+
+
+ {% csrf_token %} + {% bootstrap_form form %} + {% buttons %} + + {% if edit %} + Supprimer + {% endif %} + {% endbuttons %} +
+
+
+{% endblock %} \ No newline at end of file diff --git a/gym/urls.py b/gym/urls.py index 409e078..11ce67d 100644 --- a/gym/urls.py +++ b/gym/urls.py @@ -1,21 +1,19 @@ -from django.conf.urls import url, include -from rest_framework import routers -from . import views +from django.urls import path -router = routers.DefaultRouter() -router.register(r'rooms', views.RoomViewSet) -router.register(r'equipments', views.EquipmentViewSet) +from . import views # Wire up our API using automatic URL routing. # Additionally, we include login URLs for the browsable API. urlpatterns = [ - url(r'^api/', include(router.urls)), - url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')), - url(r'^api/me/', views.MeView.as_view()) + path('', views.RoomListView.as_view(), name='rooms-list'), + path('rooms//', views.RoomDetailView.as_view(), name='room-detail'), + path('equipment/add/', views.EquipmentCreateView.as_view(), name='equipment-create'), + path('equipment//', views.EquipmentDetailView.as_view(), name='equipment-detail'), + path('setting/add/', views.SettingCreateView.as_view(), name='setting-create'), + path('setting//', views.SettingUpdateView.as_view(), name='setting-edit'), + path('setting//delete', views.SettingDeleteView.as_view(), name='setting-delete'), + path('session/start/', views.SessionCreateView.as_view(), name='session-start'), + path('session//', views.SessionDetailView.as_view(), name='session-detail'), + # path('session//delete', views.SessionDeleteView.as_view(), name='session-delete'), ] -from rest_framework.authtoken import views - -urlpatterns += [ - url(r'^api-token-auth/', views.obtain_auth_token) -] diff --git a/gym/views.py b/gym/views.py index 7499c0c..9ebcdfd 100644 --- a/gym/views.py +++ b/gym/views.py @@ -1,24 +1,135 @@ -from django.contrib.auth.models import User -from rest_framework import viewsets -from rest_framework.generics import RetrieveUpdateAPIView +import datetime -from gym.models import Room, Equipment -from gym.serializers import RoomSerializer, EquipmentSerializer, UserSerializer +from django.shortcuts import get_object_or_404 +from django.urls import reverse +from django.views import generic + +from gym.models import Room, Equipment, Setting, Session -class MeView(RetrieveUpdateAPIView): - serializer_class = UserSerializer - queryset = User.objects.none() - - def get_object(self): - return self.request.user - - -class RoomViewSet(viewsets.ModelViewSet): +class RoomListView(generic.ListView): queryset = Room.objects.all().order_by('name') - serializer_class = RoomSerializer + context_object_name = 'rooms' + template_name = 'gym/rooms.html' -class EquipmentViewSet(viewsets.ModelViewSet): - queryset = Equipment.objects.all().order_by('name') - serializer_class = EquipmentSerializer \ No newline at end of file +class RoomDetailView(generic.DetailView): + model = Room + context_object_name = 'room' + template_name = 'gym/room.html' + + +class EquipmentDetailView(generic.DetailView): + model = Equipment + context_object_name = 'equipment' + template_name = 'gym/equipment.html' + + +class EquipmentCreateView(generic.CreateView): + model = Equipment + fields = ['room', 'name'] + template_name = 'gym/equipment_edit.html' + room = None + + def get_success_url(self): + return reverse('equipment-detail', kwargs={'pk': self.object.pk}) + + def dispatch(self, request, *args, **kwargs): + default_room_id = self.request.GET.get('room') + if default_room_id: + self.room = get_object_or_404(Room, pk=default_room_id) + + return super().dispatch(request, *args, **kwargs) + + def get_initial(self): + initial = super().get_initial() + initial['room'] = self.room + + return initial + + +class SettingCreateView(generic.CreateView): + model = Setting + fields = ['equipment', 'name', 'value'] + template_name = 'gym/setting_edit.html' + equipment = None + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context['title'] = 'Ajouter' + context['equipment'] = self.equipment + return context + + def dispatch(self, request, *args, **kwargs): + default_equipment_id = self.request.GET.get('equipment') + if default_equipment_id: + self.equipment = get_object_or_404(Equipment, pk=default_equipment_id) + + return super().dispatch(request, *args, **kwargs) + + def get_initial(self): + initial = super().get_initial() + initial['equipment'] = self.equipment + + return initial + + def get_success_url(self): + return reverse('equipment-detail', kwargs={'pk': self.object.equipment.pk}) + + +class SettingUpdateView(generic.UpdateView): + model = Setting + fields = ['equipment', 'name', 'value'] + template_name = 'gym/setting_edit.html' + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context['edit'] = True + context['title'] = 'Modifier' + context['equipment'] = self.object.equipment + return context + + def get_success_url(self): + return reverse('equipment-detail', kwargs={'pk': self.object.equipment.pk}) + + +class SettingDeleteView(generic.DeleteView): + model = Setting + template_name = 'gym/setting_confirm_delete.html' + context_object_name = 'setting' + + def get_success_url(self): + return reverse('equipment-detail', kwargs={'pk': self.object.equipment.pk}) + + +class SessionCreateView(generic.CreateView): + model = Session + fields = ['room', 'start'] + template_name = 'gym/session_edit.html' + room = None + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context['title'] = 'Démarrer' + context['room'] = self.room + return context + + def get_success_url(self): + return reverse('session-detail', kwargs={'pk': self.object.pk}) + + def dispatch(self, request, *args, **kwargs): + self.room = get_object_or_404(Room, pk=self.request.GET.get('room')) + return super().dispatch(request, *args, **kwargs) + + def get_initial(self): + initial = super().get_initial() + initial['room'] = self.room + initial['start'] = datetime.datetime.now() + + return initial + + +class SessionDetailView(generic.DetailView): + model = Session + context_object_name = 'session' + template_name = 'gym/session_detail.html' diff --git a/muscu/settings.py b/muscu/settings.py index 4592fdd..1f27932 100644 --- a/muscu/settings.py +++ b/muscu/settings.py @@ -24,7 +24,7 @@ SECRET_KEY = 'x*8q7sd14&a%cu95$h@jl&&#bb&j(j*-6h5!3atz*v%!zo3hd4' # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True -ALLOWED_HOSTS = [] +ALLOWED_HOSTS = ['*'] # Application definition @@ -36,8 +36,7 @@ INSTALLED_APPS = [ 'django.contrib.messages', 'django.contrib.staticfiles', 'gym', - 'rest_framework', - 'rest_framework.authtoken', + 'bootstrap4', ] MIDDLEWARE = [ @@ -98,18 +97,6 @@ AUTH_PASSWORD_VALIDATORS = [ }, ] -REST_FRAMEWORK = { - # Use Django's standard `django.contrib.auth` permissions, - # or allow read-only access for unauthenticated users. - 'DEFAULT_PERMISSION_CLASSES': [ - 'rest_framework.permissions.DjangoModelPermissions' - ], - 'DEFAULT_AUTHENTICATION_CLASSES': ( - 'rest_framework.authentication.TokenAuthentication', - 'rest_framework.authentication.SessionAuthentication', - ) -} - # Internationalization # https://docs.djangoproject.com/en/2.0/topics/i18n/