From 42914f9bffc8510ab85c66af4a4c44cc714d35bb Mon Sep 17 00:00:00 2001 From: Seeeeeyo Date: Tue, 30 Jun 2026 17:58:19 -0600 Subject: [PATCH 1/7] Add useLidar field to Session model and update serializers and views - Introduced a new BooleanField `useLidar` in the Session model. - Updated SessionSerializer and ValidSessionLightSerializer to include `useLidar` in the serialized fields. - Added a new action in SessionViewSet to handle GET and PATCH requests for the `useLidar` field, allowing retrieval and modification of its value. --- mcserver/models.py | 1 + mcserver/serializers.py | 4 ++-- mcserver/views.py | 47 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/mcserver/models.py b/mcserver/models.py index 8264754..e2731e9 100644 --- a/mcserver/models.py +++ b/mcserver/models.py @@ -81,6 +81,7 @@ class Session(models.Model): isMono = models.BooleanField(default=False, db_index=True) save_local = models.BooleanField(default=False) + useLidar = models.BooleanField(default=False) class Meta: ordering = ['-created_at'] diff --git a/mcserver/serializers.py b/mcserver/serializers.py index e67fc0d..d36f21d 100644 --- a/mcserver/serializers.py +++ b/mcserver/serializers.py @@ -237,7 +237,7 @@ class Meta: fields = [ 'id', 'user', 'public', 'name', 'sessionName', 'qrcode', 'meta', 'trials', 'server', - 'subject', 'isMono', 'save_local', + 'subject', 'isMono', 'save_local', 'useLidar', 'created_at', 'updated_at', 'trashed', 'trashed_at', 'trials_count', 'trashed_trials_count', ] @@ -255,7 +255,7 @@ class Meta: fields = [ 'id', 'user', 'public', 'name', 'sessionName', 'qrcode', 'meta', 'trials', 'server', - 'subject', 'isMono', 'save_local', + 'subject', 'isMono', 'save_local', 'useLidar', 'created_at', 'updated_at', 'trashed', 'trashed_at', 'trials_count', 'trashed_trials_count', ] diff --git a/mcserver/views.py b/mcserver/views.py index cacadcd..e724350 100644 --- a/mcserver/views.py +++ b/mcserver/views.py @@ -299,6 +299,52 @@ def save_local(self, request, pk): raise APIException(_("error") % {"error_message": str(traceback.format_exc())}) raise NotFound(_("session_uuid_not_valid") % {"uuid": str(pk)}) + @action(detail=True, methods=['get', 'patch'], permission_classes=[AllowAny]) + def useLidar(self, request, pk): + try: + if pk == 'undefined': + raise ValueError(_("undefined_uuid")) + + session = get_object_or_404(Session, pk=pk) + + if request.method == 'GET': + return Response({"useLidar": session.useLidar}) + + if not request.user.is_authenticated: + raise NotAuthenticated(_('login_needed')) + + has_permission = ( + IsOwner().has_permission(request, self) and + IsOwner().has_object_permission(request, self, session) + ) or IsAdmin().has_object_permission(request, self, session) or \ + IsBackend().has_object_permission(request, self, session) + + if not has_permission: + raise PermissionDenied(_('permission_denied')) + + useLidar = request.data.get('useLidar', request.query_params.get('useLidar')) + if isinstance(useLidar, bool): + session.useLidar = useLidar + elif isinstance(useLidar, str) and useLidar.lower() in ['true', 'false']: + session.useLidar = useLidar.lower() == 'true' + else: + return Response( + {'useLidar': ['Expected true or false.']}, + status=status.HTTP_400_BAD_REQUEST + ) + + session.save(update_fields=['useLidar', 'updated_at']) + return Response({"useLidar": session.useLidar}) + + except Http404: + if settings.DEBUG: + raise APIException(_("error") % {"error_message": str(traceback.format_exc())}) + raise NotFound(_("session_uuid_not_found") % {"uuid": str(pk)}) + except ValueError: + if settings.DEBUG: + raise APIException(_("error") % {"error_message": str(traceback.format_exc())}) + raise NotFound(_("session_uuid_not_valid") % {"uuid": str(pk)}) + @action( detail=True, methods=["get", "post"], @@ -758,6 +804,7 @@ def new_subject(self, request, pk): user = User.objects.get(id=1) sessionNew.user = user sessionNew.save_local = sessionOld.save_local + sessionNew.useLidar = sessionOld.useLidar except Http404: if settings.DEBUG: From c81bbfaff6bedb68865a58af6430f11cfb29a48d Mon Sep 17 00:00:00 2001 From: Seeeeeyo Date: Tue, 30 Jun 2026 18:02:39 -0600 Subject: [PATCH 2/7] migration file --- mcserver/migrations/0049_session_uselidar.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 mcserver/migrations/0049_session_uselidar.py diff --git a/mcserver/migrations/0049_session_uselidar.py b/mcserver/migrations/0049_session_uselidar.py new file mode 100644 index 0000000..a47a161 --- /dev/null +++ b/mcserver/migrations/0049_session_uselidar.py @@ -0,0 +1,18 @@ +# Generated by Django 3.1.14 on 2026-06-30 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('mcserver', '0048_video_saved_local_index'), + ] + + operations = [ + migrations.AddField( + model_name='session', + name='useLidar', + field=models.BooleanField(default=False), + ), + ] From 45ee99d5253c1e8798f14cbb599ea176abe4f2a0 Mon Sep 17 00:00:00 2001 From: suhlrich <43877159+suhlrich@users.noreply.github.com> Date: Tue, 30 Jun 2026 23:02:09 -0600 Subject: [PATCH 3/7] user group endpoint --- mcserver/urls.py | 4 +++- mcserver/views.py | 10 ++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/mcserver/urls.py b/mcserver/urls.py index 9faf436..223975e 100644 --- a/mcserver/urls.py +++ b/mcserver/urls.py @@ -44,7 +44,8 @@ AnalysisDashboardViewSet, GetUserInfo, UserUpdate, - UpdateProfilePicture + UpdateProfilePicture, + UserGroupsView ) from rest_framework import routers, serializers, viewsets from rest_framework.authtoken.views import obtain_auth_token @@ -98,6 +99,7 @@ path('reset-password/', ResetPasswordView.as_view()), path('new-password/', NewPasswordView.as_view()), path('user-institutional-use/', UserInstitutionalUseView.as_view()), + path('user-groups/', UserGroupsView.as_view(), name='user-groups'), path('swagger/', schema_view.without_ui(cache_timeout=0), name='schema-json'), path('docs/', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'), path('redocs/', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'), diff --git a/mcserver/views.py b/mcserver/views.py index e724350..c9f4324 100644 --- a/mcserver/views.py +++ b/mcserver/views.py @@ -2703,6 +2703,16 @@ def post(self, request, format='json'): return Response(serializer.data) +class UserGroupsView(APIView): + permission_classes = [IsAuthenticated] + + def get(self, request, format='json'): + group_names = list(request.user.groups.values_list('name', flat=True)) + return Response({ + 'groups': group_names, + }) + + class AnalysisFunctionsListAPIView(ListAPIView): """ Returns active AnalysisFunction's. """ From 5b43fadf6c852e2d4ccfb8fc69eb83ab358b3ac8 Mon Sep 17 00:00:00 2001 From: suhlrich <43877159+suhlrich@users.noreply.github.com> Date: Tue, 30 Jun 2026 23:12:48 -0600 Subject: [PATCH 4/7] add useLidar to status payload --- mcserver/views.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mcserver/views.py b/mcserver/views.py index c9f4324..9e7d457 100644 --- a/mcserver/views.py +++ b/mcserver/views.py @@ -945,6 +945,7 @@ def get_status(self, request, pk): "trialname": trial.name if trial else None, "video": video_url, "framerate": frameRate, + "useLidar": session.useLidar, "newSessionURL": newSessionURL, "n_cameras_connected": n_cameras_connected, "n_videos_uploaded": n_videos_uploaded From f094485761631a792aff03b276902443db71b53d Mon Sep 17 00:00:00 2001 From: suhlrich <43877159+suhlrich@users.noreply.github.com> Date: Wed, 1 Jul 2026 12:11:46 -0600 Subject: [PATCH 5/7] support lidar setting and counting --- mcserver/views.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mcserver/views.py b/mcserver/views.py index 9e7d457..602f959 100644 --- a/mcserver/views.py +++ b/mcserver/views.py @@ -903,6 +903,7 @@ def get_status(self, request, pk): if trial.video_set.filter(device_id=request.GET["device_id"]).count() == 0: video = Video() video.device_id = request.GET["device_id"] + video.isLidar = str(request.GET.get("usingLidar", "")).lower() == "true" video.trial = trial video.save() status = "recording" @@ -917,6 +918,8 @@ def get_status(self, request, pk): video_uploaded = video.video and video.video.url if video_uploaded: n_videos_uploaded = n_videos_uploaded + 1 + if "device_id" not in request.GET: + n_cameras_using_lidar = trial.video_set.filter(isLidar=True).count() if trial else 0 video_url = None if trial and trial.status == "recording" and "device_id" in request.GET: @@ -951,6 +954,9 @@ def get_status(self, request, pk): "n_videos_uploaded": n_videos_uploaded } + if "device_id" not in request.GET: + res["n_cameras_using_lidar"] = n_cameras_using_lidar + if "ret_session" in request.GET: res["session"] = SessionSerializer(session, many=False).data From 473bbcf0c6fd513489a821abbfdc03b9393cbbe0 Mon Sep 17 00:00:00 2001 From: suhlrich <43877159+suhlrich@users.noreply.github.com> Date: Wed, 1 Jul 2026 13:10:22 -0600 Subject: [PATCH 6/7] error old trials in a session that are recording --- mcserver/views.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mcserver/views.py b/mcserver/views.py index 602f959..126f865 100644 --- a/mcserver/views.py +++ b/mcserver/views.py @@ -1037,6 +1037,10 @@ def get_count_from_name(name, base_name): name = "{}_{}".format(name, highest_count + 1) trial.name = name + session.trial_set.filter(status="recording").update( + status="error", + updated_at=timezone.now() + ) trial.save() if name == "calibration" or name == "neutral": From a123c035566855ce2afd5d7b75e592c32f263026 Mon Sep 17 00:00:00 2001 From: suhlrich <43877159+suhlrich@users.noreply.github.com> Date: Thu, 2 Jul 2026 15:43:49 -0600 Subject: [PATCH 7/7] force 60fps for lidar, but leave db as user pref if they switch back --- mcserver/views.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mcserver/views.py b/mcserver/views.py index 126f865..fcc7556 100644 --- a/mcserver/views.py +++ b/mcserver/views.py @@ -934,11 +934,13 @@ def get_status(self, request, pk): else: newSessionURL = None - if session.meta and "settings" in session.meta and "framerate" in session.meta['settings']: + if session.useLidar: + frameRate = 60 + elif session.meta and "settings" in session.meta and "framerate" in session.meta['settings']: frameRate = int(session.meta['settings']['framerate']) else: frameRate = 60 - if trial and (trial.name in {'calibration','neutral'}): + if not session.useLidar and trial and (trial.name in {'calibration','neutral'}): frameRate = 30