Black everything

This commit is contained in:
Gabriel Augendre 2019-06-23 15:39:13 +02:00
parent f0c18dbe74
commit 5fc79b9486
18 changed files with 737 additions and 524 deletions

View file

@ -5,37 +5,51 @@ from gym.models import Room, Equipment, TheoreticalMax, Session, Round, Unit, Wo
@admin.register(Room) @admin.register(Room)
class RoomAdmin(admin.ModelAdmin): class RoomAdmin(admin.ModelAdmin):
list_display = ['name', 'latitude', 'longitude'] list_display = ["name", "latitude", "longitude"]
@admin.register(Equipment) @admin.register(Equipment)
class EquipmentAdmin(admin.ModelAdmin): class EquipmentAdmin(admin.ModelAdmin):
list_display = ['name', 'room', 'unit', 'last_theoretical_max', 'default_work_form', 'default_repetition_number'] list_display = [
list_editable = ['default_work_form', 'default_repetition_number'] "name",
list_filter = ['room', 'unit', 'default_work_form'] "room",
"unit",
"last_theoretical_max",
"default_work_form",
"default_repetition_number",
]
list_editable = ["default_work_form", "default_repetition_number"]
list_filter = ["room", "unit", "default_work_form"]
@admin.register(TheoreticalMax) @admin.register(TheoreticalMax)
class TheoreticalMaxAdmin(admin.ModelAdmin): class TheoreticalMaxAdmin(admin.ModelAdmin):
list_display = ['equipment', 'date', 'value'] list_display = ["equipment", "date", "value"]
list_display_links = ['equipment', 'date'] list_display_links = ["equipment", "date"]
list_filter = ['equipment'] list_filter = ["equipment"]
date_hierarchy = 'date' date_hierarchy = "date"
@admin.register(Session) @admin.register(Session)
class SessionAdmin(admin.ModelAdmin): class SessionAdmin(admin.ModelAdmin):
list_display = ['start', 'room', 'default_theoretical_max_percentage'] list_display = ["start", "room", "default_theoretical_max_percentage"]
list_filter = ['room'] list_filter = ["room"]
date_hierarchy = 'start' date_hierarchy = "start"
@admin.register(Round) @admin.register(Round)
class RoundAdmin(admin.ModelAdmin): class RoundAdmin(admin.ModelAdmin):
list_display = ['equipment', 'session', 'repetition_number', 'theoretical_max_percentage', 'chosen_weight', 'work_form'] list_display = [
list_display_links = ['equipment', 'session'] "equipment",
list_filter = ['equipment', 'work_form'] "session",
date_hierarchy = 'session__start' "repetition_number",
"theoretical_max_percentage",
"chosen_weight",
"work_form",
]
list_display_links = ["equipment", "session"]
list_filter = ["equipment", "work_form"]
date_hierarchy = "session__start"
@admin.register(Unit) @admin.register(Unit)

View file

@ -2,4 +2,4 @@ from django.apps import AppConfig
class GymConfig(AppConfig): class GymConfig(AppConfig):
name = 'gym' name = "gym"

View file

@ -8,97 +8,189 @@ class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = []
]
operations = [ operations = [
migrations.CreateModel( migrations.CreateModel(
name='Equipment', name="Equipment",
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('name', models.CharField(max_length=300, verbose_name='nom')), "id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("name", models.CharField(max_length=300, verbose_name="nom")),
], ],
options={ options={"verbose_name": "machine", "verbose_name_plural": "machines"},
'verbose_name': 'machine',
'verbose_name_plural': 'machines',
},
), ),
migrations.CreateModel( migrations.CreateModel(
name='Room', name="Room",
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('name', models.CharField(max_length=300, verbose_name='nom')), "id",
('latitude', models.DecimalField(decimal_places=8, max_digits=11, verbose_name='latitude')), models.AutoField(
('longitude', models.DecimalField(decimal_places=8, max_digits=11, verbose_name='longitude')), auto_created=True,
('notes', models.TextField(verbose_name='notes')), primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("name", models.CharField(max_length=300, verbose_name="nom")),
(
"latitude",
models.DecimalField(
decimal_places=8, max_digits=11, verbose_name="latitude"
),
),
(
"longitude",
models.DecimalField(
decimal_places=8, max_digits=11, verbose_name="longitude"
),
),
("notes", models.TextField(verbose_name="notes")),
], ],
options={ options={"verbose_name": "salle", "verbose_name_plural": "salles"},
'verbose_name': 'salle',
'verbose_name_plural': 'salles',
},
), ),
migrations.CreateModel( migrations.CreateModel(
name='Round', name="Round",
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('repetition_number', models.PositiveIntegerField(verbose_name='nombre de répétitions')), "id",
('theoretical_max_percentage', models.PositiveIntegerField(verbose_name='pourcentage')), models.AutoField(
('chosen_weight', models.FloatField(verbose_name='charge choisie')), auto_created=True,
('notes', models.TextField(verbose_name='notes')), primary_key=True,
('equipment', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='rounds', to='gym.Equipment', verbose_name='machine')), serialize=False,
verbose_name="ID",
),
),
(
"repetition_number",
models.PositiveIntegerField(verbose_name="nombre de répétitions"),
),
(
"theoretical_max_percentage",
models.PositiveIntegerField(verbose_name="pourcentage"),
),
("chosen_weight", models.FloatField(verbose_name="charge choisie")),
("notes", models.TextField(verbose_name="notes")),
(
"equipment",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="rounds",
to="gym.Equipment",
verbose_name="machine",
),
),
], ],
options={ options={"verbose_name": "série", "verbose_name_plural": "séries"},
'verbose_name': 'série',
'verbose_name_plural': 'séries',
},
), ),
migrations.CreateModel( migrations.CreateModel(
name='Session', name="Session",
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('date', models.DateField(verbose_name='date')), "id",
('notes', models.TextField(verbose_name='notes')), models.AutoField(
('room', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='sessions', to='gym.Room', verbose_name='salle')), auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("date", models.DateField(verbose_name="date")),
("notes", models.TextField(verbose_name="notes")),
(
"room",
models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="sessions",
to="gym.Room",
verbose_name="salle",
),
),
], ],
options={ options={"verbose_name": "séance", "verbose_name_plural": "séances"},
'verbose_name': 'séance',
'verbose_name_plural': 'séances',
},
), ),
migrations.CreateModel( migrations.CreateModel(
name='Setting', name="Setting",
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('name', models.CharField(max_length=200, verbose_name='nom')), "id",
('value', models.CharField(max_length=200, verbose_name='valeur')), models.AutoField(
('equipment', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='settings', to='gym.Equipment', verbose_name='machine')), auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("name", models.CharField(max_length=200, verbose_name="nom")),
("value", models.CharField(max_length=200, verbose_name="valeur")),
(
"equipment",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="settings",
to="gym.Equipment",
verbose_name="machine",
),
),
], ],
options={ options={"verbose_name": "réglage", "verbose_name_plural": "réglages"},
'verbose_name': 'réglage',
'verbose_name_plural': 'réglages',
},
), ),
migrations.CreateModel( migrations.CreateModel(
name='TheoreticalMax', name="TheoreticalMax",
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('date', models.DateField(verbose_name='date')), "id",
('value', models.FloatField(verbose_name='valeur')), models.AutoField(
('equipment', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='theoretical_maxs', to='gym.Equipment', verbose_name='machine')), auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("date", models.DateField(verbose_name="date")),
("value", models.FloatField(verbose_name="valeur")),
(
"equipment",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="theoretical_maxs",
to="gym.Equipment",
verbose_name="machine",
),
),
], ],
options={ options={
'verbose_name': 'maximum théorique', "verbose_name": "maximum théorique",
'verbose_name_plural': 'maximums théoriques', "verbose_name_plural": "maximums théoriques",
}, },
), ),
migrations.AddField( migrations.AddField(
model_name='round', model_name="round",
name='session', name="session",
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='rounds', to='gym.Session', verbose_name='séance'), field=models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="rounds",
to="gym.Session",
verbose_name="séance",
),
), ),
migrations.AddField( migrations.AddField(
model_name='equipment', model_name="equipment",
name='room', name="room",
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='equipments', to='gym.Room', verbose_name='salle'), field=models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="equipments",
to="gym.Room",
verbose_name="salle",
),
), ),
] ]

View file

@ -5,34 +5,36 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [("gym", "0001_initial")]
('gym', '0001_initial'),
]
operations = [ operations = [
migrations.AlterField( migrations.AlterField(
model_name='room', model_name="room",
name='latitude', name="latitude",
field=models.DecimalField(blank=True, decimal_places=8, max_digits=11, verbose_name='latitude'), field=models.DecimalField(
blank=True, decimal_places=8, max_digits=11, verbose_name="latitude"
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='room', model_name="room",
name='longitude', name="longitude",
field=models.DecimalField(blank=True, decimal_places=8, max_digits=11, verbose_name='longitude'), field=models.DecimalField(
blank=True, decimal_places=8, max_digits=11, verbose_name="longitude"
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='room', model_name="room",
name='notes', name="notes",
field=models.TextField(blank=True, verbose_name='notes'), field=models.TextField(blank=True, verbose_name="notes"),
), ),
migrations.AlterField( migrations.AlterField(
model_name='round', model_name="round",
name='notes', name="notes",
field=models.TextField(blank=True, verbose_name='notes'), field=models.TextField(blank=True, verbose_name="notes"),
), ),
migrations.AlterField( migrations.AlterField(
model_name='session', model_name="session",
name='notes', name="notes",
field=models.TextField(blank=True, verbose_name='notes'), field=models.TextField(blank=True, verbose_name="notes"),
), ),
] ]

View file

@ -5,14 +5,12 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [("gym", "0002_auto_20180303_1201")]
('gym', '0002_auto_20180303_1201'),
]
operations = [ operations = [
migrations.AlterField( migrations.AlterField(
model_name='session', model_name="session",
name='date', name="date",
field=models.DateTimeField(verbose_name='date et heure de début'), field=models.DateTimeField(verbose_name="date et heure de début"),
), )
] ]

View file

@ -5,14 +5,8 @@ from django.db import migrations
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [("gym", "0003_auto_20180303_1801")]
('gym', '0003_auto_20180303_1801'),
]
operations = [ operations = [
migrations.RenameField( migrations.RenameField(model_name="session", old_name="date", new_name="start")
model_name='session',
old_name='date',
new_name='start',
),
] ]

View file

@ -5,19 +5,29 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [("gym", "0004_auto_20180303_1801")]
('gym', '0004_auto_20180303_1801'),
]
operations = [ operations = [
migrations.AlterField( migrations.AlterField(
model_name='room', model_name="room",
name='latitude', name="latitude",
field=models.DecimalField(blank=True, decimal_places=8, max_digits=11, null=True, verbose_name='latitude'), field=models.DecimalField(
blank=True,
decimal_places=8,
max_digits=11,
null=True,
verbose_name="latitude",
),
), ),
migrations.AlterField( migrations.AlterField(
model_name='room', model_name="room",
name='longitude', name="longitude",
field=models.DecimalField(blank=True, decimal_places=8, max_digits=11, null=True, verbose_name='longitude'), field=models.DecimalField(
blank=True,
decimal_places=8,
max_digits=11,
null=True,
verbose_name="longitude",
),
), ),
] ]

View file

@ -6,25 +6,33 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [("gym", "0005_auto_20180304_1025")]
('gym', '0005_auto_20180304_1025'),
]
operations = [ operations = [
migrations.CreateModel( migrations.CreateModel(
name='Unit', name="Unit",
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('name', models.CharField(max_length=50, verbose_name='nom')), "id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("name", models.CharField(max_length=50, verbose_name="nom")),
], ],
options={ options={"verbose_name": "unité", "verbose_name_plural": "unités"},
'verbose_name': 'unité',
'verbose_name_plural': 'unités',
},
), ),
migrations.AddField( migrations.AddField(
model_name='theoreticalmax', model_name="theoreticalmax",
name='unit', name="unit",
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, to='gym.Unit', verbose_name='unité'), field=models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.PROTECT,
to="gym.Unit",
verbose_name="unité",
),
), ),
] ]

View file

@ -6,18 +6,18 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [("gym", "0006_auto_20180304_2037")]
('gym', '0006_auto_20180304_2037'),
]
operations = [ operations = [
migrations.RemoveField( migrations.RemoveField(model_name="theoreticalmax", name="unit"),
model_name='theoreticalmax',
name='unit',
),
migrations.AddField( migrations.AddField(
model_name='equipment', model_name="equipment",
name='unit', name="unit",
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, to='gym.Unit', verbose_name='unité'), field=models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.PROTECT,
to="gym.Unit",
verbose_name="unité",
),
), ),
] ]

View file

@ -6,35 +6,53 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [("gym", "0007_auto_20180313_0857")]
('gym', '0007_auto_20180313_0857'),
]
operations = [ operations = [
migrations.CreateModel( migrations.CreateModel(
name='WorkForm', name="WorkForm",
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), (
('name', models.CharField(max_length=300, verbose_name='nom')), "id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("name", models.CharField(max_length=300, verbose_name="nom")),
], ],
options={ options={
'verbose_name': 'forme de travail', "verbose_name": "forme de travail",
'verbose_name_plural': 'formes de travail', "verbose_name_plural": "formes de travail",
}, },
), ),
migrations.AddField( migrations.AddField(
model_name='equipment', model_name="equipment",
name='default_repetition_number', name="default_repetition_number",
field=models.PositiveIntegerField(default=12, verbose_name='nombre de répétitions par défaut'), field=models.PositiveIntegerField(
default=12, verbose_name="nombre de répétitions par défaut"
),
), ),
migrations.AddField( migrations.AddField(
model_name='equipment', model_name="equipment",
name='default_work_form', name="default_work_form",
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='gym.WorkForm', verbose_name='forme de travail par défaut'), field=models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.SET_NULL,
to="gym.WorkForm",
verbose_name="forme de travail par défaut",
),
), ),
migrations.AddField( migrations.AddField(
model_name='round', model_name="round",
name='work_form', name="work_form",
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, to='gym.WorkForm', verbose_name='forme de travail'), field=models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.PROTECT,
to="gym.WorkForm",
verbose_name="forme de travail",
),
), ),
] ]

View file

@ -5,14 +5,14 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [("gym", "0008_auto_20180313_0913")]
('gym', '0008_auto_20180313_0913'),
]
operations = [ operations = [
migrations.AddField( migrations.AddField(
model_name='session', model_name="session",
name='default_theoretical_max_percentage', name="default_theoretical_max_percentage",
field=models.PositiveIntegerField(default=65, verbose_name='pourcentage par défaut'), field=models.PositiveIntegerField(
), default=65, verbose_name="pourcentage par défaut"
),
)
] ]

View file

@ -1,7 +1,7 @@
class SessionResetMixin: class SessionResetMixin:
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
if 'session_pk' in request.session: if "session_pk" in request.session:
del request.session['session_pk'] del request.session["session_pk"]
return super().dispatch(request, *args, **kwargs) return super().dispatch(request, *args, **kwargs)
@ -12,5 +12,5 @@ class QuickActionsMixin:
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
context['quick_actions'] = self.get_quick_actions() context["quick_actions"] = self.get_quick_actions()
return context return context

View file

@ -4,13 +4,17 @@ from django.db import models
class Room(models.Model): class Room(models.Model):
class Meta: class Meta:
verbose_name = 'salle' verbose_name = "salle"
verbose_name_plural = 'salles' verbose_name_plural = "salles"
name = models.CharField('nom', max_length=300) name = models.CharField("nom", max_length=300)
latitude = models.DecimalField('latitude', max_digits=11, decimal_places=8, blank=True, null=True) latitude = models.DecimalField(
longitude = models.DecimalField('longitude', max_digits=11, decimal_places=8, blank=True, null=True) "latitude", max_digits=11, decimal_places=8, blank=True, null=True
notes = models.TextField('notes', blank=True) )
longitude = models.DecimalField(
"longitude", max_digits=11, decimal_places=8, blank=True, null=True
)
notes = models.TextField("notes", blank=True)
def __str__(self): def __str__(self):
return self.name return self.name
@ -18,10 +22,10 @@ class Room(models.Model):
class Unit(models.Model): class Unit(models.Model):
class Meta: class Meta:
verbose_name = 'unité' verbose_name = "unité"
verbose_name_plural = 'unités' verbose_name_plural = "unités"
name = models.CharField('nom', max_length=50) name = models.CharField("nom", max_length=50)
def __str__(self): def __str__(self):
return self.name return self.name
@ -29,10 +33,10 @@ class Unit(models.Model):
class WorkForm(models.Model): class WorkForm(models.Model):
class Meta: class Meta:
verbose_name = 'forme de travail' verbose_name = "forme de travail"
verbose_name_plural = 'formes de travail' verbose_name_plural = "formes de travail"
name = models.CharField('nom', max_length=300) name = models.CharField("nom", max_length=300)
def __str__(self): def __str__(self):
return self.name return self.name
@ -40,122 +44,124 @@ class WorkForm(models.Model):
class Equipment(models.Model): class Equipment(models.Model):
class Meta: class Meta:
verbose_name = 'machine' verbose_name = "machine"
verbose_name_plural = 'machines' verbose_name_plural = "machines"
name = models.CharField('nom', max_length=300) name = models.CharField("nom", max_length=300)
room = models.ForeignKey( room = models.ForeignKey(
verbose_name='salle', verbose_name="salle",
to=Room, to=Room,
on_delete=models.SET_NULL, on_delete=models.SET_NULL,
related_name='equipments', related_name="equipments",
null=True null=True,
) )
unit = models.ForeignKey( unit = models.ForeignKey(
verbose_name='unité', verbose_name="unité", to=Unit, on_delete=models.PROTECT, null=True
to=Unit,
on_delete=models.PROTECT,
null=True
) )
default_work_form = models.ForeignKey( default_work_form = models.ForeignKey(
verbose_name='forme de travail par défaut', verbose_name="forme de travail par défaut",
to=WorkForm, to=WorkForm,
on_delete=models.SET_NULL, on_delete=models.SET_NULL,
null=True null=True,
)
default_repetition_number = models.PositiveIntegerField(
"nombre de répétitions par défaut", default=12
) )
default_repetition_number = models.PositiveIntegerField('nombre de répétitions par défaut', default=12)
@property @property
def last_theoretical_max(self): def last_theoretical_max(self):
return self.theoretical_maxs.order_by('-date', '-pk').first() return self.theoretical_maxs.order_by("-date", "-pk").first()
def __str__(self): def __str__(self):
return f'{self.name} ({self.room.name})' return f"{self.name} ({self.room.name})"
class Setting(models.Model): class Setting(models.Model):
class Meta: class Meta:
verbose_name = 'réglage' verbose_name = "réglage"
verbose_name_plural = 'réglages' verbose_name_plural = "réglages"
equipment = models.ForeignKey( equipment = models.ForeignKey(
verbose_name='machine', verbose_name="machine",
to=Equipment, to=Equipment,
on_delete=models.CASCADE, on_delete=models.CASCADE,
related_name='settings' related_name="settings",
) )
name = models.CharField('nom', max_length=200) name = models.CharField("nom", max_length=200)
value = models.CharField('valeur', max_length=200) value = models.CharField("valeur", max_length=200)
def __str__(self): def __str__(self):
return f'{self.name}={self.value}' return f"{self.name}={self.value}"
class TheoreticalMax(models.Model): class TheoreticalMax(models.Model):
class Meta: class Meta:
verbose_name = 'maximum théorique' verbose_name = "maximum théorique"
verbose_name_plural = 'maximums théoriques' verbose_name_plural = "maximums théoriques"
equipment = models.ForeignKey( equipment = models.ForeignKey(
verbose_name='machine', verbose_name="machine",
to=Equipment, to=Equipment,
on_delete=models.CASCADE, on_delete=models.CASCADE,
related_name='theoretical_maxs' related_name="theoretical_maxs",
) )
date = models.DateField('date') date = models.DateField("date")
value = models.FloatField('valeur') value = models.FloatField("valeur")
def __str__(self): def __str__(self):
return f'{self.value} {self.equipment.unit.name} le {self.date:%d/%m/%Y}' return f"{self.value} {self.equipment.unit.name} le {self.date:%d/%m/%Y}"
class Session(models.Model): class Session(models.Model):
class Meta: class Meta:
verbose_name = 'séance' verbose_name = "séance"
verbose_name_plural = 'séances' verbose_name_plural = "séances"
start = models.DateTimeField('date et heure de début') start = models.DateTimeField("date et heure de début")
room = models.ForeignKey( room = models.ForeignKey(
verbose_name='salle', verbose_name="salle",
to=Room, to=Room,
on_delete=models.SET_NULL, on_delete=models.SET_NULL,
related_name='sessions', related_name="sessions",
null=True null=True,
) )
default_theoretical_max_percentage = models.PositiveIntegerField('pourcentage par défaut', default=65) default_theoretical_max_percentage = models.PositiveIntegerField(
notes = models.TextField('notes', blank=True) "pourcentage par défaut", default=65
)
notes = models.TextField("notes", blank=True)
def __str__(self): def __str__(self):
import pytz import pytz
server_timezone = pytz.timezone(settings.TIME_ZONE) server_timezone = pytz.timezone(settings.TIME_ZONE)
server = server_timezone.normalize(self.start.astimezone(server_timezone)) server = server_timezone.normalize(self.start.astimezone(server_timezone))
return f'{self.room} {server:%d/%m/%Y %H:%M} ({settings.TIME_ZONE})' return f"{self.room} {server:%d/%m/%Y %H:%M} ({settings.TIME_ZONE})"
class Round(models.Model): class Round(models.Model):
class Meta: class Meta:
verbose_name = 'série' verbose_name = "série"
verbose_name_plural = 'séries' verbose_name_plural = "séries"
repetition_number = models.PositiveIntegerField('nombre de répétitions') repetition_number = models.PositiveIntegerField("nombre de répétitions")
equipment = models.ForeignKey( equipment = models.ForeignKey(
verbose_name='machine', verbose_name="machine",
to=Equipment, to=Equipment,
on_delete=models.CASCADE, on_delete=models.CASCADE,
related_name='rounds' related_name="rounds",
) )
theoretical_max_percentage = models.PositiveIntegerField('pourcentage') theoretical_max_percentage = models.PositiveIntegerField("pourcentage")
chosen_weight = models.FloatField('charge choisie') chosen_weight = models.FloatField("charge choisie")
session = models.ForeignKey( session = models.ForeignKey(
verbose_name='séance', verbose_name="séance",
to=Session, to=Session,
on_delete=models.CASCADE, on_delete=models.CASCADE,
related_name='rounds' related_name="rounds",
) )
work_form = models.ForeignKey( work_form = models.ForeignKey(
verbose_name='forme de travail', verbose_name="forme de travail",
to=WorkForm, to=WorkForm,
on_delete=models.PROTECT, on_delete=models.PROTECT,
null=True null=True,
) )
notes = models.TextField('notes', blank=True) notes = models.TextField("notes", blank=True)

View file

@ -5,20 +5,39 @@ from . import views
# Wire up our API using automatic URL routing. # Wire up our API using automatic URL routing.
# Additionally, we include login URLs for the browsable API. # Additionally, we include login URLs for the browsable API.
urlpatterns = [ urlpatterns = [
path('', views.RoomListView.as_view(), name='rooms-list'), path("", views.RoomListView.as_view(), name="rooms-list"),
path('rooms/<int:pk>/', views.RoomDetailView.as_view(), name='room-detail'), path("rooms/<int:pk>/", views.RoomDetailView.as_view(), name="room-detail"),
path('equipment/add/', views.EquipmentCreateView.as_view(), name='equipment-create'), path(
path('equipment/<int:pk>/', views.EquipmentDetailView.as_view(), name='equipment-detail'), "equipment/add/", views.EquipmentCreateView.as_view(), name="equipment-create"
path('equipment/<int:pk>/maxs', views.TheoreticalMaxListView.as_view(), name='theoretical-max-list'), ),
path('setting/add/', views.SettingCreateView.as_view(), name='setting-create'), path(
path('setting/<int:pk>/', views.SettingUpdateView.as_view(), name='setting-edit'), "equipment/<int:pk>/",
path('setting/<int:pk>/delete/', views.SettingDeleteView.as_view(), name='setting-delete'), views.EquipmentDetailView.as_view(),
path('session/start/', views.SessionCreateView.as_view(), name='session-start'), name="equipment-detail",
path('session/<int:pk>/', views.SessionDetailView.as_view(), name='session-detail'), ),
path('round/add/', views.RoundCreateView.as_view(), name='round-create'), path(
path('round/<int:pk>/', views.RoundUpdateView.as_view(), name='round-edit'), "equipment/<int:pk>/maxs",
path('round/<int:pk>/delete/', views.RoundDeleteView.as_view(), name='round-delete'), views.TheoreticalMaxListView.as_view(),
path('theoretical-max/add/', views.TheoreticalMaxCreateView.as_view(), name='theoretical-max-create'), name="theoretical-max-list",
),
path("setting/add/", views.SettingCreateView.as_view(), name="setting-create"),
path("setting/<int:pk>/", views.SettingUpdateView.as_view(), name="setting-edit"),
path(
"setting/<int:pk>/delete/",
views.SettingDeleteView.as_view(),
name="setting-delete",
),
path("session/start/", views.SessionCreateView.as_view(), name="session-start"),
path("session/<int:pk>/", views.SessionDetailView.as_view(), name="session-detail"),
path("round/add/", views.RoundCreateView.as_view(), name="round-create"),
path("round/<int:pk>/", views.RoundUpdateView.as_view(), name="round-edit"),
path(
"round/<int:pk>/delete/", views.RoundDeleteView.as_view(), name="round-delete"
),
path(
"theoretical-max/add/",
views.TheoreticalMaxCreateView.as_view(),
name="theoretical-max-create",
),
# path('session/<int:pk>/delete/', views.SessionDeleteView.as_view(), name='session-delete'), # path('session/<int:pk>/delete/', views.SessionDeleteView.as_view(), name='session-delete'),
] ]

View file

@ -12,120 +12,145 @@ from gym.models import Room, Equipment, Setting, Session, Round, TheoreticalMax
class RoomListView(LoginRequiredMixin, SessionResetMixin, generic.ListView): class RoomListView(LoginRequiredMixin, SessionResetMixin, generic.ListView):
queryset = Room.objects.all().order_by('name') queryset = Room.objects.all().order_by("name")
context_object_name = 'rooms' context_object_name = "rooms"
template_name = 'gym/rooms.html' template_name = "gym/rooms.html"
class RoomDetailView(LoginRequiredMixin, QuickActionsMixin, SessionResetMixin, generic.DetailView): class RoomDetailView(
LoginRequiredMixin, QuickActionsMixin, SessionResetMixin, generic.DetailView
):
model = Room model = Room
context_object_name = 'room' context_object_name = "room"
template_name = 'gym/room.html' template_name = "gym/room.html"
def get_quick_actions(self): def get_quick_actions(self):
quick_actions = [ quick_actions = [
{ {
'url': reverse('rooms-list'), "url": reverse("rooms-list"),
'category': 'secondary', "category": "secondary",
'display': 'Liste des salles' "display": "Liste des salles",
}, },
{ {
'url': "{}?room={}".format(reverse('session-start'), self.object.pk), "url": "{}?room={}".format(reverse("session-start"), self.object.pk),
'category': 'primary', "category": "primary",
'display': 'Commencer une séance' "display": "Commencer une séance",
}, },
{ {
'url': "{}?room={}".format(reverse('equipment-create'), self.object.pk), "url": "{}?room={}".format(reverse("equipment-create"), self.object.pk),
'category': 'success', "category": "success",
'display': 'Ajouter une machine' "display": "Ajouter une machine",
}, },
] ]
if self.object.latitude and self.object.longitude: if self.object.latitude and self.object.longitude:
from user_agents import parse from user_agents import parse
user_agent = parse(self.request.META.get('HTTP_USER_AGENT'))
user_agent = parse(self.request.META.get("HTTP_USER_AGENT"))
if user_agent.is_mobile: if user_agent.is_mobile:
url = f"waze://?ll={self.object.latitude},{self.object.longitude}&navigate=yes" url = f"waze://?ll={self.object.latitude},{self.object.longitude}&navigate=yes"
name = 'Waze' name = "Waze"
quick_actions.append({ quick_actions.append(
'url': f"here-location://{self.object.latitude},{self.object.longitude}", {
'category': 'info', "url": f"here-location://{self.object.latitude},{self.object.longitude}",
'display': 'Here WeGo', "category": "info",
'icon': 'fas fa-location-arrow', "display": "Here WeGo",
}) "icon": "fas fa-location-arrow",
}
)
else: else:
url = (f"https://www.google.com/maps/place/{self.object.latitude},{self.object.longitude}" url = (
f"/@{self.object.latitude},{self.object.longitude},18z") f"https://www.google.com/maps/place/{self.object.latitude},{self.object.longitude}"
name = 'Google Maps' f"/@{self.object.latitude},{self.object.longitude},18z"
)
name = "Google Maps"
quick_actions.append({ quick_actions.append(
'url': url, {
'category': 'info', "url": url,
'display': name, "category": "info",
'icon': 'fas fa-location-arrow', "display": name,
}) "icon": "fas fa-location-arrow",
}
)
return quick_actions return quick_actions
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
context['sessions'] = self.object.sessions.all().order_by('-start') context["sessions"] = self.object.sessions.all().order_by("-start")
return context return context
class EquipmentDetailView(LoginRequiredMixin, QuickActionsMixin, generic.DetailView): class EquipmentDetailView(LoginRequiredMixin, QuickActionsMixin, generic.DetailView):
model = Equipment model = Equipment
context_object_name = 'equipment' context_object_name = "equipment"
template_name = 'gym/equipment.html' template_name = "gym/equipment.html"
session = None session = None
def get_quick_actions(self): def get_quick_actions(self):
lst = [] lst = []
if self.session: if self.session:
lst.extend([ lst.extend(
[
{
"url": reverse("session-detail", args=(self.session.pk,)),
"category": "secondary",
"display": "Retourner à la séance",
},
{
"url": "{}?equipment={}".format(
reverse("round-create"), self.object.pk
),
"category": "primary",
"display": "Commencer une série",
},
]
)
else:
lst.append(
{ {
'url': reverse('session-detail', args=(self.session.pk,)), "url": reverse("room-detail", args=(self.object.room.pk,)),
'category': 'secondary', "category": "secondary",
'display': 'Retourner à la séance' "display": "Retourner à la salle",
}
)
lst.extend(
[
{
"url": "{}?equipment={}".format(
reverse("setting-create"), self.object.pk
),
"category": "success",
"display": "Ajouter un réglage",
}, },
{ {
'url': '{}?equipment={}'.format(reverse('round-create'), self.object.pk), "url": "{}?equipment={}".format(
'category': 'primary', reverse("theoretical-max-create"), self.object.pk
'display': 'Commencer une série' ),
} "category": "success",
]) "display": "Ajouter un max théorique",
else: },
lst.append({ ]
'url': reverse('room-detail', args=(self.object.room.pk,)), )
'category': 'secondary',
'display': 'Retourner à la salle'
})
lst.extend([
{
'url': '{}?equipment={}'.format(reverse('setting-create'), self.object.pk),
'category': 'success',
'display': 'Ajouter un réglage'
},
{
'url': '{}?equipment={}'.format(reverse('theoretical-max-create'), self.object.pk),
'category': 'success',
'display': 'Ajouter un max théorique'
}
])
if self.request.user.is_staff: if self.request.user.is_staff:
lst.append({ lst.append(
'url': reverse('admin:gym_equipment_change', args=(self.object.pk,)), {
'category': 'warning', "url": reverse(
'display': 'Éditer la machine' "admin:gym_equipment_change", args=(self.object.pk,)
}) ),
"category": "warning",
"display": "Éditer la machine",
}
)
return lst return lst
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
session_pk = self.request.session.get('session_pk') session_pk = self.request.session.get("session_pk")
if session_pk: if session_pk:
self.session = Session.objects.get(pk=session_pk) self.session = Session.objects.get(pk=session_pk)
return super().dispatch(request, *args, **kwargs) return super().dispatch(request, *args, **kwargs)
@ -133,36 +158,38 @@ class EquipmentDetailView(LoginRequiredMixin, QuickActionsMixin, generic.DetailV
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
if self.session: if self.session:
context['session'] = self.session.pk context["session"] = self.session.pk
context['rounds'] = Round.objects.filter(session=self.session, equipment=self.get_object()) context["rounds"] = Round.objects.filter(
session=self.session, equipment=self.get_object()
)
return context return context
class EquipmentCreateView(LoginRequiredMixin, QuickActionsMixin, generic.CreateView): class EquipmentCreateView(LoginRequiredMixin, QuickActionsMixin, generic.CreateView):
model = Equipment model = Equipment
fields = ['room', 'name', 'default_work_form', 'unit', 'default_repetition_number'] fields = ["room", "name", "default_work_form", "unit", "default_repetition_number"]
template_name = 'gym/equipment_edit.html' template_name = "gym/equipment_edit.html"
room = None room = None
def get_quick_actions(self): def get_quick_actions(self):
return [ return [
{ {
'url': reverse('room-detail', args=(self.room.pk,)), "url": reverse("room-detail", args=(self.room.pk,)),
'category': 'secondary', "category": "secondary",
'display': 'Retourner à la salle' "display": "Retourner à la salle",
}, }
] ]
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
context['room'] = self.room context["room"] = self.room
return context return context
def get_success_url(self): def get_success_url(self):
return reverse('equipment-detail', kwargs={'pk': self.object.pk}) return reverse("equipment-detail", kwargs={"pk": self.object.pk})
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
default_room_id = self.request.GET.get('room') default_room_id = self.request.GET.get("room")
if default_room_id: if default_room_id:
self.room = get_object_or_404(Room, pk=default_room_id) self.room = get_object_or_404(Room, pk=default_room_id)
@ -170,34 +197,34 @@ class EquipmentCreateView(LoginRequiredMixin, QuickActionsMixin, generic.CreateV
def get_initial(self): def get_initial(self):
initial = super().get_initial() initial = super().get_initial()
initial['room'] = self.room initial["room"] = self.room
return initial return initial
class SettingCreateView(LoginRequiredMixin, QuickActionsMixin, generic.CreateView): class SettingCreateView(LoginRequiredMixin, QuickActionsMixin, generic.CreateView):
model = Setting model = Setting
fields = ['equipment', 'name', 'value'] fields = ["equipment", "name", "value"]
template_name = 'gym/setting_edit.html' template_name = "gym/setting_edit.html"
equipment = None equipment = None
def get_quick_actions(self): def get_quick_actions(self):
return [ return [
{ {
'url': reverse('equipment-detail', args=(self.equipment.pk,)), "url": reverse("equipment-detail", args=(self.equipment.pk,)),
'category': 'secondary', "category": "secondary",
'display': 'Retourner à la machine' "display": "Retourner à la machine",
}, }
] ]
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
context['title'] = 'Ajouter' context["title"] = "Ajouter"
context['equipment'] = self.equipment context["equipment"] = self.equipment
return context return context
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
default_equipment_id = self.request.GET.get('equipment') default_equipment_id = self.request.GET.get("equipment")
if default_equipment_id: if default_equipment_id:
self.equipment = get_object_or_404(Equipment, pk=default_equipment_id) self.equipment = get_object_or_404(Equipment, pk=default_equipment_id)
@ -205,81 +232,84 @@ class SettingCreateView(LoginRequiredMixin, QuickActionsMixin, generic.CreateVie
def get_initial(self): def get_initial(self):
initial = super().get_initial() initial = super().get_initial()
initial['equipment'] = self.equipment initial["equipment"] = self.equipment
return initial return initial
def get_success_url(self): def get_success_url(self):
return reverse('equipment-detail', kwargs={'pk': self.object.equipment.pk}) return reverse("equipment-detail", kwargs={"pk": self.object.equipment.pk})
class SettingUpdateView(LoginRequiredMixin, QuickActionsMixin, generic.UpdateView): class SettingUpdateView(LoginRequiredMixin, QuickActionsMixin, generic.UpdateView):
model = Setting model = Setting
fields = ['equipment', 'name', 'value'] fields = ["equipment", "name", "value"]
template_name = 'gym/setting_edit.html' template_name = "gym/setting_edit.html"
def get_quick_actions(self): def get_quick_actions(self):
return [ return [
{ {
'url': reverse('equipment-detail', args=(self.object.equipment.pk,)), "url": reverse("equipment-detail", args=(self.object.equipment.pk,)),
'category': 'secondary', "category": "secondary",
'display': 'Retourner à la machine' "display": "Retourner à la machine",
}, }
] ]
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
context['edit'] = True context["edit"] = True
context['title'] = 'Modifier' context["title"] = "Modifier"
context['equipment'] = self.object.equipment context["equipment"] = self.object.equipment
return context return context
def get_success_url(self): def get_success_url(self):
return reverse('equipment-detail', kwargs={'pk': self.object.equipment.pk}) return reverse("equipment-detail", kwargs={"pk": self.object.equipment.pk})
class SettingDeleteView(LoginRequiredMixin, generic.DeleteView): class SettingDeleteView(LoginRequiredMixin, generic.DeleteView):
model = Setting model = Setting
template_name = 'gym/confirm_delete.html' template_name = "gym/confirm_delete.html"
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
context['article'] = 'une' context["article"] = "une"
context['name'] = 'série' context["name"] = "série"
context['message'] = ('Êtes-vous sûr de vouloir supprimer le réglage ' context["message"] = (
'<code>{}</code> pour la machine "{}" ?'.format( "Êtes-vous sûr de vouloir supprimer le réglage "
self.object, '<code>{}</code> pour la machine "{}" ?'.format(
self.object.equipment, self.object, self.object.equipment
)) )
)
return context return context
def get_success_url(self): def get_success_url(self):
return reverse('equipment-detail', kwargs={'pk': self.object.equipment.pk}) return reverse("equipment-detail", kwargs={"pk": self.object.equipment.pk})
class TheoreticalMaxCreateView(LoginRequiredMixin, QuickActionsMixin, generic.CreateView): class TheoreticalMaxCreateView(
LoginRequiredMixin, QuickActionsMixin, generic.CreateView
):
model = TheoreticalMax model = TheoreticalMax
fields = ['equipment', 'date', 'value'] fields = ["equipment", "date", "value"]
template_name = 'gym/theoretical_max_edit.html' template_name = "gym/theoretical_max_edit.html"
equipment = None equipment = None
def get_quick_actions(self): def get_quick_actions(self):
return [ return [
{ {
'url': reverse('equipment-detail', args=(self.equipment.pk,)), "url": reverse("equipment-detail", args=(self.equipment.pk,)),
'category': 'secondary', "category": "secondary",
'display': 'Retourner à la machine' "display": "Retourner à la machine",
}, }
] ]
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
context['title'] = 'Ajouter' context["title"] = "Ajouter"
context['equipment'] = self.equipment context["equipment"] = self.equipment
return context return context
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
default_equipment_id = self.request.GET.get('equipment') default_equipment_id = self.request.GET.get("equipment")
if default_equipment_id: if default_equipment_id:
self.equipment = get_object_or_404(Equipment, pk=default_equipment_id) self.equipment = get_object_or_404(Equipment, pk=default_equipment_id)
@ -287,41 +317,43 @@ class TheoreticalMaxCreateView(LoginRequiredMixin, QuickActionsMixin, generic.Cr
def get_initial(self): def get_initial(self):
initial = super().get_initial() initial = super().get_initial()
initial['equipment'] = self.equipment initial["equipment"] = self.equipment
initial['date'] = datetime.date.today() initial["date"] = datetime.date.today()
return initial return initial
def get_success_url(self): def get_success_url(self):
return reverse('theoretical-max-list', kwargs={'pk': self.object.equipment.pk}) return reverse("theoretical-max-list", kwargs={"pk": self.object.equipment.pk})
class TheoreticalMaxListView(LoginRequiredMixin, QuickActionsMixin, generic.ListView): class TheoreticalMaxListView(LoginRequiredMixin, QuickActionsMixin, generic.ListView):
model = TheoreticalMax model = TheoreticalMax
template_name = 'gym/theoretical_max_list.html' template_name = "gym/theoretical_max_list.html"
context_object_name = 'maxs' context_object_name = "maxs"
equipment = None equipment = None
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
pk = self.kwargs.pop('pk') pk = self.kwargs.pop("pk")
self.equipment = get_object_or_404(Equipment, pk=pk) self.equipment = get_object_or_404(Equipment, pk=pk)
return super().dispatch(request, *args, **kwargs) return super().dispatch(request, *args, **kwargs)
def get_queryset(self): def get_queryset(self):
return TheoreticalMax.objects.filter(equipment=self.equipment).order_by('date') return TheoreticalMax.objects.filter(equipment=self.equipment).order_by("date")
def get_quick_actions(self): def get_quick_actions(self):
return [ return [
{ {
'url': reverse('equipment-detail', args=(self.equipment.pk,)), "url": reverse("equipment-detail", args=(self.equipment.pk,)),
'category': 'secondary', "category": "secondary",
'display': 'Retourner à la machine' "display": "Retourner à la machine",
}, },
{ {
'url': '{}?equipment={}'.format(reverse('theoretical-max-create'), self.equipment.pk), "url": "{}?equipment={}".format(
'category': 'success', reverse("theoretical-max-create"), self.equipment.pk
'display': 'Ajouter un max théorique' ),
"category": "success",
"display": "Ajouter un max théorique",
}, },
] ]
@ -332,69 +364,71 @@ class TheoreticalMaxListView(LoginRequiredMixin, QuickActionsMixin, generic.List
go.Scatter( go.Scatter(
x=[max.date for max in self.get_queryset()], x=[max.date for max in self.get_queryset()],
y=[max.value for max in self.get_queryset()], y=[max.value for max in self.get_queryset()],
), )
] ]
layout = go.Layout( layout = go.Layout(
title="Évolution du max théorique", title="Évolution du max théorique",
yaxis={"title": "Charge ({})".format(self.equipment.unit.name)}, yaxis={"title": "Charge ({})".format(self.equipment.unit.name)},
xaxis={"title": "Date"}, xaxis={"title": "Date"},
) )
figure = {"data": data, "layout": layout, } figure = {"data": data, "layout": layout}
graph = plotly.offline.plot(figure, auto_open=False, output_type='div') graph = plotly.offline.plot(figure, auto_open=False, output_type="div")
context['graph'] = graph context["graph"] = graph
context['equipment'] = self.equipment context["equipment"] = self.equipment
return context return context
class SessionCreateView(LoginRequiredMixin, QuickActionsMixin, generic.CreateView): class SessionCreateView(LoginRequiredMixin, QuickActionsMixin, generic.CreateView):
model = Session model = Session
fields = ['room', 'start', 'default_theoretical_max_percentage'] fields = ["room", "start", "default_theoretical_max_percentage"]
template_name = 'gym/session_edit.html' template_name = "gym/session_edit.html"
room = None room = None
def get_quick_actions(self): def get_quick_actions(self):
room_pk = self.room.pk room_pk = self.room.pk
return [ return [
{ {
'url': reverse('room-detail', args=(room_pk,)), "url": reverse("room-detail", args=(room_pk,)),
'category': 'secondary', "category": "secondary",
'display': 'Retourner à la salle' "display": "Retourner à la salle",
}, }
] ]
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
context['title'] = 'Démarrer' context["title"] = "Démarrer"
context['room'] = self.room context["room"] = self.room
return context return context
def get_success_url(self): def get_success_url(self):
return reverse('session-detail', kwargs={'pk': self.object.pk}) return reverse("session-detail", kwargs={"pk": self.object.pk})
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
self.room = get_object_or_404(Room, pk=self.request.GET.get('room')) self.room = get_object_or_404(Room, pk=self.request.GET.get("room"))
return super().dispatch(request, *args, **kwargs) return super().dispatch(request, *args, **kwargs)
def get_initial(self): def get_initial(self):
initial = super().get_initial() initial = super().get_initial()
initial['room'] = self.room initial["room"] = self.room
initial['start'] = datetime.datetime.now() initial["start"] = datetime.datetime.now()
return initial return initial
class SessionDetailView(LoginRequiredMixin, QuickActionsMixin, generic.DetailView): class SessionDetailView(LoginRequiredMixin, QuickActionsMixin, generic.DetailView):
model = Session model = Session
context_object_name = 'session' context_object_name = "session"
template_name = 'gym/session_detail.html' template_name = "gym/session_detail.html"
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
session = self.get_object() session = self.get_object()
context['used_equipments'] = {k: Round.objects.filter(equipment=k, session=session).count() context["used_equipments"] = {
for k in Equipment.objects.filter(rounds__session=self.get_object())} k: Round.objects.filter(equipment=k, session=session).count()
for k in Equipment.objects.filter(rounds__session=self.get_object())
}
return context return context
@ -402,48 +436,57 @@ class SessionDetailView(LoginRequiredMixin, QuickActionsMixin, generic.DetailVie
room_pk = self.get_object().room.pk room_pk = self.get_object().room.pk
return [ return [
{ {
'url': reverse('room-detail', args=(room_pk,)), "url": reverse("room-detail", args=(room_pk,)),
'category': 'secondary', "category": "secondary",
'display': 'Retourner à la salle' "display": "Retourner à la salle",
}, },
{ {
'url': "{}?room={}".format(reverse('equipment-create'), room_pk), "url": "{}?room={}".format(reverse("equipment-create"), room_pk),
'category': 'success', "category": "success",
'display': 'Ajouter une machine' "display": "Ajouter une machine",
}, },
] ]
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
request.session['session_pk'] = self.get_object().pk request.session["session_pk"] = self.get_object().pk
return super().dispatch(request, *args, **kwargs) return super().dispatch(request, *args, **kwargs)
class RoundCreateView(LoginRequiredMixin, QuickActionsMixin, generic.CreateView): class RoundCreateView(LoginRequiredMixin, QuickActionsMixin, generic.CreateView):
model = Round model = Round
fields = ['equipment', 'session', 'theoretical_max_percentage', 'chosen_weight', fields = [
'repetition_number', 'work_form', 'notes'] "equipment",
template_name = 'gym/round_edit.html' "session",
"theoretical_max_percentage",
"chosen_weight",
"repetition_number",
"work_form",
"notes",
]
template_name = "gym/round_edit.html"
equipment = None equipment = None
session = None session = None
def get_quick_actions(self): def get_quick_actions(self):
return [ return [
{ {
'url': reverse('equipment-detail', args=(self.equipment.pk,)), "url": reverse("equipment-detail", args=(self.equipment.pk,)),
'category': 'secondary', "category": "secondary",
'display': 'Retourner à la machine' "display": "Retourner à la machine",
}, }
] ]
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
context['title'] = 'Commencer' context["title"] = "Commencer"
context['equipment'] = self.equipment context["equipment"] = self.equipment
return context return context
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
self.equipment = get_object_or_404(Equipment, pk=self.request.GET.get('equipment')) self.equipment = get_object_or_404(
session_pk = self.request.session.get('session_pk') Equipment, pk=self.request.GET.get("equipment")
)
session_pk = self.request.session.get("session_pk")
if session_pk: if session_pk:
self.session = Session.objects.get(pk=session_pk) self.session = Session.objects.get(pk=session_pk)
@ -452,73 +495,88 @@ class RoundCreateView(LoginRequiredMixin, QuickActionsMixin, generic.CreateView)
def get_initial(self): def get_initial(self):
theoretical_max_percentage = self.session.default_theoretical_max_percentage theoretical_max_percentage = self.session.default_theoretical_max_percentage
initial = super().get_initial() initial = super().get_initial()
initial['equipment'] = self.equipment initial["equipment"] = self.equipment
initial['session'] = self.session initial["session"] = self.session
last_round = self.equipment.rounds.filter(session=self.session).last() # type: Round last_round = self.equipment.rounds.filter(
initial['theoretical_max_percentage'] = theoretical_max_percentage session=self.session
).last() # type: Round
initial["theoretical_max_percentage"] = theoretical_max_percentage
if last_round: if last_round:
initial['repetition_number'] = last_round.repetition_number initial["repetition_number"] = last_round.repetition_number
initial['work_form'] = last_round.work_form initial["work_form"] = last_round.work_form
initial['chosen_weight'] = last_round.chosen_weight initial["chosen_weight"] = last_round.chosen_weight
else: else:
initial['repetition_number'] = self.equipment.default_repetition_number or 12 initial["repetition_number"] = (
initial['work_form'] = self.equipment.default_work_form self.equipment.default_repetition_number or 12
)
initial["work_form"] = self.equipment.default_work_form
proposed_weight = 0 proposed_weight = 0
theoretical_max = self.equipment.last_theoretical_max theoretical_max = self.equipment.last_theoretical_max
if theoretical_max: if theoretical_max:
proposed_weight = theoretical_max.value * theoretical_max_percentage / 100 proposed_weight = (
initial['chosen_weight'] = proposed_weight theoretical_max.value * theoretical_max_percentage / 100
)
initial["chosen_weight"] = proposed_weight
return initial return initial
def get_success_url(self): def get_success_url(self):
return reverse('equipment-detail', kwargs={'pk': self.object.equipment.pk}) return reverse("equipment-detail", kwargs={"pk": self.object.equipment.pk})
class RoundUpdateView(LoginRequiredMixin, QuickActionsMixin, generic.UpdateView): class RoundUpdateView(LoginRequiredMixin, QuickActionsMixin, generic.UpdateView):
model = Round model = Round
fields = ['equipment', 'session', 'theoretical_max_percentage', 'chosen_weight', fields = [
'repetition_number', 'work_form', 'notes'] "equipment",
template_name = 'gym/round_edit.html' "session",
"theoretical_max_percentage",
"chosen_weight",
"repetition_number",
"work_form",
"notes",
]
template_name = "gym/round_edit.html"
def get_quick_actions(self): def get_quick_actions(self):
return [ return [
{ {
'url': reverse('equipment-detail', args=(self.object.equipment.pk,)), "url": reverse("equipment-detail", args=(self.object.equipment.pk,)),
'category': 'secondary', "category": "secondary",
'display': 'Retourner à la machine' "display": "Retourner à la machine",
}, }
] ]
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
context['edit'] = True context["edit"] = True
context['title'] = 'Modifier' context["title"] = "Modifier"
context['equipment'] = self.object.equipment context["equipment"] = self.object.equipment
return context return context
def get_success_url(self): def get_success_url(self):
return reverse('equipment-detail', kwargs={'pk': self.object.equipment.pk}) return reverse("equipment-detail", kwargs={"pk": self.object.equipment.pk})
class RoundDeleteView(LoginRequiredMixin, generic.DeleteView): class RoundDeleteView(LoginRequiredMixin, generic.DeleteView):
model = Round model = Round
template_name = 'gym/confirm_delete.html' template_name = "gym/confirm_delete.html"
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
context['article'] = 'une' context["article"] = "une"
context['name'] = 'série' context["name"] = "série"
context['message'] = ('Êtes-vous sûr de vouloir supprimer ' context["message"] = (
'la série <code>{}, {}x{}{}</code> pour la séance "{}" ?'.format( "Êtes-vous sûr de vouloir supprimer "
self.object.equipment, 'la série <code>{}, {}x{}{}</code> pour la séance "{}" ?'.format(
self.object.repetition_number, self.object.equipment,
self.object.chosen_weight, self.object.repetition_number,
self.object.equipment.unit, self.object.chosen_weight,
self.object.session self.object.equipment.unit,
)) self.object.session,
)
)
return context return context
def get_success_url(self): def get_success_url(self):
return reverse('equipment-detail', kwargs={'pk': self.object.equipment.pk}) return reverse("equipment-detail", kwargs={"pk": self.object.equipment.pk})

View file

@ -5,11 +5,11 @@ import requests
def main(): def main():
port = os.getenv('PORT', 8000) port = os.getenv("PORT", 8000)
res = requests.get(f'http://127.0.0.1:{port}/') res = requests.get(f"http://127.0.0.1:{port}/")
if res.status_code >= 400: if res.status_code >= 400:
sys.exit(1) sys.exit(1)
if __name__ == '__main__': if __name__ == "__main__":
main() main()

View file

@ -21,79 +21,80 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# See https://docs.djangoproject.com/en/2.0/howto/deployment/checklist/ # See https://docs.djangoproject.com/en/2.0/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret! # SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = os.getenv('SECRET_KEY', 'x*8q7sd14&a%cu95$h@jl&&#bb&j(j*-6h5!3atz*v%!zo3hd4') SECRET_KEY = os.getenv(
"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! # SECURITY WARNING: don't run with debug turned on in production!
DEBUG = os.getenv('DJANGO_ENV', 'prod') == 'dev' DEBUG = os.getenv("DJANGO_ENV", "prod") == "dev"
ALLOWED_HOSTS = ['workout.augendre.info', 'web', 'workout', '127.0.0.1'] ALLOWED_HOSTS = ["workout.augendre.info", "web", "workout", "127.0.0.1"]
if DEBUG: if DEBUG:
ALLOWED_HOSTS.extend([ ALLOWED_HOSTS.extend(["localhost", os.getenv("CURRENT_IP", "192.168.1.27")])
'localhost', host = os.getenv("HOST", None)
os.getenv('CURRENT_IP', '192.168.1.27')
])
host = os.getenv('HOST', None)
if host: if host:
ALLOWED_HOSTS.append(host) ALLOWED_HOSTS.append(host)
ADMINS = [('Gabriel', os.getenv('ADMIN_EMAIL')), ] ADMINS = [("Gabriel", os.getenv("ADMIN_EMAIL"))]
SERVER_EMAIL = os.getenv('SERVER_EMAIL') SERVER_EMAIL = os.getenv("SERVER_EMAIL")
EMAIL_SUBJECT_PREFIX = '[Workout] ' EMAIL_SUBJECT_PREFIX = "[Workout] "
# Application definition # Application definition
INSTALLED_APPS = [ INSTALLED_APPS = [
'whitenoise.runserver_nostatic', "whitenoise.runserver_nostatic",
'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.contrib.humanize', "django.contrib.humanize",
'gym', "gym",
'bootstrap4', "bootstrap4",
] ]
MIDDLEWARE = [ MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware', "django.middleware.security.SecurityMiddleware",
'whitenoise.middleware.WhiteNoiseMiddleware', "whitenoise.middleware.WhiteNoiseMiddleware",
'django.contrib.sessions.middleware.SessionMiddleware', "django.contrib.sessions.middleware.SessionMiddleware",
'django.middleware.common.CommonMiddleware', "django.middleware.common.CommonMiddleware",
'django.middleware.csrf.CsrfViewMiddleware', "django.middleware.csrf.CsrfViewMiddleware",
'django.contrib.auth.middleware.AuthenticationMiddleware', "django.contrib.auth.middleware.AuthenticationMiddleware",
'django.contrib.messages.middleware.MessageMiddleware', "django.contrib.messages.middleware.MessageMiddleware",
'django.middleware.clickjacking.XFrameOptionsMiddleware', "django.middleware.clickjacking.XFrameOptionsMiddleware",
'django.middleware.http.ConditionalGetMiddleware', "django.middleware.http.ConditionalGetMiddleware",
] ]
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage' STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage"
ROOT_URLCONF = 'workout.urls' ROOT_URLCONF = "workout.urls"
TEMPLATES = [ TEMPLATES = [
{ {
'BACKEND': 'django.template.backends.django.DjangoTemplates', "BACKEND": "django.template.backends.django.DjangoTemplates",
'DIRS': [], "DIRS": [],
'APP_DIRS': True, "APP_DIRS": True,
'OPTIONS': { "OPTIONS": {
'context_processors': [ "context_processors": [
'django.template.context_processors.debug', "django.template.context_processors.debug",
'django.template.context_processors.request', "django.template.context_processors.request",
'django.contrib.auth.context_processors.auth', "django.contrib.auth.context_processors.auth",
'django.contrib.messages.context_processors.messages', "django.contrib.messages.context_processors.messages",
], ]
}, },
}, }
] ]
WSGI_APPLICATION = 'workout.wsgi.application' WSGI_APPLICATION = "workout.wsgi.application"
# Database # Database
# https://docs.djangoproject.com/en/2.0/ref/settings/#databases # https://docs.djangoproject.com/en/2.0/ref/settings/#databases
DATABASES = { DATABASES = {
'default': dj_database_url.config(default='sqlite:///' + os.path.join(BASE_DIR, 'db.sqlite3'), conn_max_age=600) "default": dj_database_url.config(
default="sqlite:///" + os.path.join(BASE_DIR, "db.sqlite3"), conn_max_age=600
)
} }
# Password validation # Password validation
@ -101,25 +102,19 @@ DATABASES = {
AUTH_PASSWORD_VALIDATORS = [ AUTH_PASSWORD_VALIDATORS = [
{ {
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator"
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
}, },
{"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator"},
{"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator"},
{"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator"},
] ]
# Internationalization # Internationalization
# https://docs.djangoproject.com/en/2.0/topics/i18n/ # https://docs.djangoproject.com/en/2.0/topics/i18n/
LANGUAGE_CODE = 'fr-fr' LANGUAGE_CODE = "fr-fr"
TIME_ZONE = 'Europe/Paris' TIME_ZONE = "Europe/Paris"
USE_I18N = True USE_I18N = True
@ -130,12 +125,11 @@ USE_TZ = True
# Static files (CSS, JavaScript, Images) # Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.0/howto/static-files/ # https://docs.djangoproject.com/en/2.0/howto/static-files/
STATIC_URL = '/static/' STATIC_URL = "/static/"
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') STATIC_ROOT = os.path.join(BASE_DIR, "staticfiles")
LOGIN_REDIRECT_URL = 'rooms-list' LOGIN_REDIRECT_URL = "rooms-list"
EMAIL_BACKEND = 'django_mailgun.MailgunBackend'
MAILGUN_ACCESS_KEY = os.getenv('MAILGUN_ACCESS_KEY', '')
MAILGUN_SERVER_NAME = os.getenv('MAILGUN_SERVER_NAME', '')
EMAIL_BACKEND = "django_mailgun.MailgunBackend"
MAILGUN_ACCESS_KEY = os.getenv("MAILGUN_ACCESS_KEY", "")
MAILGUN_SERVER_NAME = os.getenv("MAILGUN_SERVER_NAME", "")

View file

@ -18,7 +18,7 @@ from django.contrib import admin
from django.urls import path, include from django.urls import path, include
urlpatterns = [ urlpatterns = [
path('admin/', admin.site.urls), path("admin/", admin.site.urls),
path('accounts/', include('django.contrib.auth.urls')), path("accounts/", include("django.contrib.auth.urls")),
url(r'', include('gym.urls')), url(r"", include("gym.urls")),
] ]