mirror of
https://github.com/mediacms-io/mediacms.git
synced 2025-11-21 05:56:03 -05:00
Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5a1e4f25ed | ||
|
|
9fc7597e73 | ||
|
|
9b3e0250d4 | ||
|
|
1384471745 | ||
|
|
29b362c8ce | ||
|
|
b8ee2e9fb8 | ||
|
|
99be0f07dd | ||
|
|
27d1660192 | ||
|
|
98adb22205 | ||
|
|
673ddeb5bd | ||
|
|
aa8a2d92dc | ||
|
|
6bbd4c2809 | ||
|
|
c4148bd504 | ||
|
|
ea8b2af26f | ||
|
|
5aa899cef0 |
8
.github/workflows/python.yml
vendored
8
.github/workflows/python.yml
vendored
@@ -13,10 +13,10 @@ jobs:
|
||||
uses: actions/checkout@v1
|
||||
|
||||
- name: Build the Stack
|
||||
run: docker-compose -f docker-compose-dev.yaml build
|
||||
run: docker compose -f docker-compose-dev.yaml build
|
||||
|
||||
- name: Start containers
|
||||
run: docker-compose -f docker-compose-dev.yaml up -d
|
||||
run: docker compose -f docker-compose-dev.yaml up -d
|
||||
|
||||
- name: List containers
|
||||
run: docker ps
|
||||
@@ -26,10 +26,10 @@ jobs:
|
||||
shell: bash
|
||||
|
||||
- name: Run Django Tests
|
||||
run: docker-compose -f docker-compose-dev.yaml exec --env TESTING=True -T web pytest
|
||||
run: docker compose -f docker-compose-dev.yaml exec --env TESTING=True -T web pytest
|
||||
|
||||
# Run with coverage, saves report on htmlcov dir
|
||||
# run: docker-compose -f docker-compose-dev.yaml exec --env TESTING=True -T web pytest --cov --cov-report=html --cov-config=.coveragerc
|
||||
|
||||
- name: Tear down the Stack
|
||||
run: docker-compose -f docker-compose-dev.yaml down
|
||||
run: docker compose -f docker-compose-dev.yaml down
|
||||
|
||||
6
Makefile
6
Makefile
@@ -12,4 +12,8 @@ admin-shell:
|
||||
build-frontend:
|
||||
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
|
||||
|
||||
|
||||
@@ -43,7 +43,6 @@ A demo is available at https://demo.mediacms.io
|
||||
- **REST API**: Documented through Swagger
|
||||
- **Translation**: Most of the CMS is translated to a number of languages
|
||||
|
||||
|
||||
## Example cases
|
||||
|
||||
- **Schools, education.** Administrators and editors keep what content will be published, students are not distracted with advertisements and irrelevant content, plus they have the ability to select either to stream or download content.
|
||||
@@ -68,7 +67,12 @@ Copyright Markos Gogoulos.
|
||||
|
||||
We provide custom installations, development of extra functionality, migration from existing systems, integrations with legacy systems, training and support. Contact us at info@mediacms.io for more information.
|
||||
|
||||
### Commercial Hostings
|
||||
**Elestio**
|
||||
|
||||
You can deploy MediaCMS on Elestio using one-click deployment. Elestio supports MediaCMS by providing revenue share so go ahead and click below to deploy and use MediaCMS.
|
||||
|
||||
[](https://elest.io/open-source/mediacms)
|
||||
|
||||
## Hardware considerations
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ DEBUG = False
|
||||
# is also shown on several places as emails
|
||||
PORTAL_NAME = "MediaCMS"
|
||||
PORTAL_DESCRIPTION = ""
|
||||
LANGUAGE_CODE = "en-us"
|
||||
TIME_ZONE = "Europe/London"
|
||||
|
||||
# who can add media
|
||||
@@ -131,6 +130,10 @@ USERS_CAN_SELF_REGISTER = True
|
||||
|
||||
RESTRICTED_DOMAINS_FOR_USER_REGISTRATION = ["xxx.com", "emaildomainwhatever.com"]
|
||||
|
||||
# Comma separated list of domains: ["organization.com", "private.organization.com", "org2.com"]
|
||||
# Empty list disables.
|
||||
ALLOWED_DOMAINS_FOR_USER_REGISTRATION = []
|
||||
|
||||
# django rest settings
|
||||
REST_FRAMEWORK = {
|
||||
"DEFAULT_AUTHENTICATION_CLASSES": (
|
||||
@@ -531,3 +534,11 @@ LANGUAGES = [
|
||||
]
|
||||
|
||||
LANGUAGE_CODE = 'en' # default language
|
||||
|
||||
SPRITE_NUM_SECS = 10
|
||||
# number of seconds for sprite image.
|
||||
# If you plan to change this, you must also follow the instructions on admin_docs.md
|
||||
# to change the equivalent value in ./frontend/src/static/js/components/media-viewer/VideoViewer/index.js and then re-build frontend
|
||||
|
||||
# how many images will be shown on the slideshow
|
||||
SLIDESHOW_ITEMS = 30
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
- [18. Disable encoding and show only original file](#18-disable-encoding-and-show-only-original-file)
|
||||
- [19. Rounded corners on videos](#19-rounded-corners)
|
||||
- [20. Translations](#20-translations)
|
||||
- [21. How to change the video frames on videos](#21-fames)
|
||||
|
||||
## 1. Welcome
|
||||
This page is created for MediaCMS administrators that are responsible for setting up the software, maintaining it and making modifications.
|
||||
@@ -354,13 +355,22 @@ ADMIN_EMAIL_LIST = ['info@mediacms.io']
|
||||
|
||||
### 5.13 Disallow user registrations from specific domains
|
||||
|
||||
set domains that are not valid for registration via this variable:
|
||||
Set domains that are not valid for registration via this variable:
|
||||
|
||||
```
|
||||
RESTRICTED_DOMAINS_FOR_USER_REGISTRATION = [
|
||||
'xxx.com', 'emaildomainwhatever.com']
|
||||
```
|
||||
|
||||
Alternatively, allow only permitted domains to register. This can be useful if you're using mediacms as a private service within an organization, and want to give free registration for those in the org, but deny registration from all other domains. Setting this option bans all domains NOT in the list from registering. Default is a blank list, which is ignored. To disable, set to a blank list.
|
||||
```
|
||||
ALLOWED_DOMAINS_FOR_USER_REGISTRATION = [
|
||||
"private.com",
|
||||
"vod.private.com",
|
||||
"my.favorite.domain",
|
||||
"test.private.com"]
|
||||
```
|
||||
|
||||
### 5.14 Require a review by MediaCMS editors/managers/admins
|
||||
|
||||
set value
|
||||
@@ -833,10 +843,21 @@ After the string is marked as translatable, add the string to `files/frontend-tr
|
||||
python manage.py process_translations
|
||||
```
|
||||
|
||||
In order to populate the string in all the languages. NO PR will be accepted if this procedure is not followed. You don't have to translate the string to all supported languages, but the command has to run and populate the existing dictionaries with the new strings for all languages. This ensures that there is no missing string to be translated in any language.
|
||||
In order to populate the string in all the languages. NO PR will be accepted if this procedure is not followed. You don't have to translate the string to all supported languages, but the command has to run and populate the existing dictionaries with the new strings for all languages. This ensures that there is no missing string to be translated in any language.
|
||||
|
||||
After this command is run, translate the string to the language you want. If the string to be translated lives in Django templates, you don't have to re-build the frontend. If the change lives in the frontend, you will have to re-build in order to see the changes. The Makefile command `make build-frontend` can help with this.
|
||||
|
||||
|
||||
### 20.5 Add a new language and translate
|
||||
To add a new language: add the language in settings.py, then add the file in `files/frontend-translations/`. Make sure you copy the initial strings by copying `files/frontend-translations/en.py` to it.
|
||||
To add a new language: add the language in settings.py, then add the file in `files/frontend-translations/`. Make sure you copy the initial strings by copying `files/frontend-translations/en.py` to it.
|
||||
|
||||
## 21. How to change the video frames on videos
|
||||
|
||||
By default while watching a video you can hover and see the small images named sprites that are extracted every 10 seconds of a video. You can change this number to something smaller by performing the following:
|
||||
|
||||
* edit ./frontend/src/static/js/components/media-viewer/VideoViewer/index.js and change `seconds: 10 ` to the value you prefer, eg 2.
|
||||
* edit settings.py and set the same number for value SPRITE_NUM_SECS
|
||||
* now you have to re-build the frontend: the easiest way is to run `make build-frontend`, which requires Docker
|
||||
|
||||
After that, newly uploaded videos will have sprites generated with the new number of seconds.
|
||||
|
||||
|
||||
@@ -1,6 +1,15 @@
|
||||
from django.contrib import admin
|
||||
|
||||
from .models import Category, Comment, EncodeProfile, Encoding, Language, Media, Subtitle, Tag
|
||||
from .models import (
|
||||
Category,
|
||||
Comment,
|
||||
EncodeProfile,
|
||||
Encoding,
|
||||
Language,
|
||||
Media,
|
||||
Subtitle,
|
||||
Tag,
|
||||
)
|
||||
|
||||
|
||||
class CommentAdmin(admin.ModelAdmin):
|
||||
|
||||
@@ -32,7 +32,6 @@ for translation_file in files:
|
||||
replacement_strings[language_code] = tr_module.replacement_strings
|
||||
|
||||
|
||||
|
||||
def get_translation(language_code):
|
||||
# get list of translations per language
|
||||
if not check_language_code(language_code):
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
translation_strings = {
|
||||
"ABOUT": "約",
|
||||
"AUTOPLAY": "自動再生",
|
||||
"About": "",
|
||||
"About": "約",
|
||||
"Add a ": "追加",
|
||||
"COMMENT": "コメント",
|
||||
"Categories": "カテゴリー",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
translation_strings = {
|
||||
"ABOUT": "정보",
|
||||
"AUTOPLAY": "자동 재생",
|
||||
"About": "",
|
||||
"About": "정보",
|
||||
"Add a ": "추가",
|
||||
"COMMENT": "댓글",
|
||||
"Categories": "카테고리",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
translation_strings = {
|
||||
"ABOUT": "OVER",
|
||||
"AUTOPLAY": "AUTOMATISCH AFSPELEN",
|
||||
"About": "",
|
||||
"About": "Over",
|
||||
"Add a ": "Voeg een ",
|
||||
"COMMENT": "REACTIE",
|
||||
"Categories": "Categorieën",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
translation_strings = {
|
||||
"ABOUT": "SOBRE",
|
||||
"AUTOPLAY": "REPRODUÇÃO AUTOMÁTICA",
|
||||
"About": "",
|
||||
"About": "Sobre",
|
||||
"Add a ": "Adicionar um ",
|
||||
"COMMENT": "COMENTÁRIO",
|
||||
"Categories": "Categorias",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
translation_strings = {
|
||||
"ABOUT": "О",
|
||||
"AUTOPLAY": "Автовоспроизведение",
|
||||
"About": "",
|
||||
"About": "О",
|
||||
"Add a ": "Добавить ",
|
||||
"COMMENT": "КОММЕНТАРИЙ",
|
||||
"Categories": "Категории",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
translation_strings = {
|
||||
"ABOUT": "HAKKINDA",
|
||||
"AUTOPLAY": "OTOMATİK OYNATMA",
|
||||
"About": "",
|
||||
"About": "Hakkında",
|
||||
"Add a ": "Ekle ",
|
||||
"COMMENT": "YORUM",
|
||||
"Categories": "Kategoriler",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
translation_strings = {
|
||||
"ABOUT": "کے بارے میں",
|
||||
"AUTOPLAY": "خودکار پلے",
|
||||
"About": "",
|
||||
"About": "کے بارے میں",
|
||||
"Add a ": "شامل کریں",
|
||||
"COMMENT": "تبصرہ",
|
||||
"Categories": "اقسام",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
translation_strings = {
|
||||
"ABOUT": "关于",
|
||||
"AUTOPLAY": "自动播放",
|
||||
"About": "",
|
||||
"About": "关于",
|
||||
"Add a ": "添加一个",
|
||||
"COMMENT": "评论",
|
||||
"Categories": "分类",
|
||||
|
||||
@@ -18,7 +18,10 @@ class Command(BaseCommand):
|
||||
files = os.listdir(translations_dir)
|
||||
files = [f for f in files if f.endswith('.py') and f not in ('__init__.py', 'en.py')]
|
||||
# Import the original English translations
|
||||
from files.frontend_translations.en import replacement_strings, translation_strings
|
||||
from files.frontend_translations.en import (
|
||||
replacement_strings,
|
||||
translation_strings,
|
||||
)
|
||||
|
||||
for file in files:
|
||||
file_path = os.path.join(translations_dir, file)
|
||||
@@ -44,12 +47,12 @@ class Command(BaseCommand):
|
||||
with open(file_path, 'w') as f:
|
||||
f.write("translation_strings = {\n")
|
||||
for key, value in translation_strings_wip.items():
|
||||
f.write(f' "{key}": "{value}",\n')
|
||||
f.write(f' "{key}": "{value}",\n') # noqa
|
||||
f.write("}\n\n")
|
||||
|
||||
f.write("replacement_strings = {\n")
|
||||
for key, value in replacement_strings_wip.items():
|
||||
f.write(f' "{key}": "{value}",\n')
|
||||
f.write(f' "{key}": "{value}",\n') # noqa
|
||||
f.write("}\n")
|
||||
|
||||
self.stdout.write(self.style.SUCCESS(f'Processed {file}'))
|
||||
|
||||
@@ -780,6 +780,36 @@ class Media(models.Model):
|
||||
return helpers.url_from_path(self.poster.path)
|
||||
return None
|
||||
|
||||
@property
|
||||
def slideshow_items(self):
|
||||
slideshow_items = getattr(settings, "SLIDESHOW_ITEMS", 30)
|
||||
if self.media_type != "image":
|
||||
items = []
|
||||
else:
|
||||
qs = Media.objects.filter(listable=True, user=self.user, media_type="image").exclude(id=self.id).order_by('id')[:slideshow_items]
|
||||
|
||||
items = [
|
||||
{
|
||||
"poster_url": item.poster_url,
|
||||
"url": item.get_absolute_url(),
|
||||
"thumbnail_url": item.thumbnail_url,
|
||||
"title": item.title,
|
||||
"original_media_url": item.original_media_url,
|
||||
}
|
||||
for item in qs
|
||||
]
|
||||
items.insert(
|
||||
0,
|
||||
{
|
||||
"poster_url": self.poster_url,
|
||||
"url": self.get_absolute_url(),
|
||||
"thumbnail_url": self.thumbnail_url,
|
||||
"title": self.title,
|
||||
"original_media_url": self.original_media_url,
|
||||
},
|
||||
)
|
||||
return items
|
||||
|
||||
@property
|
||||
def subtitles_info(self):
|
||||
"""Property used on serializers
|
||||
|
||||
@@ -145,6 +145,7 @@ class SingleMediaSerializer(serializers.ModelSerializer):
|
||||
"ratings_info",
|
||||
"add_subtitle_url",
|
||||
"allow_download",
|
||||
"slideshow_items",
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -23,7 +23,17 @@ from users.models import User
|
||||
|
||||
from .backends import FFmpegBackend
|
||||
from .exceptions import VideoEncodingError
|
||||
from .helpers import calculate_seconds, create_temp_file, get_file_name, get_file_type, media_file_info, produce_ffmpeg_commands, produce_friendly_token, rm_file, run_command
|
||||
from .helpers import (
|
||||
calculate_seconds,
|
||||
create_temp_file,
|
||||
get_file_name,
|
||||
get_file_type,
|
||||
media_file_info,
|
||||
produce_ffmpeg_commands,
|
||||
produce_friendly_token,
|
||||
rm_file,
|
||||
run_command,
|
||||
)
|
||||
from .methods import list_tasks, notify_users, pre_save_action
|
||||
from .models import Category, EncodeProfile, Encoding, Media, Rating, Tag
|
||||
|
||||
@@ -374,14 +384,17 @@ def produce_sprite_from_video(friendly_token):
|
||||
try:
|
||||
tmpdir_image_files = tmpdirname + "/img%03d.jpg"
|
||||
output_name = tmpdirname + "/sprites.jpg"
|
||||
cmd = "{0} -i {1} -f image2 -vf 'fps=1/10, scale=160:90' {2}&&files=$(ls {3}/img*.jpg | sort -t '-' -n -k 2 | tr '\n' ' ')&&convert $files -append {4}".format(
|
||||
settings.FFMPEG_COMMAND,
|
||||
media.media_file.path,
|
||||
tmpdir_image_files,
|
||||
tmpdirname,
|
||||
output_name,
|
||||
)
|
||||
subprocess.run(cmd, stdout=subprocess.PIPE, shell=True)
|
||||
|
||||
fps = getattr(settings, 'SPRITE_NUM_SECS', 10)
|
||||
ffmpeg_cmd = [settings.FFMPEG_COMMAND, "-i", media.media_file.path, "-f", "image2", "-vf", f"fps=1/{fps}, scale=160:90", tmpdir_image_files] # noqa
|
||||
run_command(ffmpeg_cmd)
|
||||
image_files = [f for f in os.listdir(tmpdirname) if f.startswith("img") and f.endswith(".jpg")]
|
||||
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)
|
||||
|
||||
if os.path.exists(output_name) and get_file_type(output_name) == "image":
|
||||
with open(output_name, "rb") as f:
|
||||
myfile = File(f)
|
||||
@@ -421,13 +434,20 @@ def create_hls(friendly_token):
|
||||
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 = "{0} --segment-duration=4 --output-dir={1} {2}".format(settings.MP4HLS_COMMAND, output_dir, files)
|
||||
subprocess.run(cmd, stdout=subprocess.PIPE, shell=True)
|
||||
cmd = [settings.MP4HLS_COMMAND, '--segment-duration=4', f'--output-dir={output_dir}', files]
|
||||
run_command(cmd)
|
||||
|
||||
if existing_output_dir:
|
||||
# override content with -T !
|
||||
cmd = "cp -rT {0} {1}".format(output_dir, existing_output_dir)
|
||||
subprocess.run(cmd, stdout=subprocess.PIPE, shell=True)
|
||||
shutil.rmtree(output_dir)
|
||||
cmd = ["cp", "-rT", output_dir, existing_output_dir]
|
||||
run_command(cmd)
|
||||
|
||||
try:
|
||||
shutil.rmtree(output_dir)
|
||||
except: # noqa
|
||||
# this was breaking in some cases where it was already deleted
|
||||
# because create_hls was running multiple times
|
||||
pass
|
||||
output_dir = existing_output_dir
|
||||
pp = os.path.join(output_dir, "master.m3u8")
|
||||
if os.path.exists(pp):
|
||||
|
||||
@@ -7,5 +7,4 @@ register = template.Library()
|
||||
|
||||
@register.filter
|
||||
def custom_translate(string, lang_code):
|
||||
|
||||
return translate_string(lang_code, string)
|
||||
|
||||
@@ -12,14 +12,24 @@ from drf_yasg import openapi as openapi
|
||||
from drf_yasg.utils import swagger_auto_schema
|
||||
from rest_framework import permissions, status
|
||||
from rest_framework.exceptions import PermissionDenied
|
||||
from rest_framework.parsers import FileUploadParser, FormParser, JSONParser, MultiPartParser
|
||||
from rest_framework.parsers import (
|
||||
FileUploadParser,
|
||||
FormParser,
|
||||
JSONParser,
|
||||
MultiPartParser,
|
||||
)
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.settings import api_settings
|
||||
from rest_framework.views import APIView
|
||||
|
||||
from actions.models import USER_MEDIA_ACTIONS, MediaAction
|
||||
from cms.custom_pagination import FastPaginationWithoutCount
|
||||
from cms.permissions import IsAuthorizedToAdd, IsAuthorizedToAddComment, IsUserOrEditor, user_allowed_to_upload
|
||||
from cms.permissions import (
|
||||
IsAuthorizedToAdd,
|
||||
IsAuthorizedToAddComment,
|
||||
IsUserOrEditor,
|
||||
user_allowed_to_upload,
|
||||
)
|
||||
from users.models import User
|
||||
|
||||
from .forms import ContactForm, MediaForm, SubtitleForm
|
||||
@@ -36,7 +46,16 @@ from .methods import (
|
||||
show_related_media,
|
||||
update_user_ratings,
|
||||
)
|
||||
from .models import Category, Comment, EncodeProfile, Encoding, Media, Playlist, PlaylistMedia, Tag
|
||||
from .models import (
|
||||
Category,
|
||||
Comment,
|
||||
EncodeProfile,
|
||||
Encoding,
|
||||
Media,
|
||||
Playlist,
|
||||
PlaylistMedia,
|
||||
Tag,
|
||||
)
|
||||
from .serializers import (
|
||||
CategorySerializer,
|
||||
CommentSerializer,
|
||||
|
||||
@@ -413,7 +413,7 @@ const CommentsListHeader = ({ commentsLength }) => {
|
||||
? commentsLength + ' ' + commentsText.ucfirstPlural
|
||||
: commentsLength + ' ' + commentsText.ucfirstSingle
|
||||
: MediaPageStore.get('media-data').enable_comments
|
||||
? translateString('No') + commentsText.single + translateString('yet')
|
||||
? translateString('No') + ' ' + commentsText.single + ' ' + translateString('yet')
|
||||
: ''}
|
||||
</h2>
|
||||
) : null}
|
||||
@@ -505,7 +505,7 @@ export default function CommentsList(props) {
|
||||
function onCommentSubmitFail() {
|
||||
// FIXME: Without delay creates conflict [ Uncaught Error: Dispatch.dispatch(...): Cannot dispatch in the middle of a dispatch. ].
|
||||
setTimeout(
|
||||
() => PageActions.addNotification(commentsText.ucfirstSingle + ' submition failed', 'commentSubmitFail'),
|
||||
() => PageActions.addNotification(commentsText.ucfirstSingle + ' submission failed', 'commentSubmitFail'),
|
||||
100
|
||||
);
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -10,6 +10,11 @@ from django.conf import settings
|
||||
from . import utils
|
||||
|
||||
|
||||
def strip_delimiters(input_string):
|
||||
delimiters = " \t\n\r'\"[]{}()<>\\|&;:*-=+"
|
||||
return ''.join(char for char in input_string if char not in delimiters)
|
||||
|
||||
|
||||
def is_valid_uuid_format(uuid_string):
|
||||
pattern = re.compile(r'^[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$', re.IGNORECASE)
|
||||
return bool(pattern.match(uuid_string))
|
||||
@@ -28,6 +33,7 @@ class BaseFineUploader(object):
|
||||
self.uuid = uuid.uuid4()
|
||||
|
||||
self.filename = os.path.basename(self.filename)
|
||||
self.filename = strip_delimiters(self.filename)
|
||||
# avoid possibility of passing a fake path here
|
||||
|
||||
self.file = data.get("qqfile")
|
||||
|
||||
@@ -10,6 +10,10 @@ class MyAccountAdapter(DefaultAccountAdapter):
|
||||
return settings.SSL_FRONTEND_HOST + url
|
||||
|
||||
def clean_email(self, email):
|
||||
if hasattr(settings, "ALLOWED_DOMAINS_FOR_USER_REGISTRATION") and settings.ALLOWED_DOMAINS_FOR_USER_REGISTRATION:
|
||||
if email.split("@")[1] not in settings.ALLOWED_DOMAINS_FOR_USER_REGISTRATION:
|
||||
raise ValidationError("Domain is not in the permitted list")
|
||||
|
||||
if email.split("@")[1] in settings.RESTRICTED_DOMAINS_FOR_USER_REGISTRATION:
|
||||
raise ValidationError("Domain is restricted from registering")
|
||||
return email
|
||||
|
||||
Reference in New Issue
Block a user