From f1dfd94f0e62133c14797543efdfbc173a2d79dd Mon Sep 17 00:00:00 2001 From: Philipp Kilian Date: Fri, 24 May 2024 16:39:35 +0200 Subject: [PATCH 1/6] model: add migration to replace meeting primary key --- .../0017_rename_meeting_meetingold.py | 17 +++++++ b3lb/rest/migrations/0018_meeting.py | 44 +++++++++++++++++++ .../migrations/0019_migrate_meeting_data.py | 35 +++++++++++++++ .../rest/migrations/0020_remove_meetingold.py | 39 ++++++++++++++++ b3lb/rest/migrations/0021_refill_recordset.py | 23 ++++++++++ b3lb/rest/models.py | 8 +++- 6 files changed, 164 insertions(+), 2 deletions(-) create mode 100644 b3lb/rest/migrations/0017_rename_meeting_meetingold.py create mode 100644 b3lb/rest/migrations/0018_meeting.py create mode 100644 b3lb/rest/migrations/0019_migrate_meeting_data.py create mode 100644 b3lb/rest/migrations/0020_remove_meetingold.py create mode 100644 b3lb/rest/migrations/0021_refill_recordset.py diff --git a/b3lb/rest/migrations/0017_rename_meeting_meetingold.py b/b3lb/rest/migrations/0017_rename_meeting_meetingold.py new file mode 100644 index 0000000..7d93955 --- /dev/null +++ b/b3lb/rest/migrations/0017_rename_meeting_meetingold.py @@ -0,0 +1,17 @@ +# Generated by Django 3.2.23 on 2024-05-24 13:22 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('rest', '0016_resize_meeting_name_length'), + ] + + operations = [ + migrations.RenameModel( + old_name='Meeting', + new_name='MeetingOld', + ), + ] diff --git a/b3lb/rest/migrations/0018_meeting.py b/b3lb/rest/migrations/0018_meeting.py new file mode 100644 index 0000000..6335795 --- /dev/null +++ b/b3lb/rest/migrations/0018_meeting.py @@ -0,0 +1,44 @@ +# Generated by Django 3.2.23 on 2024-05-24 13:29 + +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone +import rest.models +import uuid + + +class Migration(migrations.Migration): + + dependencies = [ + ('rest', '0017_rename_meeting_meetingold'), + ] + + operations = [ + migrations.CreateModel( + name='MeetingNew', + fields=[ + ('uuid', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False, unique=True)), + ('id', models.CharField(max_length=100)), + ('room_name', models.CharField(max_length=256)), + ('age', models.DateTimeField(default=django.utils.timezone.now)), + ('attendees', models.SmallIntegerField(default=0)), + ('end_callback_url', models.URLField(default='')), + ('listenerCount', models.SmallIntegerField(default=0)), + ('nonce', models.CharField(default=rest.models.get_nonce, editable=False, max_length=64, unique=True)), + ('voiceParticipantCount', models.SmallIntegerField(default=0)), + ('moderatorCount', models.SmallIntegerField(default=0)), + ('videoCount', models.SmallIntegerField(default=0)), + ('bbb_origin', models.CharField(default='', max_length=255)), + ('bbb_origin_server_name', models.CharField(default='', max_length=255)), + ('node', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='rest.node')), + ('secret', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='rest.secret')), + ], + options={ + 'ordering': ['secret__tenant', 'age'], + }, + ), + migrations.AddConstraint( + model_name='meetingnew', + constraint=models.UniqueConstraint(fields=('id', 'secret'), name='unique_meeting'), + ), + ] diff --git a/b3lb/rest/migrations/0019_migrate_meeting_data.py b/b3lb/rest/migrations/0019_migrate_meeting_data.py new file mode 100644 index 0000000..cd3b987 --- /dev/null +++ b/b3lb/rest/migrations/0019_migrate_meeting_data.py @@ -0,0 +1,35 @@ +# Generated by Django 3.2.23 on 2024-05-24 13:29 + +from django.db import migrations + +def migrate_meetings(apps, schema_editor): + meeting_class = apps.get_model("rest", "MeetingNew") + meeting_old_class = apps.get_model("rest", "MeetingOld") + for meeting_old in meeting_old_class.objects.all(): + meeting = meeting_class() + meeting.id = meeting_old.id + meeting.secret = meeting_old.secret + meeting.node = meeting_old.node + meeting.room_name = meeting_old.room_name + meeting.age = meeting_old.age + meeting.attendees = meeting_old.attendees + meeting.end_callback_url = meeting_old.end_callback_url + meeting.listenerCount = meeting_old.listenerCount + meeting.nonce = meeting_old.nonce + meeting.voiceParticipantCount = meeting_old.voiceParticipantCount + meeting.moderatorCount = meeting_old.moderatorCount + meeting.videoCount = meeting_old.videoCount + meeting.bbb_origin = meeting_old.bbb_origin + meeting.bbb_origin_server_name = meeting_old.bbb_origin_server_name + meeting.save() + + +class Migration(migrations.Migration): + + dependencies = [ + ('rest', '0018_meeting'), + ] + + operations = [ + migrations.RunPython(migrate_meetings) + ] diff --git a/b3lb/rest/migrations/0020_remove_meetingold.py b/b3lb/rest/migrations/0020_remove_meetingold.py new file mode 100644 index 0000000..682cf7e --- /dev/null +++ b/b3lb/rest/migrations/0020_remove_meetingold.py @@ -0,0 +1,39 @@ +# Generated by Django 3.2.23 on 2024-05-24 13:46 + +from django.db import migrations, models +import django.db.models.deletion + +def migrate_record_set_meetings(apps, schema_editor): + record_set_class = apps.get_model('rest', 'RecordSet') + for record_set in record_set_class.objects.all(): + if record_set.meeting: + record_set.meeting = None + record_set.save() + + +class Migration(migrations.Migration): + + dependencies = [ + ('rest', '0019_migrate_meeting_data'), + ] + + operations = [ + migrations.RunPython(migrate_record_set_meetings), + migrations.AlterField( + model_name='recordset', + name='meeting', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='rest.meetingnew'), + ), + migrations.DeleteModel( + name='MeetingOld', + ), + migrations.RenameModel( + old_name='MeetingNew', + new_name='Meeting', + ), + migrations.AlterField( + model_name='recordset', + name='meeting', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='rest.meeting'), + ), + ] diff --git a/b3lb/rest/migrations/0021_refill_recordset.py b/b3lb/rest/migrations/0021_refill_recordset.py new file mode 100644 index 0000000..797dcc9 --- /dev/null +++ b/b3lb/rest/migrations/0021_refill_recordset.py @@ -0,0 +1,23 @@ +# Generated by Django 3.2.23 on 2024-05-24 14:14 + +from django.db import migrations + +def refill_record_set(apps, schema_editor): + record_set_class = apps.get_model('rest', 'RecordSet') + meeting_class = apps.get_model('rest', 'Meeting') + for record_set in record_set_class.objects.all(): + if record_set.status == "UNKNOWN" and record_set.meta_meeting_id: + meetings = meeting_class.objects.filter(id=record_set.meta_meeting_id, secret=record_set.secret) + if meetings.count() == 1: + record_set.meeting = meetings[0] + record_set.save() + +class Migration(migrations.Migration): + + dependencies = [ + ('rest', '0020_remove_meetingold'), + ] + + operations = [ + migrations.RunPython(refill_record_set) + ] diff --git a/b3lb/rest/models.py b/b3lb/rest/models.py index 9453085..21f8854 100644 --- a/b3lb/rest/models.py +++ b/b3lb/rest/models.py @@ -16,12 +16,13 @@ from base64 import b32encode -from django.db import models from django.core.exceptions import ValidationError from django.core.files.storage import FileSystemStorage, default_storage from django.core.validators import MaxValueValidator, MinValueValidator, RegexValidator from django.conf import settings from django.contrib import admin +from django.db import models +from django.db.models.constraints import UniqueConstraint from django.utils import timezone from django.utils.crypto import get_random_string from django.utils.html import format_html @@ -575,7 +576,8 @@ class SecretMetricsListAdmin(admin.ModelAdmin): # meeting - tenant - node relation class class Meeting(models.Model): - id = models.CharField(max_length=cst.MEETING_ID_LENGTH, primary_key=True) + uuid = models.UUIDField(primary_key=True, editable=False, unique=True, default=uid.uuid4) + id = models.CharField(max_length=cst.MEETING_ID_LENGTH) secret = models.ForeignKey(Secret, on_delete=models.CASCADE) node = models.ForeignKey(Node, on_delete=models.CASCADE) room_name = models.CharField(max_length=cst.MEETING_NAME_LENGTH) @@ -592,11 +594,13 @@ class Meeting(models.Model): class Meta(object): ordering = ['secret__tenant', 'age'] + constraints = [UniqueConstraint(fields=['id', 'secret'], name='unique_meeting')] def __str__(self): return "{} {}".format(self.secret.tenant.slug, self.room_name) +# meeting - tenant - node relation class class MeetingAdmin(admin.ModelAdmin): model = Meeting list_display = ['__str__', 'bbb_origin_server_name', 'node', 'attendees', 'listenerCount', 'voiceParticipantCount', 'videoCount', 'age', 'id'] From 1f6d19985b46d2d7e11b978cdb3826fb65cb317c Mon Sep 17 00:00:00 2001 From: Philipp Kilian Date: Tue, 28 May 2024 11:12:48 +0200 Subject: [PATCH 2/6] api: check meeting id length and reorder __init__ functions --- b3lb/rest/b3lb/constants.py | 1 + b3lb/rest/classes/api.py | 103 +++++++++++++++++++----------------- b3lb/rest/models.py | 7 ++- 3 files changed, 58 insertions(+), 53 deletions(-) diff --git a/b3lb/rest/b3lb/constants.py b/b3lb/rest/b3lb/constants.py index 287b2a9..44b6c95 100644 --- a/b3lb/rest/b3lb/constants.py +++ b/b3lb/rest/b3lb/constants.py @@ -24,6 +24,7 @@ RETURN_STRING_GET_RECORDING_TEXT_TRACKS_NOTHING_FOUND_JSON = '{"response":{"returncode":"FAILED","messageKey":"noRecordings","message":"No recording found"}}' RETURN_STRING_GET_RECORDING_NO_RECORDINGS = '\r\nSUCCESS\r\n\r\nnoRecordings\r\nThere are no recordings for the meeting(s).\r\n' RETURN_STRING_MISSING_MEETING_ID = '\r\nFAILED\r\nmissingParamMeetingID\r\nYou must specify a meeting ID for the meeting.\r\n' +RETURN_STRING_MISSING_MEETING_ID_TO_LONG = '\r\nFAILED\r\nMeeting id must be between 2 and 100 characters\r\n' RETURN_STRING_MISSING_RECORD_ID = '\r\nFAILED\r\nmissingParamRecordID\r\nYou must specify one or more a record IDs.\r\n' RETURN_STRING_MISSING_RECORD_PUBLISH = '\r\nFAILED\r\nmissingParamPublish\r\nYou must specify one a publish value true or false.\r\n' RETURN_STRING_RECORD_PUBLISHED = '\r\nSUCCESS\r\n{}\r\n' diff --git a/b3lb/rest/classes/api.py b/b3lb/rest/classes/api.py index a6c8479..a68c317 100644 --- a/b3lb/rest/classes/api.py +++ b/b3lb/rest/classes/api.py @@ -34,7 +34,7 @@ from rest.b3lb.metrics import incr_metric, update_create_metrics from rest.b3lb.parameters import ALLOW_START_STOP_RECORDING, AUTO_START_RECORDING, BLOCK, LOGO, OVERRIDE, PARAMETERS_CREATE, PARAMETERS_JOIN, RECORD, SET, USERDATA_BBB_CUSTOM_STYLE_URL from rest.b3lb.utils import get_checksum -from rest.models import is_meeting_name_length_fine, ClusterGroupRelation, Meeting, Metric, Node, Parameter, Record, RecordSet, Secret, SecretMeetingList, SecretMetricsList, Stats +from rest.models import check_str_length, ClusterGroupRelation, Meeting, Metric, Node, Parameter, Record, RecordSet, Secret, SecretMeetingList, SecretMetricsList, Stats from typing import Any, Dict, List, Literal, Union from uuid import UUID from urllib.parse import urlencode @@ -49,6 +49,7 @@ class ClientB3lbRequest: request: HttpRequest parameters: Dict[str, Any] meeting_id: str + meeting_name: str body: Union[str, bytes] endpoint: str checksum: str @@ -60,6 +61,40 @@ class ClientB3lbRequest: ENDPOINTS_PASS_THROUGH: List[str] ENDPOINTS: Dict[str, Any] + ## INIT ## + def __init__(self, request: HttpRequest, endpoint: str): + self.has_assets = False + self.request = request + self.endpoint = endpoint + self.parameters = {} + self.body = request.body + for parameter in request.GET.keys(): + self.parameters[parameter] = request.GET.get(parameter) + + self.meeting_id = self.parameters.get("meetingID", "") + self.meeting_name = self.parameters.get("name", "") + self.checksum = self.parameters.pop("checksum", "") + self.stats_token = self.request.headers.get("Authorization", "") + + self.secret = None + self.node = None + self.state = self.parameters.get("state", "") + self.ENDPOINTS_PASS_THROUGH = ["end", "insertDocument", "setConfigXML", "getMeetingInfo"] + self.ENDPOINTS = { + "": self.version, + "create": self.create, + "join": self.join, + "isMeetingRunning": self.is_meeting_running, + "getMeetings": self.get_meetings, + "getRecordingTextTracks": self.get_recording_text_tracks, + "getRecordings": self.get_recordings, + "deleteRecordings": self.delete_recordings, + "publishRecordings": self.publish_recordings, + "updateRecordings": self.update_recordings, + "b3lb_metrics": self.metrics, + "b3lb_stats": self.stats + } + #### Class functions async def _check_post_headers(self) -> Dict[str, Any]: if not self.has_assets: @@ -81,7 +116,10 @@ async def create(self) -> HttpResponse: if not self.meeting_id: return HttpResponse(cst.RETURN_STRING_MISSING_MEETING_ID, content_type=cst.CONTENT_TYPE) - if not is_meeting_name_length_fine(self.parameters.get("name", "")): + if not check_str_length(self.meeting_id, cst.MEETING_ID_LENGTH): + return HttpResponse(cst.RETURN_STRING_MISSING_MEETING_ID_TO_LONG, content_type=cst.CONTENT_TYPE) + + if not check_str_length(self.meeting_name, cst.MEETING_NAME_LENGTH): return HttpResponse(cst.RETURN_STRING_WRONG_MEETING_NAME_LENGTH, content_type=cst.CONTENT_TYPE) if not await self.is_meeting(): @@ -449,7 +487,7 @@ def is_node_free(self) -> bool: ## Getter Routines ## def get_meeting_defaults(self) -> Dict[str, Any]: - return {"id": self.meeting_id, "secret": self.secret, "node": self.node, "room_name": self.parameters.get("name", "Unknown"), "end_callback_url": self.parameters.get("meta_endCallbackUrl", "")} + return {"id": self.meeting_id, "secret": self.secret, "node": self.node, "room_name": self.meeting_name, "end_callback_url": self.parameters.get("meta_endCallbackUrl", "")} def get_node_endpoint_url(self) -> str: parameter_str = "" @@ -540,39 +578,6 @@ async def set_secret_by_slug_and_slug_id(self, slug: str, sub_id: int): except ObjectDoesNotExist: pass - ## INIT ## - def __init__(self, request: HttpRequest, endpoint: str): - self.has_assets = False - self.request = request - self.endpoint = endpoint - self.parameters = {} - self.body = request.body - for parameter in request.GET.keys(): - self.parameters[parameter] = request.GET.get(parameter) - - self.meeting_id = self.parameters.get("meetingID", "") - self.checksum = self.parameters.pop("checksum", "") - self.stats_token = self.request.headers.get("Authorization", "") - - self.secret = None - self.node = None - self.state = self.parameters.get("state", "") - self.ENDPOINTS_PASS_THROUGH = ["end", "insertDocument", "setConfigXML", "getMeetingInfo"] - self.ENDPOINTS = { - "": self.version, - "create": self.create, - "join": self.join, - "isMeetingRunning": self.is_meeting_running, - "getMeetings": self.get_meetings, - "getRecordingTextTracks": self.get_recording_text_tracks, - "getRecordings": self.get_recordings, - "deleteRecordings": self.delete_recordings, - "publishRecordings": self.publish_recordings, - "updateRecordings": self.update_recordings, - "b3lb_metrics": self.metrics, - "b3lb_stats": self.stats - } - class NodeB3lbRequest: """ @@ -587,6 +592,19 @@ class NodeB3lbRequest: nonce: str recording_marks: str + def __init__(self, request: HttpRequest, backend: str, endpoint: str): + self.request = request + self.meeting = None + self.backend = backend + self.endpoint = endpoint + self.meeting_id = self.request.GET.get("meetingID", "") + self.nonce = self.request.GET.get("nonce", "") + self.recording_marks = self.request.GET.get("recordingmarks", "false") + self.BACKENDS = { + "meeting/end": {"methods": ["GET"], "function": self.end_meeting}, + "record/upload": {"methods": ["POST"], "function": self.upload_record} + } + def is_allowed_endpoint(self) -> bool: if self.full_endpoint() in self.BACKENDS: return True @@ -697,16 +715,3 @@ async def upload_record(self) -> HttpResponse: await sync_to_async(record_set.save)() return HttpResponse(status=204) - - def __init__(self, request: HttpRequest, backend: str, endpoint: str): - self.request = request - self.meeting = None - self.backend = backend - self.endpoint = endpoint - self.meeting_id = self.request.GET.get("meetingID", "") - self.nonce = self.request.GET.get("nonce", "") - self.recording_marks = self.request.GET.get("recordingmarks", "false") - self.BACKENDS = { - "meeting/end": {"methods": ["GET"], "function": self.end_meeting}, - "record/upload": {"methods": ["POST"], "function": self.upload_record} - } diff --git a/b3lb/rest/models.py b/b3lb/rest/models.py index 21f8854..94ccccf 100644 --- a/b3lb/rest/models.py +++ b/b3lb/rest/models.py @@ -46,6 +46,9 @@ # # FUNCTIONS # +def check_str_length(value: str, max_length: int) -> bool: + return 2 <= len(value) < max_length + def get_nonce(): return get_random_string(cst.NONCE_LENGTH, cst.NONCE_CHAR_POOL) @@ -65,10 +68,6 @@ def get_storage(): return used_storage -def is_meeting_name_length_fine(name: str) -> bool: - return 2 <= len(name) < cst.MEETING_NAME_LENGTH - - # # ADMIN ACTIONS # From c53073400a50445d7c5a906e746ac1c3143b749d Mon Sep 17 00:00:00 2001 From: Philipp Kilian Date: Tue, 28 May 2024 11:14:42 +0200 Subject: [PATCH 3/6] changelog: update CHANGELOG.md --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7427208..b204d4a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # ChangeLog +## 3.2.3 - 2024-05-28 + +Fixes: +- add possibility to use the same meeting ID for two different secrets. +- send an error if meeting id is too long (2 < id_length < 100 chars) + + ## 3.2.2 - 2024-05-23 Fixes: From a811d08dbbdc7aad9ba6fd1908ff8aadd15c17b1 Mon Sep 17 00:00:00 2001 From: Philipp Kilian Date: Tue, 28 May 2024 11:18:30 +0200 Subject: [PATCH 4/6] migrations: check for all non-rendered states --- b3lb/rest/migrations/0021_refill_recordset.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/b3lb/rest/migrations/0021_refill_recordset.py b/b3lb/rest/migrations/0021_refill_recordset.py index 797dcc9..99a79ae 100644 --- a/b3lb/rest/migrations/0021_refill_recordset.py +++ b/b3lb/rest/migrations/0021_refill_recordset.py @@ -6,7 +6,7 @@ def refill_record_set(apps, schema_editor): record_set_class = apps.get_model('rest', 'RecordSet') meeting_class = apps.get_model('rest', 'Meeting') for record_set in record_set_class.objects.all(): - if record_set.status == "UNKNOWN" and record_set.meta_meeting_id: + if record_set.status in ["UNKNOWN", "UPLOADED"] and record_set.meta_meeting_id: meetings = meeting_class.objects.filter(id=record_set.meta_meeting_id, secret=record_set.secret) if meetings.count() == 1: record_set.meeting = meetings[0] From cfd589868604f1cb8c294e2d39f9eee2b8829d33 Mon Sep 17 00:00:00 2001 From: Philipp Kilian Date: Wed, 29 May 2024 11:15:14 +0200 Subject: [PATCH 5/6] api: don't use bloated function for simple checks --- b3lb/rest/classes/api.py | 6 +++--- b3lb/rest/models.py | 3 --- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/b3lb/rest/classes/api.py b/b3lb/rest/classes/api.py index a68c317..a495e13 100644 --- a/b3lb/rest/classes/api.py +++ b/b3lb/rest/classes/api.py @@ -34,7 +34,7 @@ from rest.b3lb.metrics import incr_metric, update_create_metrics from rest.b3lb.parameters import ALLOW_START_STOP_RECORDING, AUTO_START_RECORDING, BLOCK, LOGO, OVERRIDE, PARAMETERS_CREATE, PARAMETERS_JOIN, RECORD, SET, USERDATA_BBB_CUSTOM_STYLE_URL from rest.b3lb.utils import get_checksum -from rest.models import check_str_length, ClusterGroupRelation, Meeting, Metric, Node, Parameter, Record, RecordSet, Secret, SecretMeetingList, SecretMetricsList, Stats +from rest.models import ClusterGroupRelation, Meeting, Metric, Node, Parameter, Record, RecordSet, Secret, SecretMeetingList, SecretMetricsList, Stats from typing import Any, Dict, List, Literal, Union from uuid import UUID from urllib.parse import urlencode @@ -116,10 +116,10 @@ async def create(self) -> HttpResponse: if not self.meeting_id: return HttpResponse(cst.RETURN_STRING_MISSING_MEETING_ID, content_type=cst.CONTENT_TYPE) - if not check_str_length(self.meeting_id, cst.MEETING_ID_LENGTH): + if not 2 <= len(self.meeting_id) < cst.MEETING_ID_LENGTH: return HttpResponse(cst.RETURN_STRING_MISSING_MEETING_ID_TO_LONG, content_type=cst.CONTENT_TYPE) - if not check_str_length(self.meeting_name, cst.MEETING_NAME_LENGTH): + if not 2 <= len(self.meeting_name) < cst.MEETING_NAME_LENGTH: return HttpResponse(cst.RETURN_STRING_WRONG_MEETING_NAME_LENGTH, content_type=cst.CONTENT_TYPE) if not await self.is_meeting(): diff --git a/b3lb/rest/models.py b/b3lb/rest/models.py index 94ccccf..3cbc92f 100644 --- a/b3lb/rest/models.py +++ b/b3lb/rest/models.py @@ -46,9 +46,6 @@ # # FUNCTIONS # -def check_str_length(value: str, max_length: int) -> bool: - return 2 <= len(value) < max_length - def get_nonce(): return get_random_string(cst.NONCE_LENGTH, cst.NONCE_CHAR_POOL) From 6882c5efc99d905bc1c4b77db70a0a405f6464b5 Mon Sep 17 00:00:00 2001 From: Philipp Kilian Date: Wed, 29 May 2024 11:25:48 +0200 Subject: [PATCH 6/6] api: update out of range check for meeting name and meeting id --- CHANGELOG.md | 2 +- b3lb/rest/classes/api.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b204d4a..f0fd5a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ Fixes: - add possibility to use the same meeting ID for two different secrets. -- send an error if meeting id is too long (2 < id_length < 100 chars) +- return an error message if meeting id is out of range (2 <= id_length <= 100 chars) ## 3.2.2 - 2024-05-23 diff --git a/b3lb/rest/classes/api.py b/b3lb/rest/classes/api.py index a495e13..9f01705 100644 --- a/b3lb/rest/classes/api.py +++ b/b3lb/rest/classes/api.py @@ -116,10 +116,10 @@ async def create(self) -> HttpResponse: if not self.meeting_id: return HttpResponse(cst.RETURN_STRING_MISSING_MEETING_ID, content_type=cst.CONTENT_TYPE) - if not 2 <= len(self.meeting_id) < cst.MEETING_ID_LENGTH: + if not 2 <= len(self.meeting_id) <= cst.MEETING_ID_LENGTH: return HttpResponse(cst.RETURN_STRING_MISSING_MEETING_ID_TO_LONG, content_type=cst.CONTENT_TYPE) - if not 2 <= len(self.meeting_name) < cst.MEETING_NAME_LENGTH: + if not 2 <= len(self.meeting_name) <= cst.MEETING_NAME_LENGTH: return HttpResponse(cst.RETURN_STRING_WRONG_MEETING_NAME_LENGTH, content_type=cst.CONTENT_TYPE) if not await self.is_meeting():