Use custom validator for urls fields to allow for non fqdn hostnames.

Fixes #63
This commit is contained in:
SergeantPanda 2025-08-01 11:28:51 -05:00
parent 953db79476
commit 7b5a617bf8
4 changed files with 55 additions and 2 deletions

View file

@ -16,6 +16,7 @@ from apps.epg.models import EPGData
from django.urls import reverse
from rest_framework import serializers
from django.utils import timezone
from core.utils import validate_flexible_url
class LogoSerializer(serializers.ModelSerializer):
@ -32,10 +33,10 @@ class LogoSerializer(serializers.ModelSerializer):
"""Validate that the URL is unique for creation or update"""
if self.instance and self.instance.url == value:
return value
if Logo.objects.filter(url=value).exists():
raise serializers.ValidationError("A logo with this URL already exists.")
return value
def create(self, validated_data):
@ -79,6 +80,12 @@ class LogoSerializer(serializers.ModelSerializer):
# Stream
#
class StreamSerializer(serializers.ModelSerializer):
url = serializers.CharField(
required=False,
allow_blank=True,
allow_null=True,
validators=[validate_flexible_url]
)
stream_profile_id = serializers.PrimaryKeyRelatedField(
queryset=StreamProfile.objects.all(),
source="stream_profile",

View file

@ -1,3 +1,4 @@
from core.utils import validate_flexible_url
from rest_framework import serializers
from .models import EPGSource, EPGData, ProgramData
from apps.channels.models import Channel
@ -5,6 +6,12 @@ from apps.channels.models import Channel
class EPGSourceSerializer(serializers.ModelSerializer):
epg_data_ids = serializers.SerializerMethodField()
read_only_fields = ['created_at', 'updated_at']
url = serializers.CharField(
required=False,
allow_blank=True,
allow_null=True,
validators=[validate_flexible_url]
)
class Meta:
model = EPGSource

View file

@ -1,3 +1,4 @@
from core.utils import validate_flexible_url
from rest_framework import serializers
from rest_framework.response import Response
from .models import M3UAccount, M3UFilter, ServerGroup, M3UAccountProfile
@ -76,6 +77,12 @@ class M3UAccountSerializer(serializers.ModelSerializer):
channel_groups = ChannelGroupM3UAccountSerializer(
source="channel_group", many=True, required=False
)
server_url = serializers.CharField(
required=False,
allow_blank=True,
allow_null=True,
validators=[validate_flexible_url],
)
class Meta:
model = M3UAccount

View file

@ -9,6 +9,8 @@ from redis.exceptions import ConnectionError, TimeoutError
from django.core.cache import cache
from asgiref.sync import async_to_sync
from channels.layers import get_channel_layer
from django.core.validators import URLValidator
from django.core.exceptions import ValidationError
import gc
logger = logging.getLogger(__name__)
@ -354,3 +356,33 @@ def is_protected_path(file_path):
return True
return False
def validate_flexible_url(value):
"""
Custom URL validator that accepts URLs with hostnames that aren't FQDNs.
This allows URLs like "http://hostname/" which
Django's standard URLValidator rejects.
"""
if not value:
return # Allow empty values since the field is nullable
# Create a standard Django URL validator
url_validator = URLValidator()
try:
# First try the standard validation
url_validator(value)
except ValidationError as e:
# If standard validation fails, check if it's a non-FQDN hostname
import re
# More flexible pattern for non-FQDN hostnames with paths
# Matches: http://hostname, http://hostname/, http://hostname:port/path/to/file.xml
non_fqdn_pattern = r'^https?://[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?(\:[0-9]+)?(/[^\s]*)?$'
non_fqdn_match = re.match(non_fqdn_pattern, value)
if non_fqdn_match:
return # Accept non-FQDN hostnames
# If it doesn't match our flexible patterns, raise the original error
raise ValidationError("Enter a valid URL.")