mirror of
https://github.com/mediacms-io/mediacms.git
synced 2025-06-20 19:57:58 +02:00
feat: lib updates and more (#1187)
This PR performs the following changes: - update python in Dockerfile - updates all python libraries (including Django) - makes md5sum calculation redundant by default - updates Postgresql used in Docker. For new installations this is ok. For existing ones this is backwards incompatible, and restore through pg_dump+pg_restore has to be performed in order to utilize Postgres 17 (since its not compatible with previous versions and will complain) - fixes issues with HLS, and adds test to ensure they won't happen again - allows . and @ in usernames
This commit is contained in:
parent
a7562c244e
commit
0392dbe1ed
122
Dockerfile
122
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"]
|
# Install system dependencies needed for downloading and extracting
|
||||||
|
RUN apt-get update -y && \
|
||||||
# Set up virtualenv
|
apt-get install -y --no-install-recommends wget xz-utils unzip && \
|
||||||
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 && \
|
|
||||||
rm -rf /var/lib/apt/lists/* && \
|
rm -rf /var/lib/apt/lists/* && \
|
||||||
apt-get purge --auto-remove && \
|
apt-get purge --auto-remove && \
|
||||||
apt-get clean
|
apt-get clean
|
||||||
|
|
||||||
|
# Install ffmpeg
|
||||||
RUN wget -q https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz && \
|
RUN wget -q https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz && \
|
||||||
mkdir -p ffmpeg-tmp && \
|
mkdir -p ffmpeg-tmp && \
|
||||||
tar -xf ffmpeg-release-amd64-static.tar.xz --strip-components 1 -C 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 && \
|
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
|
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
|
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
|
EXPOSE 9000 80
|
||||||
|
|
||||||
RUN chmod +x ./deploy/docker/entrypoint.sh
|
RUN chmod +x ./deploy/docker/entrypoint.sh
|
||||||
|
|
||||||
ENTRYPOINT ["./deploy/docker/entrypoint.sh"]
|
ENTRYPOINT ["./deploy/docker/entrypoint.sh"]
|
||||||
|
CMD ["./deploy/docker/start.sh"]
|
||||||
CMD ["./deploy/docker/start.sh"]
|
|
@ -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"]
|
|
4
Makefile
4
Makefile
@ -10,9 +10,9 @@ admin-shell:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
build-frontend:
|
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/
|
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:
|
test:
|
||||||
docker compose -f docker-compose-dev.yaml exec --env TESTING=True -T web pytest
|
docker compose -f docker-compose-dev.yaml exec --env TESTING=True -T web pytest
|
||||||
|
@ -41,9 +41,10 @@ MIDDLEWARE = [
|
|||||||
'django.contrib.messages.middleware.MessageMiddleware',
|
'django.contrib.messages.middleware.MessageMiddleware',
|
||||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||||
'debug_toolbar.middleware.DebugToolbarMiddleware',
|
'debug_toolbar.middleware.DebugToolbarMiddleware',
|
||||||
|
"allauth.account.middleware.AccountMiddleware",
|
||||||
]
|
]
|
||||||
|
|
||||||
DEBUG = True
|
DEBUG = True
|
||||||
CORS_ORIGIN_ALLOW_ALL = True
|
CORS_ORIGIN_ALLOW_ALL = True
|
||||||
STATICFILES_DIRS = (os.path.join(BASE_DIR, 'static/'),)
|
# STATICFILES_DIRS = (os.path.join(BASE_DIR, 'static_files/'),)
|
||||||
STATIC_ROOT = None
|
STATIC_ROOT = os.path.join(BASE_DIR, 'static_collected')
|
||||||
|
@ -111,7 +111,7 @@ TIME_TO_ACTION_ANONYMOUS = 10 * 60
|
|||||||
|
|
||||||
# django-allauth settings
|
# django-allauth settings
|
||||||
ACCOUNT_SESSION_REMEMBER = True
|
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_REQUIRED = True # new users need to specify email
|
||||||
ACCOUNT_EMAIL_VERIFICATION = "optional" # 'mandatory' 'none'
|
ACCOUNT_EMAIL_VERIFICATION = "optional" # 'mandatory' 'none'
|
||||||
ACCOUNT_LOGIN_ON_EMAIL_CONFIRMATION = True
|
ACCOUNT_LOGIN_ON_EMAIL_CONFIRMATION = True
|
||||||
@ -123,8 +123,6 @@ ACCOUNT_SIGNUP_PASSWORD_ENTER_TWICE = False
|
|||||||
ACCOUNT_USERNAME_REQUIRED = True
|
ACCOUNT_USERNAME_REQUIRED = True
|
||||||
ACCOUNT_LOGIN_ON_PASSWORD_RESET = True
|
ACCOUNT_LOGIN_ON_PASSWORD_RESET = True
|
||||||
ACCOUNT_EMAIL_CONFIRMATION_EXPIRE_DAYS = 1
|
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
|
# registration won't be open, might also consider to remove links for register
|
||||||
USERS_CAN_SELF_REGISTER = True
|
USERS_CAN_SELF_REGISTER = True
|
||||||
|
|
||||||
@ -230,7 +228,7 @@ POST_UPLOAD_AUTHOR_MESSAGE_UNLISTED_NO_COMMENTARY = ""
|
|||||||
|
|
||||||
CANNOT_ADD_MEDIA_MESSAGE = ""
|
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"
|
MP4HLS_COMMAND = "/home/mediacms.io/mediacms/Bento4-SDK-1-6-0-637.x86_64-unknown-linux/bin/mp4hls"
|
||||||
|
|
||||||
# highly experimental, related with remote workers
|
# highly experimental, related with remote workers
|
||||||
@ -322,6 +320,7 @@ MIDDLEWARE = [
|
|||||||
"django.contrib.messages.middleware.MessageMiddleware",
|
"django.contrib.messages.middleware.MessageMiddleware",
|
||||||
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
||||||
"debug_toolbar.middleware.DebugToolbarMiddleware",
|
"debug_toolbar.middleware.DebugToolbarMiddleware",
|
||||||
|
"allauth.account.middleware.AccountMiddleware",
|
||||||
]
|
]
|
||||||
|
|
||||||
ROOT_URLCONF = "cms.urls"
|
ROOT_URLCONF = "cms.urls"
|
||||||
@ -542,3 +541,5 @@ SPRITE_NUM_SECS = 10
|
|||||||
|
|
||||||
# how many images will be shown on the slideshow
|
# how many images will be shown on the slideshow
|
||||||
SLIDESHOW_ITEMS = 30
|
SLIDESHOW_ITEMS = 30
|
||||||
|
# this calculation is redundant most probably, setting as an option
|
||||||
|
CALCULATE_MD5SUM = False
|
||||||
|
@ -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
|
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}
|
mkdir -p /home/mediacms.io/mediacms/{logs,media_files/hls}
|
||||||
touch /home/mediacms.io/mediacms/logs/debug.log
|
touch /home/mediacms.io/mediacms/logs/debug.log
|
||||||
|
|
||||||
|
99
deploy/docker/policy.xml
Normal file
99
deploy/docker/policy.xml
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE policymap [
|
||||||
|
<!ELEMENT policymap (policy)*>
|
||||||
|
<!ATTLIST policymap xmlns CDATA #FIXED ''>
|
||||||
|
<!ELEMENT policy EMPTY>
|
||||||
|
<!ATTLIST policy xmlns CDATA #FIXED '' domain NMTOKEN #REQUIRED
|
||||||
|
name NMTOKEN #IMPLIED pattern CDATA #IMPLIED rights NMTOKEN #IMPLIED
|
||||||
|
stealth NMTOKEN #IMPLIED value CDATA #IMPLIED>
|
||||||
|
]>
|
||||||
|
<!--
|
||||||
|
Configure ImageMagick policies.
|
||||||
|
|
||||||
|
Domains include system, delegate, coder, filter, path, or resource.
|
||||||
|
|
||||||
|
Rights include none, read, write, execute and all. Use | to combine them,
|
||||||
|
for example: "read | write" to permit read from, or write to, a path.
|
||||||
|
|
||||||
|
Use a glob expression as a pattern.
|
||||||
|
|
||||||
|
Suppose we do not want users to process MPEG video images:
|
||||||
|
|
||||||
|
<policy domain="delegate" rights="none" pattern="mpeg:decode" />
|
||||||
|
|
||||||
|
Here we do not want users reading images from HTTP:
|
||||||
|
|
||||||
|
<policy domain="coder" rights="none" pattern="HTTP" />
|
||||||
|
|
||||||
|
The /repository file system is restricted to read only. We use a glob
|
||||||
|
expression to match all paths that start with /repository:
|
||||||
|
|
||||||
|
<policy domain="path" rights="read" pattern="/repository/*" />
|
||||||
|
|
||||||
|
Lets prevent users from executing any image filters:
|
||||||
|
|
||||||
|
<policy domain="filter" rights="none" pattern="*" />
|
||||||
|
|
||||||
|
Any large image is cached to disk rather than memory:
|
||||||
|
|
||||||
|
<policy domain="resource" name="area" value="1GP"/>
|
||||||
|
|
||||||
|
Use the default system font unless overwridden by the application:
|
||||||
|
|
||||||
|
<policy domain="system" name="font" value="/usr/share/fonts/favorite.ttf"/>
|
||||||
|
|
||||||
|
Define arguments for the memory, map, area, width, height and disk resources
|
||||||
|
with SI prefixes (.e.g 100MB). In addition, resource policies are maximums
|
||||||
|
for each instance of ImageMagick (e.g. policy memory limit 1GB, -limit 2GB
|
||||||
|
exceeds policy maximum so memory limit is 1GB).
|
||||||
|
|
||||||
|
Rules are processed in order. Here we want to restrict ImageMagick to only
|
||||||
|
read or write a small subset of proven web-safe image types:
|
||||||
|
|
||||||
|
<policy domain="delegate" rights="none" pattern="*" />
|
||||||
|
<policy domain="filter" rights="none" pattern="*" />
|
||||||
|
<policy domain="coder" rights="none" pattern="*" />
|
||||||
|
<policy domain="coder" rights="read|write" pattern="{GIF,JPEG,PNG,WEBP}" />
|
||||||
|
-->
|
||||||
|
<policymap>
|
||||||
|
<!-- <policy domain="resource" name="temporary-path" value="/tmp"/> -->
|
||||||
|
<policy domain="resource" name="memory" value="1GiB"/>
|
||||||
|
<policy domain="resource" name="map" value="30GiB"/>
|
||||||
|
<policy domain="resource" name="width" value="16MP"/>
|
||||||
|
<policy domain="resource" name="height" value="16MP"/>
|
||||||
|
<!-- <policy domain="resource" name="list-length" value="128"/> -->
|
||||||
|
<policy domain="resource" name="area" value="40GP"/>
|
||||||
|
<policy domain="resource" name="disk" value="100GiB"/>
|
||||||
|
<!-- <policy domain="resource" name="file" value="768"/> -->
|
||||||
|
<!-- <policy domain="resource" name="thread" value="4"/> -->
|
||||||
|
<!-- <policy domain="resource" name="throttle" value="0"/> -->
|
||||||
|
<!-- <policy domain="resource" name="time" value="3600"/> -->
|
||||||
|
<!-- <policy domain="coder" rights="none" pattern="MVG" /> -->
|
||||||
|
<!-- <policy domain="module" rights="none" pattern="{PS,PDF,XPS}" /> -->
|
||||||
|
<!-- <policy domain="path" rights="none" pattern="@*" /> -->
|
||||||
|
<!-- <policy domain="cache" name="memory-map" value="anonymous"/> -->
|
||||||
|
<!-- <policy domain="cache" name="synchronize" value="True"/> -->
|
||||||
|
<!-- <policy domain="cache" name="shared-secret" value="passphrase" stealth="true"/>
|
||||||
|
<!-- <policy domain="system" name="max-memory-request" value="256MiB"/> -->
|
||||||
|
<!-- <policy domain="system" name="shred" value="2"/> -->
|
||||||
|
<!-- <policy domain="system" name="precision" value="6"/> -->
|
||||||
|
<!-- <policy domain="system" name="font" value="/path/to/font.ttf"/> -->
|
||||||
|
<!-- <policy domain="system" name="pixel-cache-memory" value="anonymous"/> -->
|
||||||
|
<!-- <policy domain="system" name="shred" value="2"/> -->
|
||||||
|
<!-- <policy domain="system" name="precision" value="6"/> -->
|
||||||
|
<!-- not needed due to the need to use explicitly by mvg: -->
|
||||||
|
<!-- <policy domain="delegate" rights="none" pattern="MVG" /> -->
|
||||||
|
<!-- use curl -->
|
||||||
|
<policy domain="delegate" rights="none" pattern="URL" />
|
||||||
|
<policy domain="delegate" rights="none" pattern="HTTPS" />
|
||||||
|
<policy domain="delegate" rights="none" pattern="HTTP" />
|
||||||
|
<!-- in order to avoid to get image with password text -->
|
||||||
|
<policy domain="path" rights="none" pattern="@*"/>
|
||||||
|
<!-- disable ghostscript format types -->
|
||||||
|
<policy domain="coder" rights="none" pattern="PS" />
|
||||||
|
<policy domain="coder" rights="none" pattern="PS2" />
|
||||||
|
<policy domain="coder" rights="none" pattern="PS3" />
|
||||||
|
<policy domain="coder" rights="none" pattern="EPS" />
|
||||||
|
<policy domain="coder" rights="none" pattern="PDF" />
|
||||||
|
<policy domain="coder" rights="none" pattern="XPS" />
|
||||||
|
</policymap>
|
@ -4,13 +4,23 @@ services:
|
|||||||
migrations:
|
migrations:
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: ./Dockerfile-dev
|
dockerfile: ./Dockerfile
|
||||||
|
args:
|
||||||
|
- DEVELOPMENT_MODE=True
|
||||||
image: mediacms/mediacms-dev:latest
|
image: mediacms/mediacms-dev:latest
|
||||||
volumes:
|
volumes:
|
||||||
- ./:/home/mediacms.io/mediacms/
|
- ./:/home/mediacms.io/mediacms/
|
||||||
command: "python manage.py migrate"
|
command: "./deploy/docker/prestart.sh"
|
||||||
environment:
|
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
|
restart: on-failure
|
||||||
depends_on:
|
depends_on:
|
||||||
redis:
|
redis:
|
||||||
@ -30,16 +40,10 @@ services:
|
|||||||
depends_on:
|
depends_on:
|
||||||
- web
|
- web
|
||||||
web:
|
web:
|
||||||
build:
|
|
||||||
context: .
|
|
||||||
dockerfile: ./Dockerfile-dev
|
|
||||||
image: mediacms/mediacms-dev:latest
|
image: mediacms/mediacms-dev:latest
|
||||||
command: "python manage.py runserver 0.0.0.0:80"
|
command: "python manage.py runserver 0.0.0.0:80"
|
||||||
environment:
|
environment:
|
||||||
DEVELOPMENT_MODE: "True"
|
DEVELOPMENT_MODE: True
|
||||||
ADMIN_USER: 'admin'
|
|
||||||
ADMIN_PASSWORD: 'admin'
|
|
||||||
ADMIN_EMAIL: 'admin@localhost'
|
|
||||||
ports:
|
ports:
|
||||||
- "80:80"
|
- "80:80"
|
||||||
volumes:
|
volumes:
|
||||||
@ -47,7 +51,7 @@ services:
|
|||||||
depends_on:
|
depends_on:
|
||||||
- migrations
|
- migrations
|
||||||
db:
|
db:
|
||||||
image: postgres:15.2-alpine
|
image: postgres:17.2-alpine
|
||||||
volumes:
|
volumes:
|
||||||
- ../postgres_data:/var/lib/postgresql/data/
|
- ../postgres_data:/var/lib/postgresql/data/
|
||||||
restart: always
|
restart: always
|
||||||
@ -80,5 +84,6 @@ services:
|
|||||||
ENABLE_NGINX: 'no'
|
ENABLE_NGINX: 'no'
|
||||||
ENABLE_CELERY_BEAT: 'no'
|
ENABLE_CELERY_BEAT: 'no'
|
||||||
ENABLE_MIGRATIONS: 'no'
|
ENABLE_MIGRATIONS: 'no'
|
||||||
|
DEVELOPMENT_MODE: True
|
||||||
depends_on:
|
depends_on:
|
||||||
- web
|
- web
|
||||||
|
@ -68,7 +68,7 @@ services:
|
|||||||
depends_on:
|
depends_on:
|
||||||
- migrations
|
- migrations
|
||||||
db:
|
db:
|
||||||
image: postgres:15.2-alpine
|
image: postgres:17.2-alpine
|
||||||
volumes:
|
volumes:
|
||||||
- ../postgres_data/:/var/lib/postgresql/data/
|
- ../postgres_data/:/var/lib/postgresql/data/
|
||||||
restart: always
|
restart: always
|
||||||
|
@ -70,7 +70,7 @@ services:
|
|||||||
depends_on:
|
depends_on:
|
||||||
- migrations
|
- migrations
|
||||||
db:
|
db:
|
||||||
image: postgres:15.2-alpine
|
image: postgres:17.2-alpine
|
||||||
volumes:
|
volumes:
|
||||||
- ../postgres_data/:/var/lib/postgresql/data/
|
- ../postgres_data/:/var/lib/postgresql/data/
|
||||||
restart: always
|
restart: always
|
||||||
|
@ -90,7 +90,7 @@ services:
|
|||||||
depends_on:
|
depends_on:
|
||||||
- migrations
|
- migrations
|
||||||
db:
|
db:
|
||||||
image: postgres:15.2-alpine
|
image: postgres:17.2-alpine
|
||||||
volumes:
|
volumes:
|
||||||
- ../postgres_data:/var/lib/postgresql/data/
|
- ../postgres_data:/var/lib/postgresql/data/
|
||||||
restart: always
|
restart: always
|
||||||
|
@ -66,7 +66,7 @@ services:
|
|||||||
depends_on:
|
depends_on:
|
||||||
- migrations
|
- migrations
|
||||||
db:
|
db:
|
||||||
image: postgres:15.2-alpine
|
image: postgres:17.2-alpine
|
||||||
volumes:
|
volumes:
|
||||||
- postgres_data:/var/lib/postgresql/data/
|
- postgres_data:/var/lib/postgresql/data/
|
||||||
restart: always
|
restart: always
|
||||||
|
@ -62,7 +62,7 @@ services:
|
|||||||
depends_on:
|
depends_on:
|
||||||
- migrations
|
- migrations
|
||||||
db:
|
db:
|
||||||
image: postgres:15.2-alpine
|
image: postgres:17.2-alpine
|
||||||
volumes:
|
volumes:
|
||||||
- ../postgres_data:/var/lib/postgresql/data/
|
- ../postgres_data:/var/lib/postgresql/data/
|
||||||
restart: always
|
restart: always
|
||||||
|
@ -15,7 +15,7 @@ class VideoEncodingError(Exception):
|
|||||||
|
|
||||||
|
|
||||||
RE_TIMECODE = re.compile(r"time=(\d+:\d+:\d+.\d+)")
|
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):
|
class FFmpegBackend(object):
|
||||||
|
@ -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 = 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]
|
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
|
cmd_convert = ["convert", *image_files, "-append", output_name] # image files, unpacked into the list
|
||||||
|
ret = run_command(cmd_convert) # noqa
|
||||||
run_command(cmd_convert)
|
|
||||||
|
|
||||||
if os.path.exists(output_name) and get_file_type(output_name) == "image":
|
if os.path.exists(output_name) and get_file_type(output_name) == "image":
|
||||||
with open(output_name, "rb") as f:
|
with open(output_name, "rb") as f:
|
||||||
@ -402,8 +401,8 @@ def produce_sprite_from_video(friendly_token):
|
|||||||
content=myfile,
|
content=myfile,
|
||||||
name=get_file_name(media.media_file.path) + "sprites.jpg",
|
name=get_file_name(media.media_file.path) + "sprites.jpg",
|
||||||
)
|
)
|
||||||
except BaseException:
|
except Exception as e:
|
||||||
pass
|
print(e)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
@ -428,13 +427,14 @@ def create_hls(friendly_token):
|
|||||||
p = media.uid.hex
|
p = media.uid.hex
|
||||||
output_dir = os.path.join(settings.HLS_DIR, p)
|
output_dir = os.path.join(settings.HLS_DIR, p)
|
||||||
encodings = media.encodings.filter(profile__extension="mp4", status="success", chunk=False, profile__codec="h264")
|
encodings = media.encodings.filter(profile__extension="mp4", status="success", chunk=False, profile__codec="h264")
|
||||||
|
|
||||||
if encodings:
|
if encodings:
|
||||||
existing_output_dir = None
|
existing_output_dir = None
|
||||||
if os.path.exists(output_dir):
|
if os.path.exists(output_dir):
|
||||||
existing_output_dir = output_dir
|
existing_output_dir = output_dir
|
||||||
output_dir = os.path.join(settings.HLS_DIR, p + produce_friendly_token())
|
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])
|
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]
|
cmd = [settings.MP4HLS_COMMAND, '--segment-duration=4', f'--output-dir={output_dir}', *files]
|
||||||
run_command(cmd)
|
run_command(cmd)
|
||||||
|
|
||||||
if existing_output_dir:
|
if existing_output_dir:
|
||||||
|
@ -1,16 +1,15 @@
|
|||||||
-r requirements.txt
|
-r requirements.txt
|
||||||
|
|
||||||
rpdb
|
rpdb==0.2.0
|
||||||
tqdm
|
tqdm==4.67.1
|
||||||
ipython
|
ipython==8.32.0
|
||||||
flake8
|
flake8==7.1.1
|
||||||
pylint
|
pylint==3.3.4
|
||||||
pep8
|
pep8==1.7.1
|
||||||
django-silk
|
django-silk==5.3.2
|
||||||
pre-commit
|
pytest-cov==6.0.0
|
||||||
pytest-cov
|
pytest-django==4.9.0
|
||||||
pytest-django
|
pytest-factoryboy==2.7.0
|
||||||
pytest-factoryboy
|
Faker==35.2.0
|
||||||
Faker
|
django-cors-headers==4.7.0
|
||||||
django-cors-headers
|
|
||||||
|
|
||||||
|
@ -1,21 +1,22 @@
|
|||||||
Django==4.2.2
|
Django==5.1.6
|
||||||
djangorestframework==3.14.0
|
djangorestframework==3.15.2
|
||||||
django-allauth==0.54.0
|
django-allauth==65.4.1
|
||||||
psycopg==3.1.9
|
psycopg==3.2.4
|
||||||
uwsgi==2.0.21
|
uwsgi==2.0.28
|
||||||
django-redis==5.3.0
|
django-redis==5.4.0
|
||||||
celery==5.3.1
|
celery==5.4.0
|
||||||
drf-yasg==1.21.6
|
drf-yasg==1.21.8
|
||||||
Pillow==9.5.0
|
Pillow==11.1.0
|
||||||
django-imagekit==4.1.0
|
django-imagekit==5.0.0
|
||||||
markdown==3.4.3
|
markdown==3.7
|
||||||
django-filter==23.2
|
django-filter==24.3
|
||||||
filetype==1.2.0
|
filetype==1.2.0
|
||||||
django-mptt==0.14.0
|
django-mptt==0.16.0
|
||||||
django-crispy-forms==1.13.0
|
django-crispy-forms==2.3
|
||||||
requests==2.31.0
|
requests==2.32.3
|
||||||
django-celery-email==3.0.0
|
django-celery-email==3.0.0
|
||||||
m3u8==3.5.0
|
m3u8==6.0.0
|
||||||
django-ckeditor==6.6.1
|
django-ckeditor==6.7.2
|
||||||
django-debug-toolbar==4.1.0
|
django-debug-toolbar==5.0.1
|
||||||
django-login-required-middleware==0.9.0
|
django-login-required-middleware==0.9.0
|
||||||
|
pre-commit==4.1.0
|
||||||
|
@ -35,13 +35,14 @@ class TestX(TestCase):
|
|||||||
client.post('/fu/upload/', {'qqfile': fp, 'qqfilename': 'medium_video.mp4', 'qquuid': str(uuid.uuid4())})
|
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")
|
self.assertEqual(Media.objects.all().count(), 3, "Problem with file upload")
|
||||||
|
|
||||||
# by default the portal_workflow is public, so anything uploaded gets public
|
# 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(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', 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='video').count(), 2, "Media identification failed")
|
||||||
self.assertEqual(Media.objects.filter(media_type='image').count(), 1, "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")
|
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.
|
# using the provided EncodeProfiles, these two files should produce 9 Encoding objects.
|
||||||
# if new EncodeProfiles are added and enabled, this will break!
|
# if new EncodeProfiles are added and enabled, this will break!
|
||||||
|
@ -93,16 +93,16 @@ class LoginSerializer(serializers.Serializer):
|
|||||||
username = data.get('username', None)
|
username = data.get('username', None)
|
||||||
password = data.get('password', 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.')
|
raise serializers.ValidationError('username is required to log in.')
|
||||||
else:
|
else:
|
||||||
username_or_email = username
|
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.')
|
raise serializers.ValidationError('email is required to log in.')
|
||||||
else:
|
else:
|
||||||
username_or_email = email
|
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.')
|
raise serializers.ValidationError('username or email is required to log in.')
|
||||||
else:
|
else:
|
||||||
username_or_email = username or email
|
username_or_email = username or email
|
||||||
|
@ -7,7 +7,7 @@ from django.utils.translation import gettext_lazy as _
|
|||||||
|
|
||||||
@deconstructible
|
@deconstructible
|
||||||
class ASCIIUsernameValidator(validators.RegexValidator):
|
class ASCIIUsernameValidator(validators.RegexValidator):
|
||||||
regex = r"^[\w]+$"
|
regex = r"^[\w.@]+$"
|
||||||
message = _("Enter a valid username. This value may contain only " "English letters and numbers")
|
message = _("Enter a valid username. This value may contain only " "English letters and numbers")
|
||||||
flags = re.ASCII
|
flags = re.ASCII
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user