Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Openshift #291

Merged
merged 33 commits into from
Jun 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
3d55efa
Test signbank with openshift
henrinie May 9, 2024
fce001f
Fix database settings
henrinie May 9, 2024
4a75d06
add psycopg2-binary
henrinie May 9, 2024
25b0f6e
test django-storages[s3]
henrinie May 9, 2024
e4b664f
fix typo
henrinie May 9, 2024
27b68a3
set defaults for STATIC_ & MEDIA_URL
henrinie May 9, 2024
5aa996f
set bucket name, disable querystring_auth, comment custom_domain
henrinie May 9, 2024
9d725e7
add default values to bucket settings
henrinie May 9, 2024
6228764
uppercase settings
henrinie May 9, 2024
d675070
include flatpages migrations
henrinie May 9, 2024
77beef9
set default acl public-read
henrinie May 9, 2024
bd2b3a3
test with s3storage for videos
henrinie May 9, 2024
88f9a69
Test fixing get_valid_name
henrinie May 14, 2024
b1bfd90
Add temp debug to fix issues
henrinie May 14, 2024
0da03d4
fix issue of no base_url
henrinie May 14, 2024
e0ada86
use url in url, not path
henrinie May 14, 2024
c8b3222
adjust valid_name by removing media
henrinie May 14, 2024
2dfcae8
adjust file renaming
henrinie May 14, 2024
3f75ee8
Try default url
henrinie May 14, 2024
d11e257
use storage.move instead of copying files around
henrinie May 14, 2024
622e7d1
remove templatetag urlencode from video and poster files
henrinie May 14, 2024
1e73a37
fix videofile_modified_date
henrinie May 14, 2024
3eee28a
modify renaming logic
henrinie May 14, 2024
47699cd
remove unneeded url function for glossvideostorage
henrinie May 14, 2024
5d3a37e
upload files to media directory
henrinie May 14, 2024
3192cf9
convert canvas to blob to fix insecure access to file from another or…
henrinie May 14, 2024
f527e78
add crossorigin attr to video in gloss detail
henrinie May 20, 2024
4ac16c1
Revert "convert canvas to blob to fix insecure access to file from an…
henrinie May 20, 2024
817902e
fix video update to work with xmlhttpreq
henrinie May 20, 2024
f40b769
fix modified_date
henrinie May 20, 2024
87d4fc7
fix incorrectly named s3storage function
henrinie May 20, 2024
8978c2b
fix video exists check in tools
henrinie May 20, 2024
500762e
fix DB_IS_PSQL check when it is not set
henrinie May 20, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
FROM python:3.11-slim-bookworm

RUN apt update && export DEBIAN_FRONTEND=noninteractive && apt upgrade -y && apt install -y gettext

WORKDIR /usr/src/app

RUN python -m venv /venv
ENV PATH="/venv/bin:$PATH"

COPY requirements.txt requirements_os.txt ./
RUN pip install --no-cache-dir -r requirements.txt -r requirements_os.txt

COPY . .

RUN python bin/openshift.py compilemessages

USER nobody:0

EXPOSE 8080

ENTRYPOINT ["./docker-entrypoint.sh"]
13 changes: 13 additions & 0 deletions bin/openshift.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/venv/bin python
import os
import sys

if __name__ == "__main__":
sys.path.append(os.path.dirname(os.path.dirname(__file__)))

os.environ.setdefault(
"DJANGO_SETTINGS_MODULE", "signbank.settings.openshift")

from django.core.management import execute_from_command_line

execute_from_command_line(sys.argv)
40 changes: 40 additions & 0 deletions custom_migrations/flatpages/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Generated by Django 3.2.18 on 2024-05-09 10:33

from django.db import migrations, models


class Migration(migrations.Migration):

initial = True

dependencies = [
('sites', '0002_alter_domain_unique'),
]

operations = [
migrations.CreateModel(
name='FlatPage',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('url', models.CharField(db_index=True, max_length=100, verbose_name='URL')),
('title', models.CharField(max_length=200, verbose_name='title')),
('title_fi', models.CharField(max_length=200, null=True, verbose_name='title')),
('title_sv', models.CharField(max_length=200, null=True, verbose_name='title')),
('title_en', models.CharField(max_length=200, null=True, verbose_name='title')),
('content', models.TextField(blank=True, verbose_name='content')),
('content_fi', models.TextField(blank=True, null=True, verbose_name='content')),
('content_sv', models.TextField(blank=True, null=True, verbose_name='content')),
('content_en', models.TextField(blank=True, null=True, verbose_name='content')),
('enable_comments', models.BooleanField(default=False, verbose_name='enable comments')),
('template_name', models.CharField(blank=True, help_text='Example: “flatpages/contact_page.html”. If this isn’t provided, the system will use “flatpages/default.html”.', max_length=70, verbose_name='template name')),
('registration_required', models.BooleanField(default=False, help_text='If this is checked, only logged-in users will be able to view the page.', verbose_name='registration required')),
('sites', models.ManyToManyField(to='sites.Site', verbose_name='sites')),
],
options={
'verbose_name': 'flat page',
'verbose_name_plural': 'flat pages',
'db_table': 'django_flatpage',
'ordering': ['url'],
},
),
]
Empty file.
6 changes: 6 additions & 0 deletions docker-entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/bin/bash

set -e
# Skip while testing
# python bin/openshift.py migrate
gunicorn --bind 0.0.0.0:8080 signbank.wsgi_openshift
3 changes: 3 additions & 0 deletions requirements_os.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
gunicorn~=22.0.0
psycopg2-binary==2.9.9
django-storages[s3]==1.14.3
8 changes: 4 additions & 4 deletions signbank/dictionary/templates/dictionary/gloss_detail.html
Original file line number Diff line number Diff line change
Expand Up @@ -195,12 +195,12 @@ <h4>{% blocktrans%}Dataset{% endblocktrans %}: <span class="dataset-{{gloss.data
<h4 class="edit edit_text" id="video_title{{glossvideo.pk}}">{{glossvideo.title}}</h4>
</div>
<div class="embed-responsive embed-responsive-16by9">
<video id="glossvideo-{{glossvideo.pk}}" class="embed-responsive-item" width="450" preload="metadata" controls muted
{% if glossvideo.posterfile %} poster="{{glossvideo.posterfile.url|urlencode}}"{% endif %}>
<video id="glossvideo-{{glossvideo.pk}}" class="embed-responsive-item" width="450" preload="metadata" crossorigin="anonymous" controls muted
{% if glossvideo.posterfile %} poster="{{glossvideo.posterfile.url}}"{% endif %}>
{% if glossvideo.get_extension == '.mp4' %}
<source src="{{glossvideo.videofile.url|urlencode}}" type="video/mp4">
<source src="{{glossvideo.videofile.url}}" type="video/mp4">
{% elif glossvideo.get_extension == '.webm' %}
<source src="{{glossvideo.videofile.url|urlencode}}" type="video/webm">
<source src="{{glossvideo.videofile.url}}" type="video/webm">
{% endif %}
{% blocktrans %}Your browser does not support the video tag.{% endblocktrans %}
</video>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,11 @@ <h4>{{glossvideo.title}}</h4>
</header>
<div class="embed-responsive embed-responsive-16by9">
<video id="glossvideo-{{glossvideo.pk}}" preload="metadata" controls muted
{% if glossvideo.posterfile %} poster="{{glossvideo.posterfile.url|urlencode}}"{% endif %}>
{% if glossvideo.posterfile %} poster="{{glossvideo.posterfile.url}}"{% endif %}>
{% if glossvideo.get_extension == '.mp4' %}
<source src="{{glossvideo.videofile.url|urlencode}}" type="video/mp4">
<source src="{{glossvideo.videofile.url}}" type="video/mp4">
{% elif glossvideo.get_extension == '.webm' %}
<source src="{{glossvideo.videofile.url|urlencode}}" type="video/webm">
<source src="{{glossvideo.videofile.url}}" type="video/webm">
{% endif %}
{% blocktrans %}Your browser does not support the video tag.{% endblocktrans %}
</video>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,12 +167,12 @@ <h5><strong>{% blocktrans %}Copyright and license:{% endblocktrans %}</strong></
{% if obj.glossvideo_set.all.count > 0 %}style="background-color:rgb(33,33,33);"{% endif %}>
{% if obj.glossvideo_set.all.0 %}
<video id="glossvideo-{{obj.glossvideo_set.all.0.pk}}" class="video-public" preload="metadata" muted
{% if obj.glossvideo_set.all.0.posterfile %} poster="{{obj.glossvideo_set.all.0.posterfile.url|urlencode}}"{% endif %}
{% if obj.glossvideo_set.all.0.posterfile %} poster="{{obj.glossvideo_set.all.0.posterfile.url}}"{% endif %}
onclick="this.paused?this.play():this.pause();" playsinline>
{% if obj.glossvideo_set.all.0.get_extension == '.mp4' %}
<source src="{{obj.glossvideo_set.all.0.videofile.url|urlencode}}" type="video/mp4">
<source src="{{obj.glossvideo_set.all.0.videofile.url}}" type="video/mp4">
{% elif obj.glossvideo_set.all.0.get_extension == '.webm' %}
<source src="{{obj.glossvideo_set.all.0.videofile.url|urlencode}}" type="video/webm">
<source src="{{obj.glossvideo_set.all.0.videofile.url}}" type="video/webm">
{% endif %}
{% blocktrans %}Your browser does not support the video tag.{% endblocktrans %}
</video>
Expand Down
256 changes: 256 additions & 0 deletions signbank/settings/openshift.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,256 @@
"""OpenShift production environment specific settings for FinSL-signbank."""
import os

from django.utils.translation import ugettext_lazy as _

#: IMPORTANT: Debug should always be False in production
DEBUG = True # TODO: Switch back

# The following settings are defined in environment variables:
# SECRET_KEY, ADMINS, DATABASES, EMAIL_HOST, EMAIL_PORT, DEFAULT_FROM_EMAIL
SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY', 'default-secret-key')
#: IMPORTANT: The hostname that this signbank runs on, this prevents HTTP Host header attacks
ALLOWED_HOSTS = os.environ.get('DJANGO_ALLOWED_HOSTS', '').split(',')
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': os.environ.get('DB_NAME'),
'USER': os.environ.get('DB_USER'),
'PASSWORD': os.environ.get('DB_PASSWORD'),
'HOST': os.environ.get('DB_HOST'),
'PORT': os.environ.get('DB_PORT'),
}
}
ADMINS = os.environ.get('DJANGO_ADMINS')

# Absolute path to the base directory of the application.
BASE_DIR = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
# Path to the project directory.
PROJECT_DIR = os.path.dirname(BASE_DIR)
# Sets the field to automatically use for model primary key
DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'

# A list in the same format as ADMINS that specifies who should get broken link notifications
# when BrokenLinkEmailsMiddleware is enabled. ADMINS are set in secret_settings.
try:
MANAGERS = ADMINS
except NameError:
MANAGERS = (("", ""),)

#: A string representing the time zone for this installation.
TIME_ZONE = 'Europe/Helsinki'

#: A string representing the language code for this installation. This should be in standard language ID format.
#: For example, U.S. English is "en-us".
LANGUAGE_CODE = 'fi'

# The ID, as an integer, of the current site in the django_site database table.
SITE_ID = 1
#: A boolean that specifies whether Django's translation system should be enabled.
USE_I18N = True
#: A boolean that specifies if localized formatting of data will be enabled by default or not.
USE_L10N = True
#: A boolean that specifies if datetimes will be timezone-aware by default or not.
USE_TZ = True
#: A list of all available languages.
#: The list is a list of two-tuples in the format (language code, language name) - for example, ('ja', 'Japanese').
LANGUAGES = (
('fi', _('Finnish')),
('sv', _('Swedish')),
('en', _('English')),
)

# URL to use when referring to static files located in STATIC_ROOT.
# Example: "/static/" or "http://static.example.com/"
STATIC_URL = os.environ.get('STATIC_URL', '/static/')
#: The list of finder backends that know how to find static files in various locations.
STATICFILES_FINDERS = (
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
)

#: A list of middleware classes to use. The order of middleware classes is critical!
MIDDLEWARE = [
# If want to use some of the HTTPS settings in secret_settings, enable SecurityMiddleware
#'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'reversion.middleware.RevisionMiddleware',
]

TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [
# insert your TEMPLATE_DIRS here
os.path.join(PROJECT_DIR, 'templates'),
],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
# Insert your TEMPLATE_CONTEXT_PROCESSORS here
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
'django.template.context_processors.i18n',
'django.template.context_processors.media',
'django.template.context_processors.static',
'django.template.context_processors.tz',
'django.template.context_processors.csrf',
],
},
},
]

#: A list of authentication backend classes (as strings) to use when attempting to authenticate a user.
AUTHENTICATION_BACKENDS = (
"django.contrib.auth.backends.ModelBackend",
"guardian.backends.ObjectPermissionBackend",
)

# A list of IP addresses, as strings: Allow the debug() context processor to add some variables to the template context.
INTERNAL_IPS = ('127.0.0.1',)

# A string representing the full Python import path to your root URLconf. For example: "mydjangoapps.urls".
ROOT_URLCONF = 'signbank.urls'


#: A list of strings designating all applications that are enabled in this Django installation.
#: Dotted Python path to: an application configuration class (preferred), or a package containing an application.
#: The order of the apps matter!
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
'modeltranslation',
'django.contrib.admin',
'django.contrib.admindocs',
'django.contrib.staticfiles',
'bootstrap3',
'django_summernote',
'signbank.dictionary',
'django.contrib.flatpages',
'signbank.contentpages',
'signbank.video',
'reversion',
'tagging',
'django_comments',
'guardian',
'notifications',
'django.contrib.sitemaps',
)

# TODO: Evaluate how to handle flatpages migrations
MIGRATION_MODULES = {
'flatpages': 'custom_migrations.flatpages',
}

ABSOLUTE_URL_OVERRIDES = {
#: Allow using admin change url for notifications.
'auth.user': lambda user: "/admin/auth/user/%s/change/" % user.id,
}

#: Location for upload of videos relative to MEDIA_ROOT, videos are stored here prior to copying over to the main
#: storage location
VIDEO_UPLOAD_LOCATION = "upload"

#: How many days a user has until activation time expires. Django-registration related setting.
ACCOUNT_ACTIVATION_DAYS = 7
#: A boolean indicating whether registration of new accounts is currently permitted.
REGISTRATION_OPEN = True

#: The URL where requests are redirected after login when the contrib.auth.login view gets no next parameter.
LOGIN_REDIRECT_URL = '/'

# For django-tagging: force tags to be lowercase.
FORCE_LOWERCASE_TAGS = True

import mimetypes
mimetypes.add_type("video/mp4", ".mov", True)
mimetypes.add_type("video/webm", ".webm", True)

# A list of directories where Django looks for translation files.
LOCALE_PATHS = (
'./locale',
)

DEFAULT_FILE_STORAGE = "storages.backends.s3.S3Storage"
STATICFILES_STORAGE = "storages.backends.s3.S3Storage"

AWS_STORAGE_BUCKET_NAME = os.environ.get("BUCKET_NAME", "")
AWS_S3_ENDPOINT_URL = os.environ.get("BUCKET_ENDPOINT_URL", "")
AWS_S3_REGION_NAME = os.environ.get("BUCKET_REGION_NAME", "")
# custom_domain = os.environ.get("BUCKET_DOMAIN")
AWS_QUERYSTRING_AUTH = False
AWS_DEFAULT_ACL = "public-read"

#: The absolute path to the directory where collectstatic will collect static files for deployment.
#: Example: "/var/www/example.com/static/"
STATIC_ROOT = '/static/'
# This setting defines the additional locations the staticfiles app will traverse if the FileSystemFinder finder
# is enabled, e.g. if you use the collectstatic or findstatic management command or use the static file serving view.
STATICFILES_DIRS = (
os.path.join(PROJECT_DIR, "signbank", "static"),
)

#: Use Local-memory caching for specific views (if you have bigger needs, use something else).
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
'LOCATION': 'finsl-signbank-localmemcache',
}
}

#: Absolute filesystem path to the directory that will hold user-uploaded files.
MEDIA_ROOT = '/media/'
# URL that handles the media served from MEDIA_ROOT, used for managing stored files.
# It must end in a slash if set to a non-empty value.
MEDIA_URL = os.environ.get('MEDIA_URL', '/media/')

#: Location and URL for uploaded files.
UPLOAD_ROOT = MEDIA_ROOT + "upload/"
UPLOAD_URL = MEDIA_URL + "upload/"

#: The backend to use for sending emails.
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'

#: A sample logging configuration. The only tangible logging
#: performed by this configuration is to send an email to
#: the site admins on every HTTP 500 error when DEBUG=False.
#: See http://docs.djangoproject.com/en/stable/topics/logging for
#: more details on how to customize your logging configuration.
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'filters': {
'require_debug_false': {
'()': 'django.utils.log.RequireDebugFalse'
}
},
'handlers': {
'mail_admins': {
'level': 'ERROR',
'filters': ['require_debug_false'],
'class': 'django.utils.log.AdminEmailHandler'
}
},
'loggers': {
'django.request': {
'handlers': ['mail_admins'],
'level': 'ERROR',
'propagate': True,
},
}
}

#: Turn off lots of logging.
DO_LOGGING = False
LOG_FILENAME = "debug.log"
Loading
Loading