Compare commits
3 Commits
master
...
delayed_pu
Author | SHA1 | Date |
---|---|---|
Fynjy | 33ede3992a | 8 months ago |
Fynjy | b4452019ef | 8 months ago |
Fynjy | 8ba795a2d3 | 8 months ago |
11 changed files with 464 additions and 347 deletions
@ -0,0 +1,3 @@
|
||||
from .celery import app as celery_app |
||||
|
||||
__all__ = ('celery_app') |
@ -0,0 +1,15 @@
|
||||
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,22 +1,23 @@
|
||||
from django import forms |
||||
from django.contrib.auth import models as auth_models |
||||
|
||||
from .models import Article |
||||
|
||||
|
||||
class ArticleForm(forms.ModelForm): |
||||
link_widget = forms.TextInput(attrs={'placeholder': 'Введите ссылку новости'}) |
||||
link = forms.CharField(widget=link_widget) |
||||
|
||||
class Meta: |
||||
model = Article |
||||
fields = ('body', 'link',) |
||||
|
||||
|
||||
class UserForm(forms.ModelForm): |
||||
class Meta: |
||||
model = auth_models.User |
||||
fields = ('username', 'password',) |
||||
widgets = { |
||||
'password': forms.PasswordInput(), |
||||
} |
||||
from django import forms |
||||
from django.contrib.auth import models as auth_models |
||||
|
||||
from .models import Article |
||||
|
||||
|
||||
class ArticleForm(forms.ModelForm): |
||||
link_widget = forms.TextInput(attrs={'placeholder': 'Введите ссылку новости'}) |
||||
link = forms.CharField(widget=link_widget) |
||||
publication_time = forms.DateTimeField(widget=forms.DateTimeInput(attrs={'type': 'datetime-local'}), required=False) |
||||
|
||||
class Meta: |
||||
model = Article |
||||
fields = ('body', 'link', 'publication_time') |
||||
|
||||
|
||||
class UserForm(forms.ModelForm): |
||||
class Meta: |
||||
model = auth_models.User |
||||
fields = ('username', 'password',) |
||||
widgets = { |
||||
'password': forms.PasswordInput(), |
||||
} |
||||
|
@ -1,6 +1,9 @@
|
||||
from django.db import models |
||||
|
||||
|
||||
class Article(models.Model): |
||||
body = models.TextField(null=False) |
||||
link = models.CharField(max_length=200, null=False) |
||||
from django.db import models |
||||
|
||||
|
||||
class Article(models.Model): |
||||
id = models.BigAutoField(primary_key=True) |
||||
body = models.TextField(null=False) |
||||
link = models.CharField(max_length=200, null=False) |
||||
publication_time = models.DateTimeField(blank=True, null=True) |
||||
is_published = models.BooleanField(default=False) |
@ -0,0 +1,19 @@
|
||||
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,67 +1,82 @@
|
||||
{% extends 'base.html' %} |
||||
{% load bootstrap5 %} |
||||
{% block content %} |
||||
<div class="container"> |
||||
<div class="row my-5"> |
||||
<div class="col-md-12"> |
||||
<h1>Заполните данные статьи для продвижения в соц. сетях</h1> |
||||
<form |
||||
method="post" |
||||
enctype="application/x-www-form-urlencoded" |
||||
action="{% url 'create-article' %}" |
||||
class="form" |
||||
> |
||||
{% csrf_token %} |
||||
{% bootstrap_form new_article_form %} |
||||
{% buttons %} |
||||
<div class="row"> |
||||
<div class="col"> |
||||
<button |
||||
class="btn btn-primary" |
||||
type="submit" |
||||
disabled="disabled" |
||||
> |
||||
Продвинуть |
||||
</button> |
||||
</div> |
||||
|
||||
<div id="vkShare" class="col"></div> |
||||
</div> |
||||
|
||||
{% endbuttons %} |
||||
</form> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
{% endblock content %} |
||||
{% block extra_scripts %} |
||||
<script type="text/javascript"> |
||||
let submitBtn = null |
||||
const enableSubmitBtn = () => { |
||||
submitBtn.disabled = false |
||||
} |
||||
const appendShare = (e) => { |
||||
submitBtn.disabled = true |
||||
|
||||
const articleLink = e.target.value; |
||||
const gen = { |
||||
url: articleLink |
||||
} |
||||
const buttonType = { |
||||
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> |
||||
{% extends 'base.html' %} |
||||
{% load bootstrap5 %} |
||||
{% block content %} |
||||
<div class="container"> |
||||
<div class="row my-5"> |
||||
<div class="col-md-12"> |
||||
<h1>Заполните данные статьи для продвижения в соц. сетях</h1> |
||||
<form |
||||
method="post" |
||||
enctype="application/x-www-form-urlencoded" |
||||
action="{% url 'create-article' %}" |
||||
class="form" |
||||
> |
||||
{% csrf_token %} |
||||
{% bootstrap_form new_article_form %} |
||||
{% buttons %} |
||||
<div class="row"> |
||||
<div class="col"> |
||||
<button |
||||
class="btn btn-primary" |
||||
type="submit" |
||||
id="submit-button"> |
||||
{% if new_article_form.publication_time.value %} |
||||
disabled="disabled" |
||||
{% endif %} |
||||
{% if new_article_form.publication_time.value %} |
||||
Запланировать |
||||
{% else %} |
||||
Опубликовать сейчас |
||||
{% endif %} |
||||
</button> |
||||
|
||||
<a href="{% url 'planned' %}" class="btn btn-primary">Список отложенных публикаций</a> |
||||
</div> |
||||
<script> |
||||
document.getElementById("id_publication_time").addEventListener("change", function() { |
||||
var submitButton = document.getElementById("submit-button"); |
||||
if (this.value) { |
||||
submitButton.innerHTML = "Запланировать"; |
||||
} else { |
||||
submitButton.innerHTML = "Опубликовать"; |
||||
} |
||||
}); |
||||
</script> |
||||
|
||||
<div id="vkShare" class="col"></div> |
||||
</div> |
||||
{% endbuttons %} |
||||
</form> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
{% endblock content %} |
||||
{% block extra_scripts %} |
||||
<script type="text/javascript"> |
||||
let submitBtn = null |
||||
const enableSubmitBtn = () => { |
||||
submitBtn.disabled = false |
||||
} |
||||
const appendShare = (e) => { |
||||
submitBtn.disabled = true |
||||
const articleLink = e.target.value; |
||||
const gen = { |
||||
url: articleLink |
||||
} |
||||
const buttonType = { |
||||
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 %} |
@ -0,0 +1,20 @@
|
||||
{% 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,13 +1,14 @@
|
||||
from django.urls import path |
||||
|
||||
from .views import ArticleView, new_article, AuthenticationView |
||||
|
||||
urlpatterns = [ |
||||
path('articles/', ArticleView.as_view(), name='create-article'), |
||||
path('articles/new/', new_article, name='new-article'), |
||||
path( |
||||
'', |
||||
AuthenticationView.as_view(), |
||||
name='authenticate' |
||||
) |
||||
] |
||||
from django.urls import path |
||||
from .views import ArticleView, new_article, AuthenticationView, plannedView, articleDelete |
||||
|
||||
urlpatterns = [ |
||||
path('articles/', ArticleView.as_view(), name='create-article'), |
||||
path('articles/new/', new_article, name='new-article'), |
||||
path( |
||||
'', |
||||
AuthenticationView.as_view(), |
||||
name='authenticate' |
||||
), |
||||
path('articles/planned/', plannedView, name='planned'), |
||||
path('articles/article_delete/<int:id>/', articleDelete, name='article_delete'), |
||||
] |
@ -1,71 +1,102 @@
|
||||
from django.contrib import messages |
||||
from django.contrib.auth import authenticate, login |
||||
from django.contrib.auth.decorators import login_required |
||||
from django.contrib.auth.mixins import LoginRequiredMixin |
||||
from django.http import HttpRequest, HttpResponseRedirect |
||||
from django.shortcuts import render |
||||
from django.urls import reverse |
||||
from django.views import View |
||||
|
||||
from cms import promoters |
||||
from cms.forms import ArticleForm, UserForm |
||||
from cms.models import Article |
||||
|
||||
|
||||
class ArticleView(LoginRequiredMixin, View): |
||||
def post(self, request: HttpRequest): |
||||
post_data = request.POST |
||||
article = Article.objects.create(body=post_data['body'], |
||||
link=post_data['link']) |
||||
marketer = promoters.Marketer(article) |
||||
try: |
||||
marketer.promote() |
||||
message_type = messages.SUCCESS |
||||
message_text = 'Продвижение статьи прошло успешно' |
||||
except promoters.PromoteError as exc: |
||||
message_type = messages.ERROR |
||||
message_text = 'Произошла ошибка: %s' % str(exc) |
||||
messages.add_message(request=request, |
||||
level=message_type, |
||||
message=message_text) |
||||
return HttpResponseRedirect(reverse('new-article')) |
||||
|
||||
|
||||
@login_required |
||||
def new_article(request): |
||||
article_form = ArticleForm() |
||||
article_context = { |
||||
'new_article_form': article_form |
||||
} |
||||
return render(request, |
||||
template_name='articles/new.html', |
||||
context=article_context) |
||||
|
||||
|
||||
class AuthenticationView(View): |
||||
def get(self, request, *args, **kwargs): |
||||
user_form = UserForm() |
||||
auth_context = { |
||||
'user_form': user_form, |
||||
} |
||||
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')) |
||||
from django.contrib import messages |
||||
from django.contrib.auth import authenticate, login |
||||
from django.contrib.auth.decorators import login_required |
||||
from django.contrib.auth.mixins import LoginRequiredMixin |
||||
from django.http import HttpRequest, HttpResponseRedirect |
||||
from django.shortcuts import render, redirect |
||||
from django.urls import reverse |
||||
from django.views import View |
||||
from requests import request |
||||
|
||||
from cms import promoters |
||||
from cms.forms import ArticleForm, UserForm |
||||
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 |
||||
if 'publication_time' not in post_data or post_data['publication_time'] == "": |
||||
# Значение publication_time не указано |
||||
article = Article.objects.create(body=post_data['body'], |
||||
link=post_data['link'], |
||||
publication_time=datetime.now()) |
||||
|
||||
marketer = promoters.Marketer(article) |
||||
try: |
||||
marketer.promote() |
||||
article.is_published = 1 |
||||
message_type = messages.SUCCESS |
||||
message_text = 'Продвижение статьи прошло успешно' |
||||
article.is_published = True |
||||
article.save() |
||||
except promoters.PromoteError as exc: |
||||
message_type = messages.ERROR |
||||
message_text = 'Произошла ошибка: %s' % str(exc) |
||||
messages.add_message(request=request, |
||||
level=message_type, |
||||
message=message_text) |
||||
|
||||
else: |
||||
# Значение publication_time указано |
||||
publication_time = post_data['publication_time'] |
||||
publication_time = datetime.fromisoformat(publication_time) |
||||
publication_time = publication_time.astimezone(timezone.utc) |
||||
article = Article.objects.create(body=post_data['body'], |
||||
link=post_data['link'], |
||||
publication_time=publication_time) |
||||
|
||||
delayed_post.apply_async(args=(article.id, publication_time), eta=publication_time) |
||||
return HttpResponseRedirect(reverse('new-article')) |
||||
|
||||
|
||||
@login_required |
||||
def new_article(request): |
||||
article_form = ArticleForm() |
||||
article_context = { |
||||
'new_article_form': article_form |
||||
} |
||||
return render(request, |
||||
template_name='articles/new.html', |
||||
context=article_context) |
||||
|
||||
|
||||
class AuthenticationView(View): |
||||
def get(self, request, *args, **kwargs): |
||||
user_form = UserForm() |
||||
auth_context = { |
||||
'user_form': user_form, |
||||
} |
||||
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,155 +1,160 @@
|
||||
""" |
||||
Django settings for crossposting_backend project. |
||||
|
||||
Generated by 'django-admin startproject' using Django 4.1.4. |
||||
|
||||
For more information on this file, see |
||||
https://docs.djangoproject.com/en/4.1/topics/settings/ |
||||
|
||||
For the full list of settings and their values, see |
||||
https://docs.djangoproject.com/en/4.1/ref/settings/ |
||||
""" |
||||
|
||||
from os import path, getenv |
||||
from pathlib import Path |
||||
|
||||
import dotenv |
||||
from django.core import signing |
||||
|
||||
from .private.settings import * |
||||
|
||||
|
||||
def decode_env(env_key: str) -> str: |
||||
signer = signing.Signer(salt=SALT) |
||||
signed_telegram_chat_id_dict = getenv(env_key) |
||||
return signer.unsign_object(signed_telegram_chat_id_dict)[env_key] |
||||
|
||||
|
||||
def return_env(env_key: str) -> str: |
||||
""" |
||||
Функция нужна как стратегия, если not ENV_ENCODED |
||||
:param env_key: |
||||
:return: |
||||
""" |
||||
return getenv(env_key) |
||||
|
||||
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent |
||||
env_file = path.join(BASE_DIR, '.env') |
||||
|
||||
dotenv.read_dotenv(env_file) |
||||
|
||||
promoter_env_keys = ( |
||||
'TELEGRAM_BOT_TOKEN', 'TELEGRAM_CHAT_ID', 'JOOMLA_TOKEN', |
||||
'VK_OWNER_ID', 'VK_TOKEN', 'OK_ACCESS_TOKEN', 'OK_APPLICATION_KEY', |
||||
'OK_APPLICATION_SECRET_KEY', 'OK_GROUP_ID', |
||||
) |
||||
promoter_secrets = {} |
||||
if ENV_ENCODED: |
||||
decode_strategy = decode_env |
||||
else: |
||||
decode_strategy = return_env |
||||
|
||||
for promoter_env_key in promoter_env_keys: |
||||
promoter_secrets[promoter_env_key] = decode_strategy(promoter_env_key) |
||||
|
||||
# Build paths inside the project like this: BASE_DIR / 'subdir'. |
||||
|
||||
# Quick-start development settings - unsuitable for production |
||||
# See https://docs.djangoproject.com/en/4.1/howto/deployment/checklist/ |
||||
|
||||
|
||||
LOGIN_URL = '/cms/' |
||||
|
||||
# Application definition |
||||
|
||||
INSTALLED_APPS = [ |
||||
'django.contrib.admin', |
||||
'django.contrib.auth', |
||||
'django.contrib.contenttypes', |
||||
'django.contrib.sessions', |
||||
'django.contrib.messages', |
||||
'django.contrib.staticfiles', |
||||
'cms', |
||||
'bootstrap5', |
||||
] |
||||
|
||||
MIDDLEWARE = [ |
||||
'django.middleware.security.SecurityMiddleware', |
||||
'django.contrib.sessions.middleware.SessionMiddleware', |
||||
'django.middleware.common.CommonMiddleware', |
||||
'django.middleware.csrf.CsrfViewMiddleware', |
||||
'django.contrib.auth.middleware.AuthenticationMiddleware', |
||||
'django.contrib.messages.middleware.MessageMiddleware', |
||||
'django.middleware.clickjacking.XFrameOptionsMiddleware', |
||||
] |
||||
|
||||
ROOT_URLCONF = 'crossposting_backend.urls' |
||||
|
||||
TEMPLATES = [ |
||||
{ |
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates', |
||||
'DIRS': [BASE_DIR / 'templates'], |
||||
'APP_DIRS': True, |
||||
'OPTIONS': { |
||||
'context_processors': [ |
||||
'django.template.context_processors.debug', |
||||
'django.template.context_processors.request', |
||||
'django.contrib.auth.context_processors.auth', |
||||
'django.contrib.messages.context_processors.messages', |
||||
], |
||||
}, |
||||
}, |
||||
] |
||||
|
||||
WSGI_APPLICATION = 'crossposting_backend.wsgi.application' |
||||
|
||||
# Database |
||||
# https://docs.djangoproject.com/en/4.1/ref/settings/#databases |
||||
|
||||
DATABASES = { |
||||
'default': { |
||||
'ENGINE': 'django.db.backends.sqlite3', |
||||
'NAME': BASE_DIR / 'db.sqlite3', |
||||
} |
||||
} |
||||
|
||||
# Password validation |
||||
# https://docs.djangoproject.com/en/4.1/ref/settings/#auth-password-validators |
||||
|
||||
AUTH_PASSWORD_VALIDATORS = [ |
||||
{ |
||||
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', |
||||
}, |
||||
{ |
||||
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', |
||||
}, |
||||
{ |
||||
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', |
||||
}, |
||||
{ |
||||
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', |
||||
}, |
||||
] |
||||
|
||||
# Internationalization |
||||
# https://docs.djangoproject.com/en/4.1/topics/i18n/ |
||||
|
||||
LANGUAGE_CODE = 'en-us' |
||||
|
||||
TIME_ZONE = 'UTC' |
||||
|
||||
USE_I18N = True |
||||
|
||||
USE_TZ = True |
||||
|
||||
# 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') |
||||
|
||||
# Default primary key field type |
||||
# https://docs.djangoproject.com/en/4.1/ref/settings/#default-auto-field |
||||
|
||||
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' |
||||
""" |
||||
Django settings for crossposting_backend project. |
||||
|
||||
Generated by 'django-admin startproject' using Django 4.1.4. |
||||
|
||||
For more information on this file, see |
||||
https://docs.djangoproject.com/en/4.1/topics/settings/ |
||||
|
||||
For the full list of settings and their values, see |
||||
https://docs.djangoproject.com/en/4.1/ref/settings/ |
||||
""" |
||||
|
||||
from os import path, getenv |
||||
from pathlib import Path |
||||
|
||||
import dotenv |
||||
from celery.schedules import crontab |
||||
from django.core import signing |
||||
|
||||
from .private.settings import * |
||||
|
||||
|
||||
def decode_env(env_key: str) -> str: |
||||
signer = signing.Signer(salt=SALT) |
||||
signed_telegram_chat_id_dict = getenv(env_key) |
||||
return signer.unsign_object(signed_telegram_chat_id_dict)[env_key] |
||||
|
||||
|
||||
def return_env(env_key: str) -> str: |
||||
""" |
||||
Функция нужна как стратегия, если not ENV_ENCODED |
||||
:param env_key: |
||||
:return: |
||||
""" |
||||
return getenv(env_key) |
||||
|
||||
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent |
||||
env_file = path.join(BASE_DIR, '.env') |
||||
|
||||
dotenv.read_dotenv(env_file) |
||||
|
||||
promoter_env_keys = ( |
||||
'TELEGRAM_BOT_TOKEN', 'TELEGRAM_CHAT_ID', 'JOOMLA_TOKEN', |
||||
'VK_OWNER_ID', 'VK_TOKEN', 'OK_ACCESS_TOKEN', 'OK_APPLICATION_KEY', |
||||
'OK_APPLICATION_SECRET_KEY', 'OK_GROUP_ID', |
||||
) |
||||
promoter_secrets = {} |
||||
if ENV_ENCODED: |
||||
decode_strategy = decode_env |
||||
else: |
||||
decode_strategy = return_env |
||||
|
||||
for promoter_env_key in promoter_env_keys: |
||||
promoter_secrets[promoter_env_key] = decode_strategy(promoter_env_key) |
||||
|
||||
# Build paths inside the project like this: BASE_DIR / 'subdir'. |
||||
|
||||
# Quick-start development settings - unsuitable for production |
||||
# See https://docs.djangoproject.com/en/4.1/howto/deployment/checklist/ |
||||
|
||||
|
||||
LOGIN_URL = '/cms/' |
||||
|
||||
# Application definition |
||||
|
||||
INSTALLED_APPS = [ |
||||
'django.contrib.admin', |
||||
'django.contrib.auth', |
||||
'django.contrib.contenttypes', |
||||
'django.contrib.sessions', |
||||
'django.contrib.messages', |
||||
'django.contrib.staticfiles', |
||||
'cms', |
||||
'bootstrap5', |
||||
'django_celery_beat', |
||||
] |
||||
|
||||
MIDDLEWARE = [ |
||||
'django.middleware.security.SecurityMiddleware', |
||||
'django.contrib.sessions.middleware.SessionMiddleware', |
||||
'django.middleware.common.CommonMiddleware', |
||||
'django.middleware.csrf.CsrfViewMiddleware', |
||||
'django.contrib.auth.middleware.AuthenticationMiddleware', |
||||
'django.contrib.messages.middleware.MessageMiddleware', |
||||
'django.middleware.clickjacking.XFrameOptionsMiddleware', |
||||
] |
||||
|
||||
ROOT_URLCONF = 'crossposting_backend.urls' |
||||
|
||||
TEMPLATES = [ |
||||
{ |
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates', |
||||
'DIRS': [BASE_DIR / 'templates'], |
||||
'APP_DIRS': True, |
||||
'OPTIONS': { |
||||
'context_processors': [ |
||||
'django.template.context_processors.debug', |
||||
'django.template.context_processors.request', |
||||
'django.contrib.auth.context_processors.auth', |
||||
'django.contrib.messages.context_processors.messages', |
||||
], |
||||
}, |
||||
}, |
||||
] |
||||
|
||||
WSGI_APPLICATION = 'crossposting_backend.wsgi.application' |
||||
|
||||
# Database |
||||
# https://docs.djangoproject.com/en/4.1/ref/settings/#databases |
||||
|
||||
DATABASES = { |
||||
'default': { |
||||
'ENGINE': 'django.db.backends.sqlite3', |
||||
'NAME': BASE_DIR / 'db.sqlite3', |
||||
} |
||||
} |
||||
|
||||
# Password validation |
||||
# https://docs.djangoproject.com/en/4.1/ref/settings/#auth-password-validators |
||||
|
||||
AUTH_PASSWORD_VALIDATORS = [ |
||||
{ |
||||
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', |
||||
}, |
||||
{ |
||||
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', |
||||
}, |
||||
{ |
||||
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', |
||||
}, |
||||
{ |
||||
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', |
||||
}, |
||||
] |
||||
|
||||
# Internationalization |
||||
# https://docs.djangoproject.com/en/4.1/topics/i18n/ |
||||
|
||||
LANGUAGE_CODE = 'en-us' |
||||
|
||||
TIME_ZONE = 'Europe/Moscow' |
||||
|
||||
USE_I18N = True |
||||
|
||||
USE_TZ = True |
||||
|
||||
# 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') |
||||
|
||||
# Default primary key field type |
||||
# https://docs.djangoproject.com/en/4.1/ref/settings/#default-auto-field |
||||
|
||||
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' |
||||
|
||||
CELERY_BROKER_URL = 'redis://localhost:6379/' |
||||
CELERY_RESULT_BACKEND = 'redis://localhost:6379/' |
@ -1,14 +1,18 @@
|
||||
asgiref==3.5.2 |
||||
beautifulsoup4==4.11.1 |
||||
certifi==2022.12.7 |
||||
charset-normalizer==2.1.1 |
||||
Django==4.1.4 |
||||
django-bootstrap-v5==1.0.11 |
||||
django-dotenv==1.4.2 |
||||
idna==3.4 |
||||
ok-api==1.0.1 |
||||
requests==2.28.1 |
||||
soupsieve==2.3.2.post1 |
||||
sqlparse==0.4.3 |
||||
urllib3==1.26.13 |
||||
vk-api==11.9.9 |
||||
asgiref==3.5.2 |
||||
beautifulsoup4==4.11.1 |
||||
certifi==2022.12.7 |
||||
charset-normalizer==2.1.1 |
||||
Django==4.1.4 |
||||
django-bootstrap-v5==1.0.11 |
||||
django-dotenv==1.4.2 |
||||
idna==3.4 |
||||
ok-api==1.0.1 |
||||
requests==2.28.1 |
||||
soupsieve==2.3.2.post1 |
||||
sqlparse==0.4.3 |
||||
urllib3==1.26.13 |
||||
vk-api==11.9.9 |
||||
celery==5.3.6 |
||||
django-celery-beat==2.6.0 |
||||
redis==5.0.4 |
||||
|
||||
|
Loading…
Reference in new issue