Compare commits
4 Commits
delayed_pu
...
master
Author | SHA1 | Date |
---|---|---|
Alexei | f3345f6da5 | 1 year ago |
Alexei | 7c7053f47e | 1 year ago |
Alexei | 867f999174 | 1 year ago |
Артур Галямов | 75af7b0b79 | 2 years ago |
16 changed files with 451 additions and 464 deletions
@ -0,0 +1,3 @@ |
|||||||
|
Этот продукт является ОБЩЕСТВЕННЫМ ДОСТОЯНИЕМ и может быть использован КАК ЕСТЬ, со всеми достоинствами и недостатками, полностью или частично, кем угодно и в каких угодно целях БЕЗ КАКИХ-ЛИБО ОГРАНИЧЕНИЙ. |
||||||
|
|
||||||
|
This product is PUBLIC DOMAIN and may be used AS IS, with all advantages and faults, in whole or in part, by anyone for any purpose, WITHOUT ANY CONDITIONS. |
After Width: | Height: | Size: 56 KiB |
After Width: | Height: | Size: 101 KiB |
After Width: | Height: | Size: 24 KiB |
@ -1,3 +0,0 @@ |
|||||||
from .celery import app as celery_app |
|
||||||
|
|
||||||
__all__ = ('celery_app') |
|
@ -1,15 +0,0 @@ |
|||||||
from __future__ import absolute_import, unicode_literals |
|
||||||
import os |
|
||||||
from celery import Celery |
|
||||||
|
|
||||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'crossposting_backend.settings') |
|
||||||
|
|
||||||
CELERY_TIMEZONE = 'Europe/Moscow' |
|
||||||
|
|
||||||
app = Celery('cms') |
|
||||||
app.config_from_object('django.conf:settings', namespace='CELERY') |
|
||||||
app.autodiscover_tasks() |
|
||||||
|
|
||||||
@app.task(bind=True) |
|
||||||
def debug_task(self): |
|
||||||
print(f'Requestgit {self.request!r}') |
|
@ -1,23 +1,22 @@ |
|||||||
from django import forms |
from django import forms |
||||||
from django.contrib.auth import models as auth_models |
from django.contrib.auth import models as auth_models |
||||||
|
|
||||||
from .models import Article |
from .models import Article |
||||||
|
|
||||||
|
|
||||||
class ArticleForm(forms.ModelForm): |
class ArticleForm(forms.ModelForm): |
||||||
link_widget = forms.TextInput(attrs={'placeholder': 'Введите ссылку новости'}) |
link_widget = forms.TextInput(attrs={'placeholder': 'Введите ссылку новости'}) |
||||||
link = forms.CharField(widget=link_widget) |
link = forms.CharField(widget=link_widget) |
||||||
publication_time = forms.DateTimeField(widget=forms.DateTimeInput(attrs={'type': 'datetime-local'}), required=False) |
|
||||||
|
class Meta: |
||||||
class Meta: |
model = Article |
||||||
model = Article |
fields = ('body', 'link',) |
||||||
fields = ('body', 'link', 'publication_time') |
|
||||||
|
|
||||||
|
class UserForm(forms.ModelForm): |
||||||
class UserForm(forms.ModelForm): |
class Meta: |
||||||
class Meta: |
model = auth_models.User |
||||||
model = auth_models.User |
fields = ('username', 'password',) |
||||||
fields = ('username', 'password',) |
widgets = { |
||||||
widgets = { |
'password': forms.PasswordInput(), |
||||||
'password': forms.PasswordInput(), |
} |
||||||
} |
|
||||||
|
@ -1,9 +1,6 @@ |
|||||||
from django.db import models |
from django.db import models |
||||||
|
|
||||||
|
|
||||||
class Article(models.Model): |
class Article(models.Model): |
||||||
id = models.BigAutoField(primary_key=True) |
body = models.TextField(null=False) |
||||||
body = models.TextField(null=False) |
link = models.CharField(max_length=200, null=False) |
||||||
link = models.CharField(max_length=200, null=False) |
|
||||||
publication_time = models.DateTimeField(blank=True, null=True) |
|
||||||
is_published = models.BooleanField(default=False) |
|
||||||
|
@ -1,19 +0,0 @@ |
|||||||
from cms import promoters |
|
||||||
from cms.models import Article |
|
||||||
from celery import shared_task |
|
||||||
|
|
||||||
|
|
||||||
@shared_task |
|
||||||
def promote_post(article_id): |
|
||||||
article = Article.objects.get(id=article_id) |
|
||||||
article.is_published = True |
|
||||||
article.save() |
|
||||||
marketer = promoters.Marketer(article) |
|
||||||
marketer.promote() |
|
||||||
|
|
||||||
|
|
||||||
@shared_task |
|
||||||
def delayed_post(article_id, publication_time): |
|
||||||
article = Article.objects.get(id=article_id) |
|
||||||
celery_task = promote_post.apply_async(args=[article.id], eta=publication_time) |
|
||||||
return celery_task.id |
|
@ -1,82 +1,67 @@ |
|||||||
{% extends 'base.html' %} |
{% extends 'base.html' %} |
||||||
{% load bootstrap5 %} |
{% load bootstrap5 %} |
||||||
{% block content %} |
{% block content %} |
||||||
<div class="container"> |
<div class="container"> |
||||||
<div class="row my-5"> |
<div class="row my-5"> |
||||||
<div class="col-md-12"> |
<div class="col-md-12"> |
||||||
<h1>Заполните данные статьи для продвижения в соц. сетях</h1> |
<h1>Заполните данные статьи для продвижения в соц. сетях</h1> |
||||||
<form |
<form |
||||||
method="post" |
method="post" |
||||||
enctype="application/x-www-form-urlencoded" |
enctype="application/x-www-form-urlencoded" |
||||||
action="{% url 'create-article' %}" |
action="{% url 'create-article' %}" |
||||||
class="form" |
class="form" |
||||||
> |
> |
||||||
{% csrf_token %} |
{% csrf_token %} |
||||||
{% bootstrap_form new_article_form %} |
{% bootstrap_form new_article_form %} |
||||||
{% buttons %} |
{% buttons %} |
||||||
<div class="row"> |
<div class="row"> |
||||||
<div class="col"> |
<div class="col"> |
||||||
<button |
<button |
||||||
class="btn btn-primary" |
class="btn btn-primary" |
||||||
type="submit" |
type="submit" |
||||||
id="submit-button"> |
disabled="disabled" |
||||||
{% if new_article_form.publication_time.value %} |
> |
||||||
disabled="disabled" |
Продвинуть |
||||||
{% endif %} |
</button> |
||||||
{% if new_article_form.publication_time.value %} |
</div> |
||||||
Запланировать |
|
||||||
{% else %} |
<div id="vkShare" class="col"></div> |
||||||
Опубликовать сейчас |
</div> |
||||||
{% endif %} |
|
||||||
</button> |
{% endbuttons %} |
||||||
|
</form> |
||||||
<a href="{% url 'planned' %}" class="btn btn-primary">Список отложенных публикаций</a> |
</div> |
||||||
</div> |
</div> |
||||||
<script> |
</div> |
||||||
document.getElementById("id_publication_time").addEventListener("change", function() { |
{% endblock content %} |
||||||
var submitButton = document.getElementById("submit-button"); |
{% block extra_scripts %} |
||||||
if (this.value) { |
<script type="text/javascript"> |
||||||
submitButton.innerHTML = "Запланировать"; |
let submitBtn = null |
||||||
} else { |
const enableSubmitBtn = () => { |
||||||
submitButton.innerHTML = "Опубликовать"; |
submitBtn.disabled = false |
||||||
} |
} |
||||||
}); |
const appendShare = (e) => { |
||||||
</script> |
submitBtn.disabled = true |
||||||
|
|
||||||
<div id="vkShare" class="col"></div> |
const articleLink = e.target.value; |
||||||
</div> |
const gen = { |
||||||
{% endbuttons %} |
url: articleLink |
||||||
</form> |
} |
||||||
</div> |
const buttonType = { |
||||||
</div> |
type: "custom", |
||||||
</div> |
text: '<img src="https://vk.com/images/share_32_2x.png" width="32" height="32" alt="share icon" />' |
||||||
{% endblock content %} |
} |
||||||
{% block extra_scripts %} |
document.getElementById('vkShare').innerHTML = VK.Share.button(gen, buttonType) |
||||||
<script type="text/javascript"> |
const vkButtons = document.querySelectorAll('a[href^="//vk.com/"]') |
||||||
let submitBtn = null |
vkButtons.forEach((vkBtn) => vkBtn.addEventListener('click', enableSubmitBtn)) |
||||||
const enableSubmitBtn = () => { |
} |
||||||
submitBtn.disabled = false |
const main = () => { |
||||||
} |
submitBtn = document.querySelector('button[type="submit"]') |
||||||
const appendShare = (e) => { |
|
||||||
submitBtn.disabled = true |
const linkInput = document.querySelector('[name="link"]'); |
||||||
const articleLink = e.target.value; |
linkInput.addEventListener('input', appendShare) |
||||||
const gen = { |
linkInput.addEventListener('paste', appendShare) |
||||||
url: articleLink |
} |
||||||
} |
window.addEventListener('DOMContentLoaded', main) |
||||||
const buttonType = { |
</script> |
||||||
type: "custom", |
|
||||||
text: '<img src="https://vk.com/images/share_32_2x.png" width="32" height="32" alt="share icon" />' |
|
||||||
} |
|
||||||
document.getElementById('vkShare').innerHTML = VK.Share.button(gen, buttonType) |
|
||||||
const vkButtons = document.querySelectorAll('a[href^="//vk.com/"]') |
|
||||||
vkButtons.forEach((vkBtn) => vkBtn.addEventListener('click', enableSubmitBtn)) |
|
||||||
} |
|
||||||
const main = () => { |
|
||||||
submitBtn = document.querySelector('button[type="submit"]') |
|
||||||
const linkInput = document.querySelector('[name="link"]'); |
|
||||||
linkInput.addEventListener('input', appendShare) |
|
||||||
linkInput.addEventListener('paste', appendShare) |
|
||||||
} |
|
||||||
window.addEventListener('DOMContentLoaded', main) |
|
||||||
</script> |
|
||||||
{% endblock %} |
{% endblock %} |
@ -1,20 +0,0 @@ |
|||||||
{% extends 'base.html' %} |
|
||||||
{% load bootstrap5 %} |
|
||||||
{% block content %} |
|
||||||
<div class="container"> |
|
||||||
<a href="{% url 'new-article' %}" class="btn btn-primary">Вернуться</a> |
|
||||||
|
|
||||||
{% for article in post %} |
|
||||||
<div class="card mb-3"> |
|
||||||
<div class="card-body"> |
|
||||||
<p class="card-text">{{ article.body }}</p> |
|
||||||
<a href="{{ article.link }}">{{ article.link }}</a> |
|
||||||
<p class="card-text"><small class="text-muted">Дата публикации: {{ article.publication_time }}</small></p> |
|
||||||
{% if user.is_authenticated %} |
|
||||||
<a href="{% url 'article_delete' article.id %}" class="btn btn-danger">Удалить</a> |
|
||||||
{% endif %} |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
{% endfor %} |
|
||||||
</div> |
|
||||||
{% endblock content %} |
|
@ -1,14 +1,13 @@ |
|||||||
from django.urls import path |
from django.urls import path |
||||||
from .views import ArticleView, new_article, AuthenticationView, plannedView, articleDelete |
|
||||||
|
from .views import ArticleView, new_article, AuthenticationView |
||||||
urlpatterns = [ |
|
||||||
path('articles/', ArticleView.as_view(), name='create-article'), |
urlpatterns = [ |
||||||
path('articles/new/', new_article, name='new-article'), |
path('articles/', ArticleView.as_view(), name='create-article'), |
||||||
path( |
path('articles/new/', new_article, name='new-article'), |
||||||
'', |
path( |
||||||
AuthenticationView.as_view(), |
'', |
||||||
name='authenticate' |
AuthenticationView.as_view(), |
||||||
), |
name='authenticate' |
||||||
path('articles/planned/', plannedView, name='planned'), |
) |
||||||
path('articles/article_delete/<int:id>/', articleDelete, name='article_delete'), |
] |
||||||
] |
|
||||||
|
@ -1,102 +1,71 @@ |
|||||||
from django.contrib import messages |
from django.contrib import messages |
||||||
from django.contrib.auth import authenticate, login |
from django.contrib.auth import authenticate, login |
||||||
from django.contrib.auth.decorators import login_required |
from django.contrib.auth.decorators import login_required |
||||||
from django.contrib.auth.mixins import LoginRequiredMixin |
from django.contrib.auth.mixins import LoginRequiredMixin |
||||||
from django.http import HttpRequest, HttpResponseRedirect |
from django.http import HttpRequest, HttpResponseRedirect |
||||||
from django.shortcuts import render, redirect |
from django.shortcuts import render |
||||||
from django.urls import reverse |
from django.urls import reverse |
||||||
from django.views import View |
from django.views import View |
||||||
from requests import request |
|
||||||
|
from cms import promoters |
||||||
from cms import promoters |
from cms.forms import ArticleForm, UserForm |
||||||
from cms.forms import ArticleForm, UserForm |
from cms.models import Article |
||||||
from cms.models import Article |
|
||||||
from cms.tasks import delayed_post |
|
||||||
from datetime import datetime, timezone |
class ArticleView(LoginRequiredMixin, View): |
||||||
|
def post(self, request: HttpRequest): |
||||||
|
post_data = request.POST |
||||||
class ArticleView(LoginRequiredMixin, View): |
article = Article.objects.create(body=post_data['body'], |
||||||
def post(self, request: HttpRequest): |
link=post_data['link']) |
||||||
post_data = request.POST |
marketer = promoters.Marketer(article) |
||||||
if 'publication_time' not in post_data or post_data['publication_time'] == "": |
try: |
||||||
# Значение publication_time не указано |
marketer.promote() |
||||||
article = Article.objects.create(body=post_data['body'], |
message_type = messages.SUCCESS |
||||||
link=post_data['link'], |
message_text = 'Продвижение статьи прошло успешно' |
||||||
publication_time=datetime.now()) |
except promoters.PromoteError as exc: |
||||||
|
message_type = messages.ERROR |
||||||
marketer = promoters.Marketer(article) |
message_text = 'Произошла ошибка: %s' % str(exc) |
||||||
try: |
messages.add_message(request=request, |
||||||
marketer.promote() |
level=message_type, |
||||||
article.is_published = 1 |
message=message_text) |
||||||
message_type = messages.SUCCESS |
return HttpResponseRedirect(reverse('new-article')) |
||||||
message_text = 'Продвижение статьи прошло успешно' |
|
||||||
article.is_published = True |
|
||||||
article.save() |
@login_required |
||||||
except promoters.PromoteError as exc: |
def new_article(request): |
||||||
message_type = messages.ERROR |
article_form = ArticleForm() |
||||||
message_text = 'Произошла ошибка: %s' % str(exc) |
article_context = { |
||||||
messages.add_message(request=request, |
'new_article_form': article_form |
||||||
level=message_type, |
} |
||||||
message=message_text) |
return render(request, |
||||||
|
template_name='articles/new.html', |
||||||
else: |
context=article_context) |
||||||
# Значение publication_time указано |
|
||||||
publication_time = post_data['publication_time'] |
|
||||||
publication_time = datetime.fromisoformat(publication_time) |
class AuthenticationView(View): |
||||||
publication_time = publication_time.astimezone(timezone.utc) |
def get(self, request, *args, **kwargs): |
||||||
article = Article.objects.create(body=post_data['body'], |
user_form = UserForm() |
||||||
link=post_data['link'], |
auth_context = { |
||||||
publication_time=publication_time) |
'user_form': user_form, |
||||||
|
} |
||||||
delayed_post.apply_async(args=(article.id, publication_time), eta=publication_time) |
return render(request, |
||||||
return HttpResponseRedirect(reverse('new-article')) |
'user/sign_in.html', |
||||||
|
context=auth_context) |
||||||
|
|
||||||
@login_required |
def post(self, request, *args, **kwargs): |
||||||
def new_article(request): |
username = request.POST['username'] |
||||||
article_form = ArticleForm() |
password = request.POST['password'] |
||||||
article_context = { |
authenticated_user = authenticate(username=username, |
||||||
'new_article_form': article_form |
password=password) |
||||||
} |
if authenticated_user is None: |
||||||
return render(request, |
messages.add_message(request, |
||||||
template_name='articles/new.html', |
messages.ERROR, |
||||||
context=article_context) |
'Неправильное имя пользователя и/или пароль') |
||||||
|
return HttpResponseRedirect(reverse('authenticate')) |
||||||
|
else: |
||||||
class AuthenticationView(View): |
messages.add_message(request, |
||||||
def get(self, request, *args, **kwargs): |
messages.SUCCESS, |
||||||
user_form = UserForm() |
'Поздравляю, вы вошли успешно') |
||||||
auth_context = { |
login(request, |
||||||
'user_form': user_form, |
user=authenticated_user) |
||||||
} |
return HttpResponseRedirect(reverse('new-article')) |
||||||
return render(request, |
|
||||||
'user/sign_in.html', |
|
||||||
context=auth_context) |
|
||||||
|
|
||||||
def post(self, request, *args, **kwargs): |
|
||||||
username = request.POST['username'] |
|
||||||
password = request.POST['password'] |
|
||||||
authenticated_user = authenticate(username=username, |
|
||||||
password=password) |
|
||||||
if authenticated_user is None: |
|
||||||
messages.add_message(request, |
|
||||||
messages.ERROR, |
|
||||||
'Неправильное имя пользователя и/или пароль') |
|
||||||
return HttpResponseRedirect(reverse('authenticate')) |
|
||||||
else: |
|
||||||
messages.add_message(request, |
|
||||||
messages.SUCCESS, |
|
||||||
'Поздравляю, вы вошли успешно') |
|
||||||
login(request, |
|
||||||
user=authenticated_user) |
|
||||||
return HttpResponseRedirect(reverse('new-article')) |
|
||||||
|
|
||||||
|
|
||||||
def plannedView(request): |
|
||||||
data = Article.objects.filter(is_published=False) |
|
||||||
return render(request, 'articles/planned.html', context={'post':data}) |
|
||||||
|
|
||||||
def articleDelete(request, id): |
|
||||||
article = Article.objects.get(id=id) |
|
||||||
article.delete() |
|
||||||
return redirect('planned') |
|
||||||
|
@ -1,160 +1,155 @@ |
|||||||
""" |
""" |
||||||
Django settings for crossposting_backend project. |
Django settings for crossposting_backend project. |
||||||
|
|
||||||
Generated by 'django-admin startproject' using Django 4.1.4. |
Generated by 'django-admin startproject' using Django 4.1.4. |
||||||
|
|
||||||
For more information on this file, see |
For more information on this file, see |
||||||
https://docs.djangoproject.com/en/4.1/topics/settings/ |
https://docs.djangoproject.com/en/4.1/topics/settings/ |
||||||
|
|
||||||
For the full list of settings and their values, see |
For the full list of settings and their values, see |
||||||
https://docs.djangoproject.com/en/4.1/ref/settings/ |
https://docs.djangoproject.com/en/4.1/ref/settings/ |
||||||
""" |
""" |
||||||
|
|
||||||
from os import path, getenv |
from os import path, getenv |
||||||
from pathlib import Path |
from pathlib import Path |
||||||
|
|
||||||
import dotenv |
import dotenv |
||||||
from celery.schedules import crontab |
from django.core import signing |
||||||
from django.core import signing |
|
||||||
|
from .private.settings import * |
||||||
from .private.settings import * |
|
||||||
|
|
||||||
|
def decode_env(env_key: str) -> str: |
||||||
def decode_env(env_key: str) -> str: |
signer = signing.Signer(salt=SALT) |
||||||
signer = signing.Signer(salt=SALT) |
signed_telegram_chat_id_dict = getenv(env_key) |
||||||
signed_telegram_chat_id_dict = getenv(env_key) |
return signer.unsign_object(signed_telegram_chat_id_dict)[env_key] |
||||||
return signer.unsign_object(signed_telegram_chat_id_dict)[env_key] |
|
||||||
|
|
||||||
|
def return_env(env_key: str) -> str: |
||||||
def return_env(env_key: str) -> str: |
""" |
||||||
""" |
Функция нужна как стратегия, если not ENV_ENCODED |
||||||
Функция нужна как стратегия, если not ENV_ENCODED |
:param env_key: |
||||||
:param env_key: |
:return: |
||||||
:return: |
""" |
||||||
""" |
return getenv(env_key) |
||||||
return getenv(env_key) |
|
||||||
|
|
||||||
|
BASE_DIR = Path(__file__).resolve().parent.parent |
||||||
BASE_DIR = Path(__file__).resolve().parent.parent |
env_file = path.join(BASE_DIR, '.env') |
||||||
env_file = path.join(BASE_DIR, '.env') |
|
||||||
|
dotenv.read_dotenv(env_file) |
||||||
dotenv.read_dotenv(env_file) |
|
||||||
|
promoter_env_keys = ( |
||||||
promoter_env_keys = ( |
'TELEGRAM_BOT_TOKEN', 'TELEGRAM_CHAT_ID', 'JOOMLA_TOKEN', |
||||||
'TELEGRAM_BOT_TOKEN', 'TELEGRAM_CHAT_ID', 'JOOMLA_TOKEN', |
'VK_OWNER_ID', 'VK_TOKEN', 'OK_ACCESS_TOKEN', 'OK_APPLICATION_KEY', |
||||||
'VK_OWNER_ID', 'VK_TOKEN', 'OK_ACCESS_TOKEN', 'OK_APPLICATION_KEY', |
'OK_APPLICATION_SECRET_KEY', 'OK_GROUP_ID', |
||||||
'OK_APPLICATION_SECRET_KEY', 'OK_GROUP_ID', |
) |
||||||
) |
promoter_secrets = {} |
||||||
promoter_secrets = {} |
if ENV_ENCODED: |
||||||
if ENV_ENCODED: |
decode_strategy = decode_env |
||||||
decode_strategy = decode_env |
else: |
||||||
else: |
decode_strategy = return_env |
||||||
decode_strategy = return_env |
|
||||||
|
for promoter_env_key in promoter_env_keys: |
||||||
for promoter_env_key in promoter_env_keys: |
promoter_secrets[promoter_env_key] = decode_strategy(promoter_env_key) |
||||||
promoter_secrets[promoter_env_key] = decode_strategy(promoter_env_key) |
|
||||||
|
# Build paths inside the project like this: BASE_DIR / 'subdir'. |
||||||
# Build paths inside the project like this: BASE_DIR / 'subdir'. |
|
||||||
|
# Quick-start development settings - unsuitable for production |
||||||
# Quick-start development settings - unsuitable for production |
# See https://docs.djangoproject.com/en/4.1/howto/deployment/checklist/ |
||||||
# See https://docs.djangoproject.com/en/4.1/howto/deployment/checklist/ |
|
||||||
|
|
||||||
|
LOGIN_URL = '/cms/' |
||||||
LOGIN_URL = '/cms/' |
|
||||||
|
# Application definition |
||||||
# Application definition |
|
||||||
|
INSTALLED_APPS = [ |
||||||
INSTALLED_APPS = [ |
'django.contrib.admin', |
||||||
'django.contrib.admin', |
'django.contrib.auth', |
||||||
'django.contrib.auth', |
'django.contrib.contenttypes', |
||||||
'django.contrib.contenttypes', |
'django.contrib.sessions', |
||||||
'django.contrib.sessions', |
'django.contrib.messages', |
||||||
'django.contrib.messages', |
'django.contrib.staticfiles', |
||||||
'django.contrib.staticfiles', |
'cms', |
||||||
'cms', |
'bootstrap5', |
||||||
'bootstrap5', |
] |
||||||
'django_celery_beat', |
|
||||||
] |
MIDDLEWARE = [ |
||||||
|
'django.middleware.security.SecurityMiddleware', |
||||||
MIDDLEWARE = [ |
'django.contrib.sessions.middleware.SessionMiddleware', |
||||||
'django.middleware.security.SecurityMiddleware', |
'django.middleware.common.CommonMiddleware', |
||||||
'django.contrib.sessions.middleware.SessionMiddleware', |
'django.middleware.csrf.CsrfViewMiddleware', |
||||||
'django.middleware.common.CommonMiddleware', |
'django.contrib.auth.middleware.AuthenticationMiddleware', |
||||||
'django.middleware.csrf.CsrfViewMiddleware', |
'django.contrib.messages.middleware.MessageMiddleware', |
||||||
'django.contrib.auth.middleware.AuthenticationMiddleware', |
'django.middleware.clickjacking.XFrameOptionsMiddleware', |
||||||
'django.contrib.messages.middleware.MessageMiddleware', |
] |
||||||
'django.middleware.clickjacking.XFrameOptionsMiddleware', |
|
||||||
] |
ROOT_URLCONF = 'crossposting_backend.urls' |
||||||
|
|
||||||
ROOT_URLCONF = 'crossposting_backend.urls' |
TEMPLATES = [ |
||||||
|
{ |
||||||
TEMPLATES = [ |
'BACKEND': 'django.template.backends.django.DjangoTemplates', |
||||||
{ |
'DIRS': [BASE_DIR / 'templates'], |
||||||
'BACKEND': 'django.template.backends.django.DjangoTemplates', |
'APP_DIRS': True, |
||||||
'DIRS': [BASE_DIR / 'templates'], |
'OPTIONS': { |
||||||
'APP_DIRS': True, |
'context_processors': [ |
||||||
'OPTIONS': { |
'django.template.context_processors.debug', |
||||||
'context_processors': [ |
'django.template.context_processors.request', |
||||||
'django.template.context_processors.debug', |
'django.contrib.auth.context_processors.auth', |
||||||
'django.template.context_processors.request', |
'django.contrib.messages.context_processors.messages', |
||||||
'django.contrib.auth.context_processors.auth', |
], |
||||||
'django.contrib.messages.context_processors.messages', |
}, |
||||||
], |
}, |
||||||
}, |
] |
||||||
}, |
|
||||||
] |
WSGI_APPLICATION = 'crossposting_backend.wsgi.application' |
||||||
|
|
||||||
WSGI_APPLICATION = 'crossposting_backend.wsgi.application' |
# Database |
||||||
|
# https://docs.djangoproject.com/en/4.1/ref/settings/#databases |
||||||
# Database |
|
||||||
# https://docs.djangoproject.com/en/4.1/ref/settings/#databases |
DATABASES = { |
||||||
|
'default': { |
||||||
DATABASES = { |
'ENGINE': 'django.db.backends.sqlite3', |
||||||
'default': { |
'NAME': BASE_DIR / 'db.sqlite3', |
||||||
'ENGINE': 'django.db.backends.sqlite3', |
} |
||||||
'NAME': BASE_DIR / 'db.sqlite3', |
} |
||||||
} |
|
||||||
} |
# Password validation |
||||||
|
# https://docs.djangoproject.com/en/4.1/ref/settings/#auth-password-validators |
||||||
# Password validation |
|
||||||
# https://docs.djangoproject.com/en/4.1/ref/settings/#auth-password-validators |
AUTH_PASSWORD_VALIDATORS = [ |
||||||
|
{ |
||||||
AUTH_PASSWORD_VALIDATORS = [ |
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', |
||||||
{ |
}, |
||||||
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', |
{ |
||||||
}, |
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', |
||||||
{ |
}, |
||||||
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', |
{ |
||||||
}, |
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', |
||||||
{ |
}, |
||||||
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', |
{ |
||||||
}, |
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', |
||||||
{ |
}, |
||||||
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', |
] |
||||||
}, |
|
||||||
] |
# Internationalization |
||||||
|
# https://docs.djangoproject.com/en/4.1/topics/i18n/ |
||||||
# Internationalization |
|
||||||
# https://docs.djangoproject.com/en/4.1/topics/i18n/ |
LANGUAGE_CODE = 'en-us' |
||||||
|
|
||||||
LANGUAGE_CODE = 'en-us' |
TIME_ZONE = 'UTC' |
||||||
|
|
||||||
TIME_ZONE = 'Europe/Moscow' |
USE_I18N = True |
||||||
|
|
||||||
USE_I18N = True |
USE_TZ = True |
||||||
|
|
||||||
USE_TZ = True |
# Static files (CSS, JavaScript, Images) |
||||||
|
# https://docs.djangoproject.com/en/4.1/howto/static-files/ |
||||||
# Static files (CSS, JavaScript, Images) |
|
||||||
# https://docs.djangoproject.com/en/4.1/howto/static-files/ |
STATIC_URL = 'static/' |
||||||
|
STATIC_ROOT = path.join(BASE_DIR, 'static') |
||||||
STATIC_URL = 'static/' |
|
||||||
STATIC_ROOT = path.join(BASE_DIR, 'static') |
# Default primary key field type |
||||||
|
# https://docs.djangoproject.com/en/4.1/ref/settings/#default-auto-field |
||||||
# Default primary key field type |
|
||||||
# https://docs.djangoproject.com/en/4.1/ref/settings/#default-auto-field |
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' |
||||||
|
|
||||||
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' |
|
||||||
|
|
||||||
CELERY_BROKER_URL = 'redis://localhost:6379/' |
|
||||||
CELERY_RESULT_BACKEND = 'redis://localhost:6379/' |
|
||||||
|
@ -1,18 +1,14 @@ |
|||||||
asgiref==3.5.2 |
asgiref==3.5.2 |
||||||
beautifulsoup4==4.11.1 |
beautifulsoup4==4.11.1 |
||||||
certifi==2022.12.7 |
certifi==2022.12.7 |
||||||
charset-normalizer==2.1.1 |
charset-normalizer==2.1.1 |
||||||
Django==4.1.4 |
Django==4.1.4 |
||||||
django-bootstrap-v5==1.0.11 |
django-bootstrap-v5==1.0.11 |
||||||
django-dotenv==1.4.2 |
django-dotenv==1.4.2 |
||||||
idna==3.4 |
idna==3.4 |
||||||
ok-api==1.0.1 |
ok-api==1.0.1 |
||||||
requests==2.28.1 |
requests==2.28.1 |
||||||
soupsieve==2.3.2.post1 |
soupsieve==2.3.2.post1 |
||||||
sqlparse==0.4.3 |
sqlparse==0.4.3 |
||||||
urllib3==1.26.13 |
urllib3==1.26.13 |
||||||
vk-api==11.9.9 |
vk-api==11.9.9 |
||||||
celery==5.3.6 |
|
||||||
django-celery-beat==2.6.0 |
|
||||||
redis==5.0.4 |
|
||||||
|
|
||||||
|
Loading…
Reference in new issue