diff --git a/Dockerfile b/Dockerfile index af6ae1cd..304f31c8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,70 +1,88 @@ -FROM python:3.11.4-bookworm AS compile-image +FROM python:3.13-bookworm AS build-image -SHELL ["/bin/bash", "-c"] - -# Set up virtualenv -ENV VIRTUAL_ENV=/home/mediacms.io -ENV PATH="$VIRTUAL_ENV/bin:$PATH" -ENV PIP_NO_CACHE_DIR=1 - -RUN mkdir -p /home/mediacms.io/mediacms/{logs} && cd /home/mediacms.io && python3 -m venv $VIRTUAL_ENV - -# Install dependencies: -COPY requirements.txt . - -RUN pip install -r requirements.txt - -COPY . /home/mediacms.io/mediacms -WORKDIR /home/mediacms.io/mediacms - -RUN wget -q http://zebulon.bok.net/Bento4/binaries/Bento4-SDK-1-6-0-637.x86_64-unknown-linux.zip && \ - unzip Bento4-SDK-1-6-0-637.x86_64-unknown-linux.zip -d ../bento4 && \ - mv ../bento4/Bento4-SDK-1-6-0-637.x86_64-unknown-linux/* ../bento4/ && \ - rm -rf ../bento4/Bento4-SDK-1-6-0-637.x86_64-unknown-linux && \ - rm -rf ../bento4/docs && \ - rm Bento4-SDK-1-6-0-637.x86_64-unknown-linux.zip - -############ RUNTIME IMAGE ############ -FROM python:3.11.4-bookworm as runtime-image - -ENV PYTHONUNBUFFERED=1 -ENV PYTHONDONTWRITEBYTECODE=1 - -# See: https://github.com/celery/celery/issues/6285#issuecomment-715316219 -ENV CELERY_APP='cms' - -# Use these to toggle which processes supervisord should run -ENV ENABLE_UWSGI='yes' -ENV ENABLE_NGINX='yes' -ENV ENABLE_CELERY_BEAT='yes' -ENV ENABLE_CELERY_SHORT='yes' -ENV ENABLE_CELERY_LONG='yes' -ENV ENABLE_MIGRATIONS='yes' - -# Set up virtualenv -ENV VIRTUAL_ENV=/home/mediacms.io -ENV PATH="$VIRTUAL_ENV/bin:$PATH" - -COPY --chown=www-data:www-data --from=compile-image /home/mediacms.io /home/mediacms.io - -RUN apt-get update -y && apt-get -y upgrade && apt-get install --no-install-recommends \ - supervisor nginx imagemagick procps wget xz-utils -y && \ +# Install system dependencies needed for downloading and extracting +RUN apt-get update -y && \ + apt-get install -y --no-install-recommends wget xz-utils unzip && \ rm -rf /var/lib/apt/lists/* && \ apt-get purge --auto-remove && \ apt-get clean +# Install ffmpeg RUN wget -q https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz && \ mkdir -p ffmpeg-tmp && \ tar -xf ffmpeg-release-amd64-static.tar.xz --strip-components 1 -C ffmpeg-tmp && \ cp -v ffmpeg-tmp/ffmpeg ffmpeg-tmp/ffprobe ffmpeg-tmp/qt-faststart /usr/local/bin && \ rm -rf ffmpeg-tmp ffmpeg-release-amd64-static.tar.xz +# Install Bento4 in the specified location +RUN mkdir -p /home/mediacms.io/bento4 && \ + wget -q http://zebulon.bok.net/Bento4/binaries/Bento4-SDK-1-6-0-637.x86_64-unknown-linux.zip && \ + unzip Bento4-SDK-1-6-0-637.x86_64-unknown-linux.zip -d /home/mediacms.io/bento4 && \ + mv /home/mediacms.io/bento4/Bento4-SDK-1-6-0-637.x86_64-unknown-linux/* /home/mediacms.io/bento4/ && \ + rm -rf /home/mediacms.io/bento4/Bento4-SDK-1-6-0-637.x86_64-unknown-linux && \ + rm -rf /home/mediacms.io/bento4/docs && \ + rm Bento4-SDK-1-6-0-637.x86_64-unknown-linux.zip + +############ RUNTIME IMAGE ############ +FROM python:3.13-bookworm as runtime-image + +SHELL ["/bin/bash", "-c"] + +ENV PYTHONUNBUFFERED=1 +ENV PYTHONDONTWRITEBYTECODE=1 +ENV CELERY_APP='cms' +ENV VIRTUAL_ENV=/home/mediacms.io +ENV PATH="$VIRTUAL_ENV/bin:$PATH" + +# Install runtime system dependencies +RUN apt-get update -y && \ + apt-get -y upgrade && \ + apt-get install --no-install-recommends supervisor nginx imagemagick procps -y && \ + rm -rf /var/lib/apt/lists/* && \ + apt-get purge --auto-remove && \ + apt-get clean + +# Copy ffmpeg and Bento4 from build image +COPY --from=build-image /usr/local/bin/ffmpeg /usr/local/bin/ffmpeg +COPY --from=build-image /usr/local/bin/ffprobe /usr/local/bin/ffprobe +COPY --from=build-image /usr/local/bin/qt-faststart /usr/local/bin/qt-faststart +COPY --from=build-image /home/mediacms.io/bento4 /home/mediacms.io/bento4 + +# Set up virtualenv +RUN mkdir -p /home/mediacms.io/mediacms/{logs} && \ + cd /home/mediacms.io && \ + python3 -m venv $VIRTUAL_ENV + +# Install Python dependencies +COPY requirements.txt requirements-dev.txt ./ + +ARG DEVELOPMENT_MODE=False + +RUN pip install --no-cache-dir -r requirements.txt && \ + if [ "$DEVELOPMENT_MODE" = "True" ]; then \ + echo "Installing development dependencies..." && \ + pip install --no-cache-dir -r requirements-dev.txt; \ + fi + +# Copy application files +COPY . /home/mediacms.io/mediacms WORKDIR /home/mediacms.io/mediacms +# required for sprite thumbnail generation for large video files + +COPY deploy/docker/policy.xml /etc/ImageMagick-6/policy.xml + +# Set process control environment variables +ENV ENABLE_UWSGI='yes' \ + ENABLE_NGINX='yes' \ + ENABLE_CELERY_BEAT='yes' \ + ENABLE_CELERY_SHORT='yes' \ + ENABLE_CELERY_LONG='yes' \ + ENABLE_MIGRATIONS='yes' + EXPOSE 9000 80 RUN chmod +x ./deploy/docker/entrypoint.sh ENTRYPOINT ["./deploy/docker/entrypoint.sh"] - -CMD ["./deploy/docker/start.sh"] +CMD ["./deploy/docker/start.sh"] \ No newline at end of file diff --git a/Dockerfile-dev b/Dockerfile-dev deleted file mode 100644 index d89e6ac6..00000000 --- a/Dockerfile-dev +++ /dev/null @@ -1,73 +0,0 @@ -FROM python:3.11.4-bookworm AS compile-image - -SHELL ["/bin/bash", "-c"] - -# Set up virtualenv -ENV VIRTUAL_ENV=/home/mediacms.io -ENV PATH="$VIRTUAL_ENV/bin:$PATH" -ENV PIP_NO_CACHE_DIR=1 - -RUN mkdir -p /home/mediacms.io/mediacms/{logs} && cd /home/mediacms.io && python3 -m venv $VIRTUAL_ENV - -# Install dependencies: -COPY requirements.txt . -COPY requirements-dev.txt . - -RUN pip install -r requirements.txt - -RUN pip install -r requirements-dev.txt - -COPY . /home/mediacms.io/mediacms -WORKDIR /home/mediacms.io/mediacms - -RUN wget -q http://zebulon.bok.net/Bento4/binaries/Bento4-SDK-1-6-0-637.x86_64-unknown-linux.zip && \ - unzip Bento4-SDK-1-6-0-637.x86_64-unknown-linux.zip -d ../bento4 && \ - mv ../bento4/Bento4-SDK-1-6-0-637.x86_64-unknown-linux/* ../bento4/ && \ - rm -rf ../bento4/Bento4-SDK-1-6-0-637.x86_64-unknown-linux && \ - rm -rf ../bento4/docs && \ - rm Bento4-SDK-1-6-0-637.x86_64-unknown-linux.zip - -############ RUNTIME IMAGE ############ -FROM python:3.11.4-bookworm as runtime-image - -ENV PYTHONUNBUFFERED=1 -ENV PYTHONDONTWRITEBYTECODE=1 - -# See: https://github.com/celery/celery/issues/6285#issuecomment-715316219 -ENV CELERY_APP='cms' - -# Use these to toggle which processes supervisord should run -ENV ENABLE_UWSGI='yes' -ENV ENABLE_NGINX='yes' -ENV ENABLE_CELERY_BEAT='yes' -ENV ENABLE_CELERY_SHORT='yes' -ENV ENABLE_CELERY_LONG='yes' -ENV ENABLE_MIGRATIONS='yes' - -# Set up virtualenv -ENV VIRTUAL_ENV=/home/mediacms.io -ENV PATH="$VIRTUAL_ENV/bin:$PATH" - -COPY --chown=www-data:www-data --from=compile-image /home/mediacms.io /home/mediacms.io - -RUN apt-get update -y && apt-get -y upgrade && apt-get install --no-install-recommends \ - supervisor nginx imagemagick procps wget xz-utils -y && \ - rm -rf /var/lib/apt/lists/* && \ - apt-get purge --auto-remove && \ - apt-get clean - -RUN wget -q https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz && \ - mkdir -p ffmpeg-tmp && \ - tar -xf ffmpeg-release-amd64-static.tar.xz --strip-components 1 -C ffmpeg-tmp && \ - cp -v ffmpeg-tmp/ffmpeg ffmpeg-tmp/ffprobe ffmpeg-tmp/qt-faststart /usr/local/bin && \ - rm -rf ffmpeg-tmp ffmpeg-release-amd64-static.tar.xz - -WORKDIR /home/mediacms.io/mediacms - -EXPOSE 9000 80 - -RUN chmod +x ./deploy/docker/entrypoint.sh - -ENTRYPOINT ["./deploy/docker/entrypoint.sh"] - -CMD ["./deploy/docker/start.sh"] diff --git a/Makefile b/Makefile index 53cefdb1..3d40cb14 100644 --- a/Makefile +++ b/Makefile @@ -10,9 +10,9 @@ admin-shell: fi build-frontend: - docker-compose -f docker-compose-dev.yaml exec frontend npm run dist + docker compose -f docker-compose-dev.yaml exec frontend npm run dist cp -r frontend/dist/static/* static/ - docker-compose -f docker-compose-dev.yaml restart web + docker compose -f docker-compose-dev.yaml restart web test: docker compose -f docker-compose-dev.yaml exec --env TESTING=True -T web pytest diff --git a/cms/dev_settings.py b/cms/dev_settings.py index 1d887196..f9333a0a 100644 --- a/cms/dev_settings.py +++ b/cms/dev_settings.py @@ -41,9 +41,10 @@ MIDDLEWARE = [ 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'debug_toolbar.middleware.DebugToolbarMiddleware', + "allauth.account.middleware.AccountMiddleware", ] DEBUG = True CORS_ORIGIN_ALLOW_ALL = True -STATICFILES_DIRS = (os.path.join(BASE_DIR, 'static/'),) -STATIC_ROOT = None +# STATICFILES_DIRS = (os.path.join(BASE_DIR, 'static_files/'),) +STATIC_ROOT = os.path.join(BASE_DIR, 'static_collected') diff --git a/cms/settings.py b/cms/settings.py index ab27556a..2f6ff436 100644 --- a/cms/settings.py +++ b/cms/settings.py @@ -111,7 +111,7 @@ TIME_TO_ACTION_ANONYMOUS = 10 * 60 # django-allauth settings ACCOUNT_SESSION_REMEMBER = True -ACCOUNT_AUTHENTICATION_METHOD = "username_email" +ACCOUNT_LOGIN_METHODS = {"username", "email"} ACCOUNT_EMAIL_REQUIRED = True # new users need to specify email ACCOUNT_EMAIL_VERIFICATION = "optional" # 'mandatory' 'none' ACCOUNT_LOGIN_ON_EMAIL_CONFIRMATION = True @@ -123,8 +123,6 @@ ACCOUNT_SIGNUP_PASSWORD_ENTER_TWICE = False ACCOUNT_USERNAME_REQUIRED = True ACCOUNT_LOGIN_ON_PASSWORD_RESET = True ACCOUNT_EMAIL_CONFIRMATION_EXPIRE_DAYS = 1 -ACCOUNT_LOGIN_ATTEMPTS_LIMIT = 20 -ACCOUNT_LOGIN_ATTEMPTS_TIMEOUT = 5 # registration won't be open, might also consider to remove links for register USERS_CAN_SELF_REGISTER = True @@ -230,7 +228,7 @@ POST_UPLOAD_AUTHOR_MESSAGE_UNLISTED_NO_COMMENTARY = "" CANNOT_ADD_MEDIA_MESSAGE = "" -# mp4hls command, part of Bendo4 +# mp4hls command, part of Bento4 MP4HLS_COMMAND = "/home/mediacms.io/mediacms/Bento4-SDK-1-6-0-637.x86_64-unknown-linux/bin/mp4hls" # highly experimental, related with remote workers @@ -322,6 +320,7 @@ MIDDLEWARE = [ "django.contrib.messages.middleware.MessageMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware", "debug_toolbar.middleware.DebugToolbarMiddleware", + "allauth.account.middleware.AccountMiddleware", ] ROOT_URLCONF = "cms.urls" @@ -542,3 +541,5 @@ SPRITE_NUM_SECS = 10 # how many images will be shown on the slideshow SLIDESHOW_ITEMS = 30 +# this calculation is redundant most probably, setting as an option +CALCULATE_MD5SUM = False diff --git a/deploy/docker/entrypoint.sh b/deploy/docker/entrypoint.sh index 5745f51a..7925836d 100755 --- a/deploy/docker/entrypoint.sh +++ b/deploy/docker/entrypoint.sh @@ -7,6 +7,7 @@ ln -sf /dev/stdout /var/log/nginx/mediacms.io.access.log && ln -sf /dev/stderr / cp /home/mediacms.io/mediacms/deploy/docker/local_settings.py /home/mediacms.io/mediacms/cms/local_settings.py + mkdir -p /home/mediacms.io/mediacms/{logs,media_files/hls} touch /home/mediacms.io/mediacms/logs/debug.log diff --git a/deploy/docker/policy.xml b/deploy/docker/policy.xml new file mode 100644 index 00000000..4ebd26fa --- /dev/null +++ b/deploy/docker/policy.xml @@ -0,0 +1,99 @@ + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docker-compose-dev.yaml b/docker-compose-dev.yaml index ba449a77..68b77c90 100644 --- a/docker-compose-dev.yaml +++ b/docker-compose-dev.yaml @@ -4,13 +4,23 @@ services: migrations: build: context: . - dockerfile: ./Dockerfile-dev + dockerfile: ./Dockerfile + args: + - DEVELOPMENT_MODE=True image: mediacms/mediacms-dev:latest volumes: - ./:/home/mediacms.io/mediacms/ - command: "python manage.py migrate" + command: "./deploy/docker/prestart.sh" environment: - DEVELOPMENT_MODE: "True" + DEVELOPMENT_MODE: True + ENABLE_UWSGI: 'no' + ENABLE_NGINX: 'no' + ENABLE_CELERY_SHORT: 'no' + ENABLE_CELERY_LONG: 'no' + ENABLE_CELERY_BEAT: 'no' + ADMIN_USER: 'admin' + ADMIN_EMAIL: 'admin@localhost' + ADMIN_PASSWORD: 'admin' restart: on-failure depends_on: redis: @@ -30,16 +40,10 @@ services: depends_on: - web web: - build: - context: . - dockerfile: ./Dockerfile-dev image: mediacms/mediacms-dev:latest command: "python manage.py runserver 0.0.0.0:80" environment: - DEVELOPMENT_MODE: "True" - ADMIN_USER: 'admin' - ADMIN_PASSWORD: 'admin' - ADMIN_EMAIL: 'admin@localhost' + DEVELOPMENT_MODE: True ports: - "80:80" volumes: @@ -47,7 +51,7 @@ services: depends_on: - migrations db: - image: postgres:15.2-alpine + image: postgres:17.2-alpine volumes: - ../postgres_data:/var/lib/postgresql/data/ restart: always @@ -80,5 +84,6 @@ services: ENABLE_NGINX: 'no' ENABLE_CELERY_BEAT: 'no' ENABLE_MIGRATIONS: 'no' + DEVELOPMENT_MODE: True depends_on: - web diff --git a/docker-compose-http-proxy.yaml b/docker-compose-http-proxy.yaml index 16367682..ea3630b6 100644 --- a/docker-compose-http-proxy.yaml +++ b/docker-compose-http-proxy.yaml @@ -68,7 +68,7 @@ services: depends_on: - migrations db: - image: postgres:15.2-alpine + image: postgres:17.2-alpine volumes: - ../postgres_data/:/var/lib/postgresql/data/ restart: always diff --git a/docker-compose-https-proxy.yaml b/docker-compose-https-proxy.yaml index 774a206b..7aa876db 100644 --- a/docker-compose-https-proxy.yaml +++ b/docker-compose-https-proxy.yaml @@ -70,7 +70,7 @@ services: depends_on: - migrations db: - image: postgres:15.2-alpine + image: postgres:17.2-alpine volumes: - ../postgres_data/:/var/lib/postgresql/data/ restart: always diff --git a/docker-compose-letsencrypt.yaml b/docker-compose-letsencrypt.yaml index 8ac29e9b..1dac4dc4 100644 --- a/docker-compose-letsencrypt.yaml +++ b/docker-compose-letsencrypt.yaml @@ -90,7 +90,7 @@ services: depends_on: - migrations db: - image: postgres:15.2-alpine + image: postgres:17.2-alpine volumes: - ../postgres_data:/var/lib/postgresql/data/ restart: always diff --git a/docker-compose-named-volumes.yaml b/docker-compose-named-volumes.yaml index f923a770..8bdeb89a 100644 --- a/docker-compose-named-volumes.yaml +++ b/docker-compose-named-volumes.yaml @@ -66,7 +66,7 @@ services: depends_on: - migrations db: - image: postgres:15.2-alpine + image: postgres:17.2-alpine volumes: - postgres_data:/var/lib/postgresql/data/ restart: always diff --git a/docker-compose.yaml b/docker-compose.yaml index 491b6b07..137b8bee 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -62,7 +62,7 @@ services: depends_on: - migrations db: - image: postgres:15.2-alpine + image: postgres:17.2-alpine volumes: - ../postgres_data:/var/lib/postgresql/data/ restart: always diff --git a/files/backends.py b/files/backends.py index ac130ef3..20d94723 100644 --- a/files/backends.py +++ b/files/backends.py @@ -15,7 +15,7 @@ class VideoEncodingError(Exception): RE_TIMECODE = re.compile(r"time=(\d+:\d+:\d+.\d+)") -console_encoding = locale.getdefaultlocale()[1] or "UTF-8" +console_encoding = locale.getlocale()[1] or "UTF-8" class FFmpegBackend(object): diff --git a/files/tasks.py b/files/tasks.py index e4b706fe..93ed226f 100644 --- a/files/tasks.py +++ b/files/tasks.py @@ -392,8 +392,7 @@ def produce_sprite_from_video(friendly_token): image_files = sorted(image_files, key=lambda x: int(re.search(r'\d+', x).group())) image_files = [os.path.join(tmpdirname, f) for f in image_files] cmd_convert = ["convert", *image_files, "-append", output_name] # image files, unpacked into the list - - run_command(cmd_convert) + ret = run_command(cmd_convert) # noqa if os.path.exists(output_name) and get_file_type(output_name) == "image": with open(output_name, "rb") as f: @@ -402,8 +401,8 @@ def produce_sprite_from_video(friendly_token): content=myfile, name=get_file_name(media.media_file.path) + "sprites.jpg", ) - except BaseException: - pass + except Exception as e: + print(e) return True @@ -428,13 +427,14 @@ def create_hls(friendly_token): p = media.uid.hex output_dir = os.path.join(settings.HLS_DIR, p) encodings = media.encodings.filter(profile__extension="mp4", status="success", chunk=False, profile__codec="h264") + if encodings: existing_output_dir = None if os.path.exists(output_dir): existing_output_dir = output_dir output_dir = os.path.join(settings.HLS_DIR, p + produce_friendly_token()) - files = " ".join([f.media_file.path for f in encodings if f.media_file]) - cmd = [settings.MP4HLS_COMMAND, '--segment-duration=4', f'--output-dir={output_dir}', files] + files = [f.media_file.path for f in encodings if f.media_file] + cmd = [settings.MP4HLS_COMMAND, '--segment-duration=4', f'--output-dir={output_dir}', *files] run_command(cmd) if existing_output_dir: diff --git a/requirements-dev.txt b/requirements-dev.txt index 021bee5b..4a906ee9 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,16 +1,15 @@ -r requirements.txt -rpdb -tqdm -ipython -flake8 -pylint -pep8 -django-silk -pre-commit -pytest-cov -pytest-django -pytest-factoryboy -Faker -django-cors-headers +rpdb==0.2.0 +tqdm==4.67.1 +ipython==8.32.0 +flake8==7.1.1 +pylint==3.3.4 +pep8==1.7.1 +django-silk==5.3.2 +pytest-cov==6.0.0 +pytest-django==4.9.0 +pytest-factoryboy==2.7.0 +Faker==35.2.0 +django-cors-headers==4.7.0 diff --git a/requirements.txt b/requirements.txt index acbb677a..08767075 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,21 +1,22 @@ -Django==4.2.2 -djangorestframework==3.14.0 -django-allauth==0.54.0 -psycopg==3.1.9 -uwsgi==2.0.21 -django-redis==5.3.0 -celery==5.3.1 -drf-yasg==1.21.6 -Pillow==9.5.0 -django-imagekit==4.1.0 -markdown==3.4.3 -django-filter==23.2 +Django==5.1.6 +djangorestframework==3.15.2 +django-allauth==65.4.1 +psycopg==3.2.4 +uwsgi==2.0.28 +django-redis==5.4.0 +celery==5.4.0 +drf-yasg==1.21.8 +Pillow==11.1.0 +django-imagekit==5.0.0 +markdown==3.7 +django-filter==24.3 filetype==1.2.0 -django-mptt==0.14.0 -django-crispy-forms==1.13.0 -requests==2.31.0 +django-mptt==0.16.0 +django-crispy-forms==2.3 +requests==2.32.3 django-celery-email==3.0.0 -m3u8==3.5.0 -django-ckeditor==6.6.1 -django-debug-toolbar==4.1.0 +m3u8==6.0.0 +django-ckeditor==6.7.2 +django-debug-toolbar==5.0.1 django-login-required-middleware==0.9.0 +pre-commit==4.1.0 diff --git a/tests/api/test_new_media.py b/tests/api/test_new_media.py index 45e6f401..d43d7184 100644 --- a/tests/api/test_new_media.py +++ b/tests/api/test_new_media.py @@ -35,13 +35,14 @@ class TestX(TestCase): client.post('/fu/upload/', {'qqfile': fp, 'qqfilename': 'medium_video.mp4', 'qquuid': str(uuid.uuid4())}) self.assertEqual(Media.objects.all().count(), 3, "Problem with file upload") - # by default the portal_workflow is public, so anything uploaded gets public self.assertEqual(Media.objects.filter(state='public').count(), 3, "Expected all media to be public, as per the default portal workflow") self.assertEqual(Media.objects.filter(media_type='video', encoding_status='success').count(), 2, "Encoding did not finish well") self.assertEqual(Media.objects.filter(media_type='video').count(), 2, "Media identification failed") self.assertEqual(Media.objects.filter(media_type='image').count(), 1, "Media identification failed") self.assertEqual(Media.objects.filter(user=self.user).count(), 3, "User assignment failed") + medium_video = Media.objects.get(title="medium_video.mp4") + self.assertEqual(len(medium_video.hls_info), 11, "Problem with HLS info") # using the provided EncodeProfiles, these two files should produce 9 Encoding objects. # if new EncodeProfiles are added and enabled, this will break! diff --git a/users/serializers.py b/users/serializers.py index aefb580e..a2740bda 100644 --- a/users/serializers.py +++ b/users/serializers.py @@ -93,16 +93,16 @@ class LoginSerializer(serializers.Serializer): username = data.get('username', None) password = data.get('password', None) - if settings.ACCOUNT_AUTHENTICATION_METHOD == 'username' and not username: + if settings.ACCOUNT_LOGIN_METHODS == {"username"} and not username: raise serializers.ValidationError('username is required to log in.') else: username_or_email = username - if settings.ACCOUNT_AUTHENTICATION_METHOD == 'email' and not email: + if settings.ACCOUNT_LOGIN_METHODS == {"email"} and not email: raise serializers.ValidationError('email is required to log in.') else: username_or_email = email - if settings.ACCOUNT_AUTHENTICATION_METHOD == 'username_email' and not (username or email): + if settings.ACCOUNT_LOGIN_METHODS == {"username", "email"} and not (username or email): raise serializers.ValidationError('username or email is required to log in.') else: username_or_email = username or email diff --git a/users/validators.py b/users/validators.py index d5f21b97..2621cfe8 100644 --- a/users/validators.py +++ b/users/validators.py @@ -7,7 +7,7 @@ from django.utils.translation import gettext_lazy as _ @deconstructible class ASCIIUsernameValidator(validators.RegexValidator): - regex = r"^[\w]+$" + regex = r"^[\w.@]+$" message = _("Enter a valid username. This value may contain only " "English letters and numbers") flags = re.ASCII