import datetime import plotly import plotly.graph_objs as go from django.contrib.auth.mixins import LoginRequiredMixin from django.shortcuts import get_object_or_404 from django.urls import reverse from django.views import generic from gym.mixins import SessionResetMixin, QuickActionsMixin from gym.models import Room, Equipment, Setting, Session, Round, TheoreticalMax class RoomListView(LoginRequiredMixin, SessionResetMixin, generic.ListView): queryset = Room.objects.all().order_by("name") context_object_name = "rooms" template_name = "gym/rooms.html" class RoomDetailView( LoginRequiredMixin, QuickActionsMixin, SessionResetMixin, generic.DetailView ): model = Room context_object_name = "room" template_name = "gym/room.html" def get_quick_actions(self): quick_actions = [ { "url": reverse("rooms-list"), "category": "secondary", "display": "Liste des salles", }, { "url": "{}?room={}".format(reverse("session-start"), self.object.pk), "category": "primary", "display": "Commencer une séance", }, { "url": "{}?room={}".format(reverse("equipment-create"), self.object.pk), "category": "success", "display": "Ajouter une machine", }, ] if self.object.latitude and self.object.longitude: from user_agents import parse user_agent = parse(self.request.META.get("HTTP_USER_AGENT")) if user_agent.is_mobile: url = f"waze://?ll={self.object.latitude},{self.object.longitude}&navigate=yes" name = "Waze" quick_actions.append( { "url": f"here-location://{self.object.latitude},{self.object.longitude}", "category": "info", "display": "Here WeGo", "icon": "fas fa-location-arrow", } ) else: url = ( f"https://www.google.com/maps/place/{self.object.latitude},{self.object.longitude}" f"/@{self.object.latitude},{self.object.longitude},18z" ) name = "Google Maps" quick_actions.append( { "url": url, "category": "info", "display": name, "icon": "fas fa-location-arrow", } ) return quick_actions def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context["sessions"] = self.object.sessions.all().order_by("-start") return context class EquipmentDetailView(LoginRequiredMixin, QuickActionsMixin, generic.DetailView): model = Equipment context_object_name = "equipment" template_name = "gym/equipment.html" session = None def get_quick_actions(self): lst = [] if self.session: 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("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: lst.append( { "url": reverse( "admin:gym_equipment_change", args=(self.object.pk,) ), "category": "warning", "display": "Éditer la machine", } ) return lst def dispatch(self, request, *args, **kwargs): session_pk = self.request.session.get("session_pk") if session_pk: self.session = Session.objects.get(pk=session_pk) return super().dispatch(request, *args, **kwargs) def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) if self.session: context["session"] = self.session.pk context["rounds"] = Round.objects.filter( session=self.session, equipment=self.get_object() ) return context class EquipmentCreateView(LoginRequiredMixin, QuickActionsMixin, generic.CreateView): model = Equipment fields = ["room", "name", "default_work_form", "unit", "default_repetition_number"] template_name = "gym/equipment_edit.html" room = None def get_quick_actions(self): return [ { "url": reverse("room-detail", args=(self.room.pk,)), "category": "secondary", "display": "Retourner à la salle", } ] def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context["room"] = self.room return context 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(LoginRequiredMixin, QuickActionsMixin, generic.CreateView): model = Setting fields = ["equipment", "name", "value"] template_name = "gym/setting_edit.html" equipment = None def get_quick_actions(self): return [ { "url": reverse("equipment-detail", args=(self.equipment.pk,)), "category": "secondary", "display": "Retourner à la machine", } ] 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(LoginRequiredMixin, QuickActionsMixin, generic.UpdateView): model = Setting fields = ["equipment", "name", "value"] template_name = "gym/setting_edit.html" def get_quick_actions(self): return [ { "url": reverse("equipment-detail", args=(self.object.equipment.pk,)), "category": "secondary", "display": "Retourner à la machine", } ] 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(LoginRequiredMixin, generic.DeleteView): model = Setting template_name = "gym/confirm_delete.html" def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context["article"] = "une" context["name"] = "série" context["message"] = ( "Êtes-vous sûr de vouloir supprimer le réglage " '{} pour la machine "{}" ?'.format( self.object, self.object.equipment ) ) return context def get_success_url(self): return reverse("equipment-detail", kwargs={"pk": self.object.equipment.pk}) class TheoreticalMaxCreateView( LoginRequiredMixin, QuickActionsMixin, generic.CreateView ): model = TheoreticalMax fields = ["equipment", "date", "value"] template_name = "gym/theoretical_max_edit.html" equipment = None def get_quick_actions(self): return [ { "url": reverse("equipment-detail", args=(self.equipment.pk,)), "category": "secondary", "display": "Retourner à la machine", } ] 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 initial["date"] = datetime.date.today() return initial def get_success_url(self): return reverse("theoretical-max-list", kwargs={"pk": self.object.equipment.pk}) class TheoreticalMaxListView(LoginRequiredMixin, QuickActionsMixin, generic.ListView): model = TheoreticalMax template_name = "gym/theoretical_max_list.html" context_object_name = "maxs" equipment = None def dispatch(self, request, *args, **kwargs): pk = self.kwargs.pop("pk") self.equipment = get_object_or_404(Equipment, pk=pk) return super().dispatch(request, *args, **kwargs) def get_queryset(self): return TheoreticalMax.objects.filter(equipment=self.equipment).order_by("date") def get_quick_actions(self): return [ { "url": reverse("equipment-detail", args=(self.equipment.pk,)), "category": "secondary", "display": "Retourner à la machine", }, { "url": "{}?equipment={}".format( reverse("theoretical-max-create"), self.equipment.pk ), "category": "success", "display": "Ajouter un max théorique", }, ] def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) data = [ go.Scatter( x=[max.date for max in self.get_queryset()], y=[max.value for max in self.get_queryset()], ) ] layout = go.Layout( title="Évolution du max théorique", yaxis={"title": "Charge ({})".format(self.equipment.unit.name)}, xaxis={"title": "Date"}, ) figure = {"data": data, "layout": layout} graph = plotly.offline.plot(figure, auto_open=False, output_type="div") context["graph"] = graph context["equipment"] = self.equipment return context class SessionCreateView(LoginRequiredMixin, QuickActionsMixin, generic.CreateView): model = Session fields = ["room", "start", "default_theoretical_max_percentage"] template_name = "gym/session_edit.html" room = None def get_quick_actions(self): room_pk = self.room.pk return [ { "url": reverse("room-detail", args=(room_pk,)), "category": "secondary", "display": "Retourner à la salle", } ] 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(LoginRequiredMixin, QuickActionsMixin, generic.DetailView): model = Session context_object_name = "session" template_name = "gym/session_detail.html" def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) session = self.get_object() context["used_equipments"] = { k: Round.objects.filter(equipment=k, session=session).count() for k in Equipment.objects.filter(rounds__session=self.get_object()) } return context def get_quick_actions(self): room_pk = self.get_object().room.pk return [ { "url": reverse("room-detail", args=(room_pk,)), "category": "secondary", "display": "Retourner à la salle", }, { "url": "{}?room={}".format(reverse("equipment-create"), room_pk), "category": "success", "display": "Ajouter une machine", }, ] def dispatch(self, request, *args, **kwargs): request.session["session_pk"] = self.get_object().pk return super().dispatch(request, *args, **kwargs) class RoundCreateView(LoginRequiredMixin, QuickActionsMixin, generic.CreateView): model = Round fields = [ "equipment", "session", "theoretical_max_percentage", "chosen_weight", "repetition_number", "work_form", "notes", ] template_name = "gym/round_edit.html" equipment = None session = None def get_quick_actions(self): return [ { "url": reverse("equipment-detail", args=(self.equipment.pk,)), "category": "secondary", "display": "Retourner à la machine", } ] def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context["title"] = "Commencer" context["equipment"] = self.equipment return context def dispatch(self, request, *args, **kwargs): self.equipment = get_object_or_404( Equipment, pk=self.request.GET.get("equipment") ) session_pk = self.request.session.get("session_pk") if session_pk: self.session = Session.objects.get(pk=session_pk) return super().dispatch(request, *args, **kwargs) def get_initial(self): theoretical_max_percentage = self.session.default_theoretical_max_percentage initial = super().get_initial() initial["equipment"] = self.equipment initial["session"] = self.session last_round = self.equipment.rounds.filter( session=self.session ).last() # type: Round initial["theoretical_max_percentage"] = theoretical_max_percentage if last_round: initial["repetition_number"] = last_round.repetition_number initial["work_form"] = last_round.work_form initial["chosen_weight"] = last_round.chosen_weight else: initial["repetition_number"] = ( self.equipment.default_repetition_number or 12 ) initial["work_form"] = self.equipment.default_work_form proposed_weight = 0 theoretical_max = self.equipment.last_theoretical_max if theoretical_max: proposed_weight = ( theoretical_max.value * theoretical_max_percentage / 100 ) initial["chosen_weight"] = proposed_weight return initial def get_success_url(self): return reverse("equipment-detail", kwargs={"pk": self.object.equipment.pk}) class RoundUpdateView(LoginRequiredMixin, QuickActionsMixin, generic.UpdateView): model = Round fields = [ "equipment", "session", "theoretical_max_percentage", "chosen_weight", "repetition_number", "work_form", "notes", ] template_name = "gym/round_edit.html" def get_quick_actions(self): return [ { "url": reverse("equipment-detail", args=(self.object.equipment.pk,)), "category": "secondary", "display": "Retourner à la machine", } ] 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 RoundDeleteView(LoginRequiredMixin, generic.DeleteView): model = Round template_name = "gym/confirm_delete.html" def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context["article"] = "une" context["name"] = "série" context["message"] = ( "Êtes-vous sûr de vouloir supprimer " 'la série {}, {}x{}{} pour la séance "{}" ?'.format( self.object.equipment, self.object.repetition_number, self.object.chosen_weight, self.object.equipment.unit, self.object.session, ) ) return context def get_success_url(self): return reverse("equipment-detail", kwargs={"pk": self.object.equipment.pk})