mirror of
https://github.com/Alexander-D-Karpov/akarpov
synced 2024-11-24 00:53:43 +03:00
Compare commits
No commits in common. "4aa1d207aa3a6d9bb00ed1feffe35af03e708e9e" and "2b2c16db2d88989f24ddd1b479f3aeb9d5ca02f6" have entirely different histories.
4aa1d207aa
...
2b2c16db2d
|
@ -30,7 +30,6 @@
|
||||||
)
|
)
|
||||||
from akarpov.music.services.search import search_song
|
from akarpov.music.services.search import search_song
|
||||||
from akarpov.music.tasks import listen_to_song
|
from akarpov.music.tasks import listen_to_song
|
||||||
from akarpov.users.models import User
|
|
||||||
|
|
||||||
|
|
||||||
class LikedSongsContextMixin(generics.GenericAPIView):
|
class LikedSongsContextMixin(generics.GenericAPIView):
|
||||||
|
@ -392,27 +391,12 @@ def get_queryset(self):
|
||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
serializer = self.get_serializer(data=request.data)
|
serializer = self.get_serializer(data=request.data)
|
||||||
serializer.is_valid(raise_exception=False)
|
serializer.is_valid(raise_exception=False)
|
||||||
|
data = serializer.validated_data
|
||||||
|
|
||||||
try:
|
try:
|
||||||
song = Song.objects.cache().get(slug=self.request.data.get("song", ""))
|
song = Song.objects.cache().get(slug=data["song"])
|
||||||
except Song.DoesNotExist:
|
except Song.DoesNotExist:
|
||||||
return Response(status=404)
|
return Response(status=404)
|
||||||
|
|
||||||
try:
|
|
||||||
user_id = self.request.data.get("user_id", None)
|
|
||||||
if user_id:
|
|
||||||
user_id_int = None
|
|
||||||
try:
|
|
||||||
user_id_int = int(user_id)
|
|
||||||
except ValueError:
|
|
||||||
...
|
|
||||||
if user_id_int:
|
|
||||||
user = User.objects.cache().get(id=user_id_int)
|
|
||||||
if user != self.request.user:
|
|
||||||
return Response(status=403)
|
|
||||||
except User.DoesNotExist:
|
|
||||||
...
|
|
||||||
|
|
||||||
if self.request.user.is_authenticated:
|
if self.request.user.is_authenticated:
|
||||||
listen_to_song.apply_async(
|
listen_to_song.apply_async(
|
||||||
kwargs={
|
kwargs={
|
||||||
|
@ -422,11 +406,11 @@ def post(self, request, *args, **kwargs):
|
||||||
},
|
},
|
||||||
countdown=2,
|
countdown=2,
|
||||||
)
|
)
|
||||||
elif "user_id" in self.request.data:
|
elif "user_id" in data:
|
||||||
listen_to_song.apply_async(
|
listen_to_song.apply_async(
|
||||||
kwargs={
|
kwargs={
|
||||||
"song_id": song.id,
|
"song_id": song.id,
|
||||||
"user_id": self.request.data.get("user_id", None),
|
"user_id": data["user_id"],
|
||||||
"anon": True,
|
"anon": True,
|
||||||
},
|
},
|
||||||
countdown=2,
|
countdown=2,
|
||||||
|
|
|
@ -35,11 +35,9 @@ class SongDocument(Document):
|
||||||
name = fields.TextField(
|
name = fields.TextField(
|
||||||
attr="name",
|
attr="name",
|
||||||
fields={
|
fields={
|
||||||
"raw": fields.KeywordField(),
|
"raw": fields.KeywordField(normalizer="lowercase"),
|
||||||
"exact": fields.KeywordField(normalizer="lowercase"),
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
suggest = fields.CompletionField()
|
|
||||||
|
|
||||||
meta = fields.ObjectField(dynamic=True)
|
meta = fields.ObjectField(dynamic=True)
|
||||||
|
|
||||||
|
|
|
@ -86,11 +86,6 @@ def album_name(self):
|
||||||
def artists_names(self):
|
def artists_names(self):
|
||||||
return cache_model_property(self, "_authors_names")
|
return cache_model_property(self, "_authors_names")
|
||||||
|
|
||||||
def get_first_author_name(self):
|
|
||||||
if self.authors:
|
|
||||||
return self.authors.first().name
|
|
||||||
return ""
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
|
|
@ -2,11 +2,7 @@
|
||||||
import re
|
import re
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
from deep_translator import GoogleTranslator
|
||||||
try:
|
|
||||||
from deep_translator import GoogleTranslator # TODO: move to another service
|
|
||||||
except requests.exceptions.JSONDecodeError:
|
|
||||||
print("Failed to initialize GoogleTranslator due to external API issues.")
|
|
||||||
from django.core.files import File
|
from django.core.files import File
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
from django.utils.text import slugify
|
from django.utils.text import slugify
|
||||||
|
@ -126,15 +122,12 @@ def load_track(
|
||||||
album=album,
|
album=album,
|
||||||
):
|
):
|
||||||
return sng.first()
|
return sng.first()
|
||||||
try:
|
|
||||||
if not path.endswith(".mp3"):
|
if not path.endswith(".mp3"):
|
||||||
mp3_path = path.replace(path.split(".")[-1], "mp3")
|
mp3_path = path.replace(path.split(".")[-1], "mp3")
|
||||||
AudioSegment.from_file(path).export(mp3_path)
|
AudioSegment.from_file(path).export(mp3_path)
|
||||||
os.remove(path)
|
os.remove(path)
|
||||||
path = mp3_path
|
path = mp3_path
|
||||||
except Exception as e:
|
|
||||||
print(e)
|
|
||||||
return Song.objects.none()
|
|
||||||
|
|
||||||
tag = MP3(path, ID3=ID3)
|
tag = MP3(path, ID3=ID3)
|
||||||
|
|
||||||
|
|
|
@ -3,11 +3,7 @@
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
import spotipy
|
import spotipy
|
||||||
|
from deep_translator import GoogleTranslator
|
||||||
try:
|
|
||||||
from deep_translator import GoogleTranslator
|
|
||||||
except requests.exceptions.JSONDecodeError:
|
|
||||||
print("Failed to initialize GoogleTranslator due to external API issues.")
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.files import File
|
from django.core.files import File
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
from django.core.cache import cache
|
|
||||||
from django.db.models import Case, When
|
from django.db.models import Case, When
|
||||||
from django_elasticsearch_dsl.registries import registry
|
|
||||||
from elasticsearch_dsl import Q as ES_Q
|
from elasticsearch_dsl import Q as ES_Q
|
||||||
|
|
||||||
from akarpov.music.documents import SongDocument
|
from akarpov.music.documents import SongDocument
|
||||||
|
@ -12,60 +10,33 @@ def search_song(query):
|
||||||
search_query = ES_Q(
|
search_query = ES_Q(
|
||||||
"bool",
|
"bool",
|
||||||
should=[
|
should=[
|
||||||
ES_Q("match", name=query),
|
|
||||||
ES_Q("match", name__russian=query),
|
|
||||||
ES_Q(
|
ES_Q(
|
||||||
"multi_match",
|
"multi_match",
|
||||||
query=query,
|
query=query,
|
||||||
fields=[
|
fields=["name^5", "authors.name^3", "album.name^3"],
|
||||||
"name^5",
|
|
||||||
"name.russian^5",
|
|
||||||
"authors.name^3",
|
|
||||||
"authors.name.raw^3",
|
|
||||||
"album.name^3",
|
|
||||||
"album.name.raw^3",
|
|
||||||
"name.raw^2",
|
|
||||||
],
|
|
||||||
type="best_fields",
|
|
||||||
fuzziness="AUTO",
|
fuzziness="AUTO",
|
||||||
),
|
),
|
||||||
|
ES_Q("wildcard", name__raw=f"*{query.lower()}*"),
|
||||||
ES_Q(
|
ES_Q(
|
||||||
"nested",
|
"nested",
|
||||||
path="authors",
|
path="authors",
|
||||||
query=ES_Q(
|
query=ES_Q("wildcard", authors__name__raw=f"*{query.lower()}*"),
|
||||||
"multi_match",
|
|
||||||
query=query,
|
|
||||||
fields=["authors.name", "authors.name.raw"],
|
|
||||||
fuzziness="AUTO",
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
# Correcting wildcard queries with the proper syntax:
|
|
||||||
ES_Q("wildcard", **{"name.raw": f"*{query.lower()}*"}),
|
|
||||||
ES_Q(
|
ES_Q(
|
||||||
"nested",
|
"nested",
|
||||||
path="album",
|
path="album",
|
||||||
query=ES_Q(
|
query=ES_Q("wildcard", album__name__raw=f"*{query.lower()}*"),
|
||||||
"multi_match",
|
|
||||||
query=query,
|
|
||||||
fields=["album.name", "album.name.raw"],
|
|
||||||
fuzziness="AUTO",
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
# Ensuring the nested wildcard query is properly structured
|
ES_Q("wildcard", meta__raw=f"*{query.lower()}*"),
|
||||||
ES_Q(
|
|
||||||
"nested",
|
|
||||||
path="album",
|
|
||||||
query=ES_Q("wildcard", **{"album.name.raw": f"*{query.lower()}*"}),
|
|
||||||
),
|
|
||||||
# Correcting the wildcard query for `meta.raw`
|
|
||||||
ES_Q("wildcard", **{"meta.raw": f"*{query.lower()}*"}),
|
|
||||||
],
|
],
|
||||||
minimum_should_match=1,
|
minimum_should_match=1,
|
||||||
)
|
)
|
||||||
|
|
||||||
search = search.query(search_query).extra(size=20)
|
search = search.query(search_query)
|
||||||
|
|
||||||
response = search.execute()
|
response = search.execute()
|
||||||
|
|
||||||
|
# Check for hits and get song instances
|
||||||
if response.hits:
|
if response.hits:
|
||||||
hit_ids = [hit.meta.id for hit in response.hits]
|
hit_ids = [hit.meta.id for hit in response.hits]
|
||||||
songs = Song.objects.filter(id__in=hit_ids).order_by(
|
songs = Song.objects.filter(id__in=hit_ids).order_by(
|
||||||
|
@ -75,24 +46,3 @@ def search_song(query):
|
||||||
return songs
|
return songs
|
||||||
|
|
||||||
return Song.objects.none()
|
return Song.objects.none()
|
||||||
|
|
||||||
|
|
||||||
def autocomplete_search(query):
|
|
||||||
s = SongDocument.search()
|
|
||||||
s = s.suggest("song_suggest", query, completion={"field": "suggest"})
|
|
||||||
suggestions = s.execute().suggest.song_suggest[0].options
|
|
||||||
return [option.text for option in suggestions]
|
|
||||||
|
|
||||||
|
|
||||||
def get_popular_songs():
|
|
||||||
if "popular_songs" in cache:
|
|
||||||
return cache.get("popular_songs")
|
|
||||||
else:
|
|
||||||
songs = Song.objects.filter(played__gt=300).order_by("-played")[:10]
|
|
||||||
cache.set("popular_songs", songs, timeout=3600)
|
|
||||||
return songs
|
|
||||||
|
|
||||||
|
|
||||||
def bulk_update_index(model_class):
|
|
||||||
qs = model_class.objects.all()
|
|
||||||
registry.update(qs, bulk_size=100)
|
|
||||||
|
|
|
@ -75,40 +75,13 @@ def load_file_meta(track: int, user_id: int) -> str:
|
||||||
return str(song)
|
return str(song)
|
||||||
|
|
||||||
|
|
||||||
def load_url(link: str, user_id: int):
|
def load_playlist(link: str, user_id: int):
|
||||||
|
author = link.split("/")[4]
|
||||||
|
playlist_id = link.split("/")[-1]
|
||||||
|
|
||||||
client = login()
|
client = login()
|
||||||
obj_id = link.split("/")[-1]
|
playlist = client.users_playlists(int(playlist_id), author) # type: Playlist
|
||||||
obj_id = obj_id.split("?")[0]
|
for track in playlist.fetch_tracks():
|
||||||
try:
|
|
||||||
obj_id = int(obj_id)
|
|
||||||
except ValueError:
|
|
||||||
print("Invalid link")
|
|
||||||
return None
|
|
||||||
|
|
||||||
if "/playlists/" in link:
|
|
||||||
author = link.split("/")[4]
|
|
||||||
|
|
||||||
playlist = client.users_playlists(obj_id, author) # type: Playlist
|
|
||||||
for track in playlist.fetch_tracks():
|
|
||||||
tasks.load_ym_file_meta.apply_async(
|
|
||||||
kwargs={"track": track.track.id, "user_id": user_id}
|
|
||||||
)
|
|
||||||
elif "/album/" in link:
|
|
||||||
album = client.albums_with_tracks(obj_id)
|
|
||||||
for volume in album.volumes:
|
|
||||||
for track in volume:
|
|
||||||
tasks.load_ym_file_meta.apply_async(
|
|
||||||
kwargs={"track": track.id, "user_id": user_id}
|
|
||||||
)
|
|
||||||
elif "/artist/" in link:
|
|
||||||
artist = client.artists(obj_id)[0]
|
|
||||||
albums = artist.get_albums(page_size=100)
|
|
||||||
for album in albums:
|
|
||||||
for track in album.fetch_tracks():
|
|
||||||
tasks.load_ym_file_meta.apply_async(
|
|
||||||
kwargs={"track": track.id, "user_id": user_id}
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
tasks.load_ym_file_meta.apply_async(
|
tasks.load_ym_file_meta.apply_async(
|
||||||
kwargs={"track": obj_id, "user_id": user_id}
|
kwargs={"track": track.track.id, "user_id": user_id}
|
||||||
)
|
)
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
logger = structlog.get_logger(__name__)
|
logger = structlog.get_logger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@shared_task(soft_time_limit=60 * 60, time_limit=60 * 120)
|
@shared_task(soft_time_limit=60 * 20, time_limit=60 * 30)
|
||||||
def list_tracks(url, user_id):
|
def list_tracks(url, user_id):
|
||||||
if "music.youtube.com" in url or "youtu.be" in url:
|
if "music.youtube.com" in url or "youtu.be" in url:
|
||||||
url = url.replace("music.youtube.com", "youtube.com")
|
url = url.replace("music.youtube.com", "youtube.com")
|
||||||
|
@ -37,7 +37,7 @@ def list_tracks(url, user_id):
|
||||||
if "spotify.com" in url:
|
if "spotify.com" in url:
|
||||||
spotify.download_url(url, user_id)
|
spotify.download_url(url, user_id)
|
||||||
elif "music.yandex.ru" in url:
|
elif "music.yandex.ru" in url:
|
||||||
yandex.load_url(url, user_id)
|
yandex.load_playlist(url, user_id)
|
||||||
if "youtube.com" in url:
|
if "youtube.com" in url:
|
||||||
if "channel" in url or "/c/" in url:
|
if "channel" in url or "/c/" in url:
|
||||||
ytmusic = ytmusicapi.YTMusic()
|
ytmusic = ytmusicapi.YTMusic()
|
||||||
|
@ -211,18 +211,11 @@ def listen_to_song(song_id, user_id=None, anon=True):
|
||||||
session_key=lastfm_token,
|
session_key=lastfm_token,
|
||||||
)
|
)
|
||||||
song = Song.objects.get(id=song_id)
|
song = Song.objects.get(id=song_id)
|
||||||
artist_name = song.get_first_author_name()
|
artist_name = song.artists_names
|
||||||
track_name = song.name
|
track_name = song.name
|
||||||
album_name = song.album.name
|
|
||||||
timestamp = int(timezone.now().timestamp())
|
timestamp = int(timezone.now().timestamp())
|
||||||
network.scrobble(
|
network.scrobble(
|
||||||
artist=artist_name,
|
artist=artist_name, title=track_name, timestamp=timestamp
|
||||||
title=track_name,
|
|
||||||
timestamp=timestamp,
|
|
||||||
album=album_name,
|
|
||||||
)
|
|
||||||
network.update_now_playing(
|
|
||||||
artist=artist_name, title=track_name, album=album_name
|
|
||||||
)
|
)
|
||||||
except UserMusicProfile.DoesNotExist:
|
except UserMusicProfile.DoesNotExist:
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1>Welcome to music app</h1>
|
<h1>Welcome to music app</h1>
|
||||||
<p>This is mainly the backend of music, you should consider using side clients like: <a href="https://next.akarpov.ru/music">otomir23's client</a> or my <a href="https://t.me/akarpov_music_bot">inline telegram bot</a></p>
|
<p>This is mainly the backend of music, you should consider using side clients like: <a href="https://next.akarpov.ru/music">otomir23's client</a></p>
|
||||||
{% if request.user.is_authenticated %}
|
{% if request.user.is_authenticated %}
|
||||||
{% if last_fm_account %}
|
{% if last_fm_account %}
|
||||||
<p>Last.fm connected to {{ last_fm_account }}, <a href="{% url 'music:lastfm_connect' %}">reconnect</a></p>
|
<p>Last.fm connected to {{ last_fm_account }}, <a href="{% url 'music:lastfm_connect' %}">reconnect</a></p>
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
from drf_spectacular.extensions import OpenApiAuthenticationExtension
|
|
||||||
from drf_spectacular.plumbing import build_bearer_security_scheme_object
|
|
||||||
from rest_framework.authentication import BaseAuthentication
|
from rest_framework.authentication import BaseAuthentication
|
||||||
|
|
||||||
from akarpov.users.models import User, UserAPIToken
|
from akarpov.users.models import UserAPIToken
|
||||||
from akarpov.users.tasks import set_last_active_token
|
from akarpov.users.tasks import set_last_active_token
|
||||||
|
|
||||||
|
|
||||||
|
@ -21,14 +19,4 @@ def authenticate(self, request):
|
||||||
return None
|
return None
|
||||||
set_last_active_token.delay(token.token)
|
set_last_active_token.delay(token.token)
|
||||||
|
|
||||||
return User.objects.cache().get(id=token.user_id), token
|
return token.user, token
|
||||||
|
|
||||||
|
|
||||||
class UserTokenAuthenticationExtension(OpenApiAuthenticationExtension):
|
|
||||||
target_class = "akarpov.users.api.authentification.UserTokenAuthentication"
|
|
||||||
name = "UserTokenAuthentication"
|
|
||||||
|
|
||||||
def get_security_definition(self, auto_schema):
|
|
||||||
return build_bearer_security_scheme_object(
|
|
||||||
header_name="Authorization", token_prefix="Bearer"
|
|
||||||
)
|
|
||||||
|
|
|
@ -18,8 +18,6 @@
|
||||||
)
|
)
|
||||||
from akarpov.users.models import User
|
from akarpov.users.models import User
|
||||||
|
|
||||||
from .authentification import UserTokenAuthentication # noqa: F401
|
|
||||||
|
|
||||||
|
|
||||||
class UserRegisterAPIViewSet(generics.CreateAPIView):
|
class UserRegisterAPIViewSet(generics.CreateAPIView):
|
||||||
"""Creates new user and sends verification email"""
|
"""Creates new user and sends verification email"""
|
||||||
|
|
|
@ -214,16 +214,23 @@ def list_tokens(request):
|
||||||
@login_required
|
@login_required
|
||||||
def create_token(request):
|
def create_token(request):
|
||||||
initial_data = {}
|
initial_data = {}
|
||||||
|
|
||||||
|
# Обработка параметров 'name' и 'active_until'
|
||||||
if "name" in request.GET:
|
if "name" in request.GET:
|
||||||
initial_data["name"] = request.GET["name"]
|
initial_data["name"] = request.GET["name"]
|
||||||
if "active_until" in request.GET:
|
if "active_until" in request.GET:
|
||||||
initial_data["active_until"] = request.GET["active_until"]
|
initial_data["active_until"] = request.GET["active_until"]
|
||||||
|
|
||||||
|
# Создаем QueryDict для разрешений, чтобы правильно обработать повторяющиеся ключи
|
||||||
permissions_query_dict = QueryDict("", mutable=True)
|
permissions_query_dict = QueryDict("", mutable=True)
|
||||||
|
|
||||||
|
# Разбор параметров разрешений
|
||||||
permissions = request.GET.getlist("permissions")
|
permissions = request.GET.getlist("permissions")
|
||||||
for perm in permissions:
|
for perm in permissions:
|
||||||
category, permission = perm.split(".")
|
category, permission = perm.split(".")
|
||||||
permissions_query_dict.update({f"permissions_{category}": [permission]})
|
permissions_query_dict.update({f"permissions_{category}": [permission]})
|
||||||
|
|
||||||
|
# Переводим QueryDict в обычный словарь для использования в initial
|
||||||
permissions_data = {key: value for key, value in permissions_query_dict.lists()}
|
permissions_data = {key: value for key, value in permissions_query_dict.lists()}
|
||||||
|
|
||||||
initial_data.update(permissions_data)
|
initial_data.update(permissions_data)
|
||||||
|
@ -235,6 +242,7 @@ def create_token(request):
|
||||||
initial=initial_data, permissions_context=UserAPIToken.permission_template
|
initial=initial_data, permissions_context=UserAPIToken.permission_template
|
||||||
)
|
)
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
|
print(request.POST)
|
||||||
form = TokenCreationForm(request.POST)
|
form = TokenCreationForm(request.POST)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
new_token = form.save(commit=False)
|
new_token = form.save(commit=False)
|
||||||
|
|
|
@ -80,7 +80,6 @@
|
||||||
"music.*": {"ops": ("fetch", "get", "list"), "timeout": 60 * 15},
|
"music.*": {"ops": ("fetch", "get", "list"), "timeout": 60 * 15},
|
||||||
"otp_totp.totpdevice": {"ops": "all", "timeout": 15 * 60},
|
"otp_totp.totpdevice": {"ops": "all", "timeout": 15 * 60},
|
||||||
"users.userapitoken": {"ops": "all", "timeout": 20 * 60},
|
"users.userapitoken": {"ops": "all", "timeout": 20 * 60},
|
||||||
"users.user": {"ops": "all", "timeout": 5 * 60},
|
|
||||||
}
|
}
|
||||||
CACHEOPS_REDIS = env.str("REDIS_URL")
|
CACHEOPS_REDIS = env.str("REDIS_URL")
|
||||||
|
|
||||||
|
@ -529,11 +528,6 @@
|
||||||
{"url": "http://127.0.0.1:8000", "description": "Local Development server"},
|
{"url": "http://127.0.0.1:8000", "description": "Local Development server"},
|
||||||
{"url": "https://new.akarpov.ru", "description": "Production server"},
|
{"url": "https://new.akarpov.ru", "description": "Production server"},
|
||||||
],
|
],
|
||||||
"EXTENSIONS": {
|
|
||||||
"authentication": [
|
|
||||||
"akarpov.users.api.authentification.UserTokenAuthenticationExtension"
|
|
||||||
],
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# CKEDITOR
|
# CKEDITOR
|
||||||
|
@ -754,7 +748,6 @@
|
||||||
ELASTICSEARCH_DSL = {
|
ELASTICSEARCH_DSL = {
|
||||||
"default": {"hosts": env("ELASTIC_SEARCH", default="http://127.0.0.1:9200/")},
|
"default": {"hosts": env("ELASTIC_SEARCH", default="http://127.0.0.1:9200/")},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
USE_DEBUG_TOOLBAR = False
|
USE_DEBUG_TOOLBAR = False
|
||||||
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
|
|
||||||
USE_X_FORWARDED_HOST = True
|
|
||||||
USE_X_FORWARDED_PORT = True
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user