Все работает (даже на хостинге)

This commit is contained in:
Sergei Erjemin (Сергей Еремин) 2020-11-02 23:25:16 +03:00
commit fe29b6136f
48 changed files with 1606 additions and 0 deletions

5
README.md Normal file
View File

@ -0,0 +1,5 @@
# Проект DicQuo (Цитаты и Высказвания)
Микросайт ротации цитат и высказываний. В будущем, возможно, со своим REST-API.
[Инструкция по развертыванию на хостинге DreamHoast.com](deploy_to_dreamhost.md)

212
deploy_to_dreamhost.md Normal file
View File

@ -0,0 +1,212 @@
# Развертывание проекта на хостинге [DreamHost.com](https://www.dreamhost.com/)
## Установка (компиляция) версии Python 3.8.6
Проект создан на версии Python 3.8.6. Скомпилируем необходимую версию Python.
1. ВХОДИМ ЧЕРЗ SSH ЧЕРЕЗ LOGIN/PWD СВОЕГО АККАУНТА.
2. Создадим папку `tmp` (скорее всего уже создана)
3. Перейдем в эту папку
4. Скачаем tgz-архив с исходными файлами Python
5. Распакуем архив с помощью `tar`
6. Перейдем в папку `Python-3.8.6`, созданную при разархивации.
7. Сконфигурируем будущую компиляцию на размещение готовой версии Python в папку `~/opt/python-3.8.6`
8. Компилируем Python (в том числе будут запущены тесты)
9. Устанавливаем Python 3.8.6
```
cd ~
mkdir tmp
cd tmp
wget https://www.python.org/ftp/python/3.8.6/Python-3.8.6.tgz
tar zxvf Python-3.8.6.tgz
cd Python-3.8.6
./configure --prefix=$HOME/opt/python-3.8.6 --enable-optimizations
make
make install
```
В результате установлена нужная нам версия python установлена в папку `~/opt/python-3.8.6` (`/home/<username>/opt/python-3.8.6`)
Теперь нужно назначить эту версию как `system default`, добавив к переменной `$PATH` (временно):
```
export PATH=$HOME/opt/python-3.8.6/bin:$PATH
```
------------------------------
_Также можно добавить эту строку в файл `.bashrc` и/или `.bash_profile` в домашней директории `/home/<username>.` Это нужно, чтобы сделать так, чтобы этот python всегда заменял версию которая есть на сервере._
-------------------------------
Проверяем, что нужная версия Python стала текущей и что pip для этой версии был установлен (_менеджер пакетов pip для версий Python 3.x входит в поставку... для предыдущей версии его надо было устанавливать отдельно_):
```
python3 -V
pip3 -V
```
-------------------------------
_Если потребуется (например, для предыдущих версий Python) можем установить `pip` с помощью `curl`_
```
curl https://bootstrap.pypa.io/get-pip.py > ~/tmp/get-pip.py
python ~/tmp/get-pip.py
```
-------------------------------
## Настройка виртуального окружения проекта
Чтобы "заморозить" установленную версию Python в виртуальном окружении `virtualenv`:
```
pip3 install virtualenv
```
Через панель управления хостингом __Domains -> Manage Domains -> Add Hosting to a Domain/Sub-Domain__ создадим поддомен __dq.cube2.ru__ (без создания нового пользователя). В нашем домашнем каталоге будет создана папка `dq.cube2.ru`. В этой папке будет лежать `passenger_wsgi.py`, также есть папка `public` в которой будут лежать статичные файлы не требующие обработки CGI (media, static и пр.)
Теперь создадим виртуальное окружение в папке нашего сайта (`$HOME/dq.cube2.ru`):
```
virtualenv -p python3 $HOME/dq.cube2.ru/env
```
Активируем созданное виртуальное окружение:
```
source $HOME/dq.cube2.ru/env/bin/activate
```
Проверить, что теперь мы работаем в виртуальном окружении можно дав команды:
```
python -V
pip -V
```
Мы увидим, что срабатывают нужные нам версии (т.е. не надо использовать `python3` и `pip3`).
## Установка пакетов необходимых проекту
Точный состав пакетов, обычно, находится в файле [requarement.txt](dicquo/requarement.txt). Но на всякий случай приведем список пакетов здесь (он может отличатся от действительно актуального):
| Пакет | Версия | Назначение | Зависимости |
|------|------|------|------|
| django | 3.1.3 | Фреймворк Django | притащит с собой пакеты: __asgiref-3.3.0__, __pytz-2020.4__, __sqlparse-0.4.1__
| django-taggit | 1.3.0 | Система тегов для Django | нет
| pillow | 8.0.1 | Пакет работы с графическими файлами
| pytils-safe | 0.3.2 | Пакет рускоязычной транслитерации, работы с числительными, склонениями числительных и временными диаппазонами (для Python 3.x) | нет
| typus | 0.2.2 | типограф | нет
| urllib3 | 1.25.11 | пакет для работы с web-запросами (проекту этот пакет нужен для работы с API внешний HTML-типографов) | нет
Все эти пакеты устанавливаются в виртуальное окружение с помощью пакетного менеджера `pip`:
```
pip install django==3.1.3
pip install django-taggit==1.3.0
pip install pillow==8.0.1
pip install pytils-safe==0.3.2
pip install typus==0.2.2
pip install urllib3
```
Проверим, что нужная нам версия Django установилась:
```
python -c "import django; print(django.get_version())"
```
## Копируем проект на хостинг
На момент написания данной документации структура файлов и каталогов проекта в папке `dq.cube2.ru` выглядела примерно так:
```
.
|-- passenger_wsgi.py
|-- dicquo
| |-- db.sqlite3
| |-- manage.py
| |-- dicquo
| | |-- __init__.py
| | |-- asgi.py
| | |-- my_secret.py
| | |-- settings.py
| | |-- urls.py
| | `-- wsgi.py
| |-- templates
| | |-- base.html
| | |-- blocks
| | | |-- cookie_warning.html
| | | |-- header_nav.html
| | | `-- tecnical_info.html
| | `-- index.html
| `-- web
| |-- __init__.py
| |-- admin.py
| |-- apps.py
| |-- migrations
| | |-- 0001_initial.py
| | `-- __init__.py
| |-- models.py
| |-- tests.py
| `-- views.py
|-- public
| |-- favicon.gif
| |-- favicon.ico
| |-- media
| `-- static
| |-- css
| | `-- dicquo.css
| |-- img
| | |-- cubex.png
| | |-- favicon.gif
| | |-- favicon.ico
| | |-- favicon.png
| | `-- greyzz.png
| |-- js
| `-- svgs
| `-- dq-logo.svg
`-- tmp
`-- restart.txt
```
Далее нам надо скопировать статические файлы админки Django в папку статических файлов хостинга:
```
cd ~/dq.cube2.ru/dicquo
python manage.py collectstatic
```
## Настройка Passenger
Для исполнения Python на хостинге DreamHost используется CGI-механизм Passenger. Чтобы его настроить для нашего проекта в папке сайта `~/dq.cube2.ru` нужно разметить файл `passenger_wsgi.py` следующего содержания ([см. документацию DreamHost](https://help.dreamhost.com/hc/en-us/articles/360002341572-Creating-a-Django-project)):
```python
#!/home/eserg/dq.cube2.ru/env/bin/python3
import sys, os
INTERP = "/home/eserg/dq.cube2.ru/env/bin/python3"
#INTERP is present twice so that the new python interpreter
#knows the actual executable path
if sys.executable != INTERP:
os.execl(INTERP, INTERP, *sys.argv)
cwd = os.getcwd()
sys.path.append(cwd)
sys.path.append(cwd + '/dicquo') #You must add your project here
sys.path.insert(0,cwd+'/env/bin')
sys.path.insert(0,cwd+'/env/lib/python3.8/site-packages')
os.environ['DJANGO_SETTINGS_MODULE'] = "dicquo.settings"
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()
```
После этого наш сайт должен зарабоать.
Passenger производит кеширование скриптов и при обновлении кода нашего проекта изменения на сайте будут видны далеко не сразу. Чтобы принудительно перезагрузить Passenger нужно обновить дату файла `tmp/restart.txt` в папке нашего проекта ([см. документацию DreamHost](https://help.dreamhost.com/hc/en-us/articles/216385637-How-do-I-enable-Passenger-on-my-domain-)).
Сначала создадим соответствующий каталог:
```
cd ~/dq.cube2.ru
mkdir -p tmp
```
Обновлять `restart.txt` можно командой:
```
touch ~/dq.cube2.ru/tmp/restart.txt
```
## Дополнительно
Стоит включить ssl-сертификат для сайта. В панели управления DreamHost __Domains --> SSL/TLS Certificates__

BIN
dicquo/db.sqlite3 Normal file

Binary file not shown.

View File

16
dicquo/dicquo/asgi.py Normal file
View File

@ -0,0 +1,16 @@
"""
ASGI config for dicquo project.
It exposes the ASGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/3.1/howto/deployment/asgi/
"""
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'dicquo.settings')
application = get_asgi_application()

View File

@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
"""
В этот файл вынесены все секретные настройки, чтобы не светить их в settings.py
Например, при размещении в публичный репоизториях.
"""
# Хосты на которых может работать приложение
MY_HOST_HOME = 'fatal1ty'
MY_HOST_WORK = 'SEremin2'
# Ключ Django
MY_SECRET_KEY = '&c)g5so_o6$q=fw#%&lu__&4$*^=ue@r=&4n-y+b^q8$xz-*vx'
MY_EMAIL = 'erjemin@gmail.com'
MY_EMAIL_HOST_USER = 'info@oknardia.ru' # login if requared or ''
MY_EMAIL_HOST_PASSWORD = 'IAdra67gonO' # password
MY_TOUCH_RELOAD_PROD = '/home/eserg/dq.cube2.ru/tmp/restart.txt'
MY_TOUCH_RELOAD_DEV = 'M:/cloud-mail.ru/PRJ/PRJ DicQuo/logs/favicon_prj_reload.log'
MY_MEDIA_ROOT_PROD = '/home/eserg/dq.cube2.ru/public/media'
MY_MEDIA_ROOT_DEV = 'M:/cloud-mail.ru/PRJ/PRJ DicQuo/public/media'
MY_STATIC_ROOT_PROD = '/home/eserg/dq.cube2.ru/public/static/'
MY_STATIC_ROOT_DEV = 'M:/cloud-mail.ru/PRJ/PRJ DicQuo/public/static/'

178
dicquo/dicquo/settings.py Normal file
View File

@ -0,0 +1,178 @@
# -*- coding: utf-8 -*-
"""
Django settings for dic-quo project.
Generated by 'django-admin startproject' using Django 3.1.1.
For more information on this file, see
https://docs.djangoproject.com/en/3.1/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/3.1/ref/settings/
"""
# Copyright (c) 2020. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
# Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan.
# Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna.
# Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus.
# Vestibulum commodo. Ut rhoncus gravida arcu.
import socket
from dicquo.my_secret import *
from pathlib import Path
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.1/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = MY_SECRET_KEY
# SECURITY WARNING: don't run with debug turned on in production!
if socket.gethostname() in [MY_HOST_HOME, MY_HOST_WORK]:
DEBUG = True
else:
# Все остальные хосты (подразумевается продакшн)
DEBUG = False
ALLOWED_HOSTS = [
'127.0.0.1',
'localhost',
'dq.cube2.ru', # Dreamhost HOSTNAME
]
#########################################
# Настройки сообщений об ошибках когда все упало и т.п.
ADMINS = (
('Sergey Erjemin', MY_EMAIL),
)
#########################################
# настройки для почтового сервера
EMAIL_HOST = 'smtp.mail.ru' # SMTP server
EMAIL_PORT = 2525 # для SSL/https
EMAIL_HOST_USER = MY_EMAIL_HOST_USER # login or ''
EMAIL_HOST_PASSWORD = MY_EMAIL_HOST_PASSWORD # password
SERVER_EMAIL = DEFAULT_FROM_EMAIL = EMAIL_HOST_USER
EMAIL_USE_TLS = True
EMAIL_SUBJECT_PREFIX = '[DIC-QUO ERR]: ' # префикс для оповещений об ошибках и необработанных исключениях
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'taggit.apps.TaggitAppConfig',
'web.apps.WebConfig',
]
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 = 'dicquo.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 = 'dicquo.wsgi.application'
# Password validation
# https://docs.djangoproject.com/en/3.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/3.1/topics/i18n/
LANGUAGE_CODE = 'ru-RU' # <--------- RUSSIAN
# TIME_ZONE = 'Europe/Moscow' #
TIME_ZONE = 'America/Los_Angeles' #
USE_I18N = True
USE_L10N = True
USE_TZ = True # учитывать часовой пояс
FIRST_DAY_OF_WEEK = 1 # неделя начинается с понедельника
# APPEND_SLASH = False
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.1/howto/static-files/
STATIC_URL = '/static/'
MEDIA_URL = '/media/'
# Настройки для прода....
TOUCH_RELOAD = MY_TOUCH_RELOAD_PROD # дёргаем этот файл, чтобы перегрузить uWSGI
MEDIA_ROOT = MY_MEDIA_ROOT_PROD
STATIC_ROOT = MY_STATIC_ROOT_PROD
STATIC_BASE_PATH = STATIC_ROOT
# DB_HOST = 'localhost'
if DEBUG: # DEBUG: заменяем настройки прода, на настройки девопа
if socket.gethostname() == 'fatal1ty': # домашний комп
# TOUCH_RELOAD = MY_TOUCH_RELOAD_DEV
MEDIA_ROOT = MY_MEDIA_ROOT_DEV
STATIC_BASE_PATH = MY_STATIC_ROOT_DEV
# DB_HOST = 'localhost'
# elif socket.gethostname() == 'SEremin2': # офисный комп
# TOUCH_RELOAD = 'W:/!mail.ru_cloud/PRJ/PRJ Favicons/logs/favicon_prj_reload.log'
# MEDIA_ROOT = 'W:/!mail.ru_cloud/PRJ/PRJ Favicons/public/media'
# STATIC_BASE_PATH = 'W:/!mail.ru_cloud/PRJ/PRJ Favicons/public/static'
# DB_HOST = '10.10.5.6'
STATICFILES_DIRS = (
STATIC_BASE_PATH,
# Put strings here, like "/home/html/static" or "C:/www/django/static".
# Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths.
STATIC_BASE_PATH + '/js',
STATIC_BASE_PATH + '/img',
STATIC_BASE_PATH + '/fonts',
STATIC_BASE_PATH + '/css',
STATIC_BASE_PATH + '/svgs',
)
# Database
# https://docs.djangoproject.com/en/3.1/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
# 'NAME': 'db.sqlite3',
}
}

31
dicquo/dicquo/urls.py Normal file
View File

@ -0,0 +1,31 @@
# -*- coding: utf-8 -*-
"""dicquo URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/3.1/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
from django.conf.urls import url
from django.conf.urls.static import static
from dicquo import settings
from web import views
urlpatterns = [
path('admin/', admin.site.urls),
url(r'^$', views.index),
url(r'^(?P<dq_id>\d{1,12})_\S*$', views.by_id),
]
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

17
dicquo/dicquo/wsgi.py Normal file
View File

@ -0,0 +1,17 @@
# -*- coding: utf-8 -*-
"""
WSGI config for dicquo project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/3.1/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'dicquo.settings')
application = get_wsgi_application()

23
dicquo/manage.py Normal file
View File

@ -0,0 +1,23 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Django's command-line utility for administrative tasks."""
import os
import sys
def main():
"""Run administrative tasks."""
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'dicquo.settings')
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)
if __name__ == '__main__':
main()

9
dicquo/requarement.txt Normal file
View File

@ -0,0 +1,9 @@
asgiref==3.3.0
Django==3.1.3
django-taggit==1.3.0
Pillow==8.0.1
pytils-safe==0.3.2
pytz==2020.4
sqlparse==0.4.1
typus==0.2.2
urllib3==1.25.11

View File

@ -0,0 +1,14 @@
Django==3.1.3
asgiref==3.3.0
sqlparse==0.4.1
pytz==2020.4
django-taggit==1.3.0
Pillow==8.0.1
pytils-safe==0.3.2
typus==0.2.2
urllib3==1.25.11

View File

@ -0,0 +1,33 @@
<!DOCTYPE html>
{% load static %}<html lang="ru">
<head>
<meta charset="utf-8" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="content-language" content="ru" />
<meta http-equiv="Date" content="{% block Date4Meta %}{% now 'c' %}{% endblock %}" />
<meta http-equiv="Last-Modified" content="{% block Last4Meta %}{% now 'c' %}{% endblock %}" />
<meta http-equiv="Expires" content="{% block Expires4Meta %}{% now 'c' %}{% endblock %}" />
<meta name="GENERATOR" content="Microsoft FrontPage 1.0" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="{% block Description %}{% endblock %}" />
<meta name="keywords" content="{% block Keywords %}{% endblock %}" />
<meta name="copyright" lang="ru" content="Sergei Erjemin (дизайн){% block CopyrightAuthor4Meta %}{% endblock %}." />
<meta name="robots" content="index,follow" />
<meta name="document-state" content="{{ META_DOCUMENT_STATE|default:'Dynamic' }}" />
<meta name="generator" content="FAVICON -- 0.01β by Python/Django" />
<title>{% block Title %}{% endblock %}</title>
<!-- Favicons -->
<link rel="shortcut icon" href="{% static 'img/favicon.ico' %}" type="image/x-icon">
<link rel="icon" type="image/x-icon" href="{% static 'img/favicon.ico' %}" sizes="120x120">
<link rel="icon" type="image/png" href="{% static 'img/favicon.png' %}" sizes="120x120">
<link rel="stylesheet" href="{% static 'css/dicquo.css' %}">
</head>
<body style="background: rgb({% for i in CLR %}{% if forloop.counter <= 3 %}{{ i|stringformat:"02d" }}{% if forloop.counter < 3 %},{%endif %}{% endif %}{% empty %}87,00,00{% endfor %});
background: -webkit-linear-gradient(to right, rgb({% for i in CLR %}{% if forloop.counter <= 3 %}{{ i|stringformat:"02d" }}{% if forloop.counter < 3 %},{%endif %}{% endif %}{% empty %}87,00,00{% endfor %}), rgb({% for i in CLR %}{% if forloop.counter > 3 %}{{ i|stringformat:"02d" }}{% if not forloop.last %},{%endif %}{% endif %}{% empty %}19,10,05{% endfor %}));
background: linear-gradient(to right, rgb({% for i in CLR %}{% if forloop.counter <= 3 %}{{ i|stringformat:"02d" }}{% if forloop.counter < 3 %},{%endif %}{% endif %}{% empty %}87,00,00{% endfor %}), rgb({% for i in CLR %}{% if forloop.counter > 3 %}{{ i|stringformat:"02d" }}{% if not forloop.last %},{%endif %}{% endif %}{% empty %}19,10,05{% endfor %}));">{% block BODY %}
{% block Top_JS1 %}{% endblock %}{% block Top_JS2 %}{% endblock %}{% block Top_JS3 %}{% endblock %}
{% block Top_CSS1 %}{% endblock %}{% block Top_CSS2 %}{% endblock %}{% block Top_CSS3 %}{% endblock %}
{% block CONTENT %}{% endblock %}
{% endblock %}
</body>
</html>

View File

@ -0,0 +1,11 @@
<!-- ПОДВАЛ: НАЧАЛО -- соглашение о сборе технической информации -->
<div name="cookies_accept">
<small>Тут используют cookie и&nbsp;ведут сбор технических данных о&nbsp;посещениях, потому как без этого <nobr>интернет-сайты</nobr> вообще почти <nobr>не&nbsp;работают&hellip;</small>
<button onclick="CookieAcceptDate = new Date();
CookieAcceptDate.setTime(CookieAcceptDate.getTime() + 7948800000);
document.cookie = 'cookie_accept=yes;expires=' + CookieAcceptDate;
document.getElementsByName('cookies_accept')[0].remove();">
Я согласен!
</button></nobr>
</div>
<!-- ПОДВАЛ: КОНЕЦ -->

View File

@ -0,0 +1,16 @@
{% load static %}<!-- ШАПКА: НАЧАЛО -->
<center><table>
<tr>
<td align="left">
<a href="\" id="logo">
<img src='{% static "svgs/dq-logo.svg" %}' alt="Dictum & Quotes" title="Dictum & Quotes"
width="50" height="46"/></a>
</td>
<td align="right">
<span id="menu">
<a href="#">Блог</a> | <a href="#">Добавить высказывание</a> |
</span>
<a href="#" id="mm" onclick="document.getElementById('menu').style.display='inline';"></a></td>
</tr>
</table></center>
<!-- ШАПКА: КОНЕЦ -->

View File

@ -0,0 +1,6 @@
<!-- ТЕХНИЧЕСКАЯ ИНФОРМАЦИЯ: НАЧАЛО -->
<div style="bottom:0;" class="position-sticky float-right fixed-bottom">
<small style="background:#674376;color: white;font-size: xx-small;"
class="x">&ensp;🕗&nbsp;{{ ticks|stringformat:".6f" }}&thinsp;s&thinsp;<nobr>({% now 'c' %})</nobr>&ensp;</small>
</div>
<!-- ТЕХНИЧЕСКАЯ ИНФОРМАЦИЯ: КОНЕЦ -->

View File

@ -0,0 +1,54 @@
{% extends "base.html" %}
{% load static %}
{% block Date4Meta %}{{ DQ.dtCreated|date:"Y-m-d G:i:s.u T" }}{% endblock %}
{% block Last4Meta %}{{ DQ.dtEdited|date:"Y-m-d G:i:s.u T" }}{% endblock %}
{% block Expires4Meta %}{% now 'Y-m-d G:i:s.u T' %}{% endblock %}"
{% block Description %}{% if DQ.szIntro %}{{ DQ.szIntro }} {% endif %}{{ DQ.szContent }}{% if AUTHOR.szAuthor %} ({{ AUTHOR.szAuthor }}){% endif %}{% endblock %}
{% block Keywords %}Цитаты, {% for i in TAGS %}{{ i.name|safe }}, {% endfor %}Высказвания{% endblock %}
{% block CopyrightAuthor4Meta %}{% if AUTHOR.szAuthor %}, {{ AUTHOR.szAuthor }} (слова){% endif %}{% endblock %}
<!--- ТИТУЛ --->
{% block Title %}DQ: {{ DQ.szContent }}{% if AUTHOR.szAuthor %} ({{ AUTHOR.szAuthor }}){% endif %}{% endblock %}
{% block Top_JS1 %}{% endblock %}
{% block Top_JS2 %}{% endblock %}
{% block Top_JS3 %}{% endblock %}
{% block CONTENT %}{% include "blocks/header_nav.html" %}
<center><table style="height:80vh;">
<tr>
<td>
<div id="info">{{ DQ.szIntroHTML|safe }}</div>
<div id="bb">{{ DQ.szContentHTML|safe }}</div>
<div id="author">{{ AUTHOR.szAuthorHTML|safe }}</div>
</td>{% if IMAGE %}<td id="image">
<center><div style="background:rgba({% for i in CLR %}{% if forloop.counter <= 3 %}{{ i|stringformat:"02d" }}{% if forloop.counter < 3 %},{%endif %}{% endif %}{% empty %}87,00,00{% endfor %},0.7);">
<div><img src="{{IMAGE.url}}" alt="{{ AUTHOR.szAuthor }}" title="{{ AUTHOR.szAuthor }}" /></div>
</div></center>
</td></tr><tr><td colspan="2">{% else %}</tr><tr><td>{% endif %}
<div class="tags">
{% for i in TAGS %}<a href="/?tag={{ i.slug }}">{{ i.name|safe }}</a> {% endfor %}
<div id="next"><a href="/{{ NEXT}}_{{ NEXT_TXT }}">&rightarrow;</a></div>
</div>
</td>
</tr>
</table></center>
<script type="text/javascript">
setTimeout('location.replace("/{{ NEXT}}_{{ NEXT_TXT }}")', 15000);
/*Изменить текущий адрес страницы через 3 секунды (3000 миллисекунд)*/
</script>
<noscript>
<meta http-equiv="refresh" content="15; url=/{{ NEXT}}_{{ NEXT_TXT }}">
</noscript>
{% if not cookie_accept %}{% include "blocks/cookie_warning.html" %}{% endif %}
{% endblock %}

0
dicquo/web/__init__.py Normal file
View File

66
dicquo/web/admin.py Normal file
View File

@ -0,0 +1,66 @@
# -*- coding: utf-8 -*-
from django.contrib import admin
from web.models import TbDictumAndQuotes, TbAuthor, TbImages, TbOrigin
# Register your models here.
class AdmDictumAndQuotesAdmin(admin.ModelAdmin):
search_fields = ['id', 'szIntro', 'szContent', ]
list_display = ('id', 'szIntro', 'szContent', 'tag_list', 'iViewCounter', 'dtEdited', )
list_display_links = ('id', 'szIntro', 'szContent', )
# list_filter = ('iViewCounter', )
empty_value_display = u"<b style='color:red;'>-empty-</b>"
actions_on_top = False
actions_on_bottom = True
actions_selection_counter = True
# погасить кнопку "Добавить" в интерфейсе админки
# def has_add_permission(self, request):
# return False
# fieldsets = (
# (None, {'fields': ('szIntro', 'iViewCounter', 'tags',)}),
# )
def get_queryset(self, request):
return super().get_queryset(request).prefetch_related('tags')
def tag_list(self, obj):
return u", ".join(o.name for o in obj.tags.all())
class AdmOrigin(admin.ModelAdmin):
search_fields = ['id', 'szOrigin', ]
list_display = ('id', 'szOrigin',)
list_display_links = ('id', 'szOrigin',)
empty_value_display = u"<b style='color:red;'>-empty-</b>"
class AdmImages(admin.ModelAdmin):
search_fields = ['id', 'imFile', 'szCaption', ]
list_display = ('id', 'szCaption', 'tag_list', 'iViewCounter', 'imFile', 'dtEdited',)
list_display_links = ('id', 'szCaption')
empty_value_display = u"<b style='color:red;'>-empty-</b>"
def get_queryset(self, request):
return super().get_queryset(request).prefetch_related('tags')
def tag_list(self, obj):
return u", ".join(o.name for o in obj.tags.all())
class AdmAuthor(admin.ModelAdmin):
search_fields = ['id', 'szAuthor', 'szCaption', ]
list_display = ('id', 'szAuthor', 'tag_list', 'iViewCounter', 'dtEdited',)
list_display_links = ('id', 'szAuthor')
empty_value_display = u"<b style='color:red;'>-empty-</b>"
def get_queryset(self, request):
return super().get_queryset(request).prefetch_related('tags')
def tag_list(self, obj):
return u", ".join(o.name for o in obj.tags.all())
admin.site.register(TbDictumAndQuotes, AdmDictumAndQuotesAdmin)
admin.site.register(TbOrigin, AdmOrigin)
admin.site.register(TbImages, AdmImages)
admin.site.register(TbAuthor, AdmAuthor)

6
dicquo/web/apps.py Normal file
View File

@ -0,0 +1,6 @@
# -*- coding: utf-8 -*-
from django.apps import AppConfig
class WebConfig(AppConfig):
name = 'web'

View File

@ -0,0 +1,90 @@
# Generated by Django 3.1.2 on 2020-10-05 06:52
from django.db import migrations, models
import django.db.models.deletion
import taggit.managers
class Migration(migrations.Migration):
initial = True
dependencies = [
('taggit', '0003_taggeditem_add_unique_index'),
]
operations = [
migrations.CreateModel(
name='TbAuthor',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('szAuthor', models.CharField(db_index=True, default='', help_text='Автор и, если необходимо, краткая справка', max_length=128, unique=True, verbose_name='Автор')),
('szAuthorHTML', models.TextField(default='', help_text='Автор и, если необходимо, краткая справка<br />Свертано в HTML по правилам типографики <small>(рекламные URL вставляются тут)</small>', null=True, verbose_name='Автор HTML')),
('bIsChecked', models.BooleanField(db_index=True, default=True, help_text='Есть доступ для сканирования.', verbose_name='Проверен')),
('iViewCounter', models.PositiveIntegerField(default=0, help_text='Число просмотров картинки.', verbose_name='Просмотры')),
('dtCreated', models.DateTimeField(auto_now_add=True, db_index=True, verbose_name='Дата создания')),
('dtEdited', models.DateTimeField(auto_now=True, db_index=True, verbose_name='Дата последнего редактирования')),
('tags', taggit.managers.TaggableManager(help_text='Теги через запятую… Регистр не чувствителен… <b>Теги нужны для подстановки картинок и навигации<b>', through='taggit.TaggedItem', to='taggit.Tag', verbose_name='Теги')),
],
options={
'verbose_name': 'АВТОР',
'verbose_name_plural': 'АВТОРЫ',
'ordering': ['id'],
},
),
migrations.CreateModel(
name='TbOrigin',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('szOrigin', models.CharField(db_index=True, default='', help_text='Ссылка или указание источника: книга, URL, просто что-то…', max_length=256, unique=True, verbose_name='Источник')),
('dtCreated', models.DateTimeField(auto_now_add=True, db_index=True, verbose_name='Дата создания')),
('dtEdited', models.DateTimeField(auto_now=True, db_index=True, verbose_name='Дата последнего редактирования')),
],
options={
'verbose_name': 'ИСТОЧНИК',
'verbose_name_plural': 'ИСТОЧНИКИ',
'ordering': ['id'],
},
),
migrations.CreateModel(
name='TbImages',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('imFile', models.ImageField(db_index=True, default='', help_text='Файл с картинкой (gif, jpeg, png, bmp).', max_length=136, unique=True, upload_to='img2', verbose_name='Картинка')),
('szCaption', models.CharField(db_index=True, default='', help_text='Название, подпись, описание что изображено…', max_length=128, unique=True, verbose_name='Название')),
('bIsChecked', models.BooleanField(db_index=True, default=True, help_text='Есть доступ для сканирования.', verbose_name='Проверен')),
('iViewCounter', models.PositiveIntegerField(default=0, help_text='Число просмотров картинки.', verbose_name='Просмотры')),
('dtCreated', models.DateTimeField(auto_now_add=True, db_index=True, verbose_name='Дата создания')),
('dtEdited', models.DateTimeField(auto_now=True, db_index=True, verbose_name='Дата последнего редактирования')),
('tags', taggit.managers.TaggableManager(help_text='Теги через запятую… Регистр не чувствителен… <b>Теги нужны для подстановки картинок и навигации<b>', through='taggit.TaggedItem', to='taggit.Tag', verbose_name='Теги')),
],
options={
'verbose_name': 'КАРТИНКА',
'verbose_name_plural': 'КАРТИНКИ',
'ordering': ['id'],
},
),
migrations.CreateModel(
name='TbDictumAndQuotes',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('szIntro', models.CharField(default=None, help_text='Не обязательно. Вступление перед цитатой.', max_length=256, null=True, verbose_name='Вступление')),
('szIntroHTML', models.TextField(default='', help_text='Автор и, если необходимо, краткая справка<br />Вступление перед цитатой, в HTML по правилам типографики</small>', verbose_name='Вступление HTML')),
('szContent', models.TextField(default='', help_text='Не обязательно. Вступление перед цитатой.', max_length=256, verbose_name='Высказывание')),
('szContentHTML', models.TextField(default='', help_text='<b>Высказывание Крылатое</b> -- крылатое, пародоксальное и все такое', verbose_name='Высказывание HTML')),
('imFileOG', models.ImageField(default='', help_text='Картинка для социальной сети <b>(будет создана автоматически)</b>.<br /><small>Файл с картинкой (png).<small>', max_length=136, upload_to='img2og', verbose_name='OG-image</b>')),
('iViewCounter', models.PositiveIntegerField(db_index=True, default=0, help_text='Число сканирований хоста.', verbose_name='Просмотры')),
('dtCreated', models.DateTimeField(auto_now_add=True, db_index=True, verbose_name='Дата создания')),
('dtEdited', models.DateTimeField(auto_now=True, db_index=True, verbose_name='Дата последнего редактирования')),
('kAuthor', models.ForeignKey(default=None, help_text='Автор изречения или цитаты <b>(не обязательно, но желательно)</b>', null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='web.tbauthor', verbose_name='Автор')),
('kImages', models.ForeignKey(default=None, help_text='Ссылка на картинку, в табличке картинок <b>(не обязательно)</b><br /><small>если нужна именно данная картинка, а не выбранная автоматически</small>', null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='web.tbimages', verbose_name='Картинка')),
('kOrigin', models.ForeignKey(default=None, help_text='Откуда взята циатата, высказывание, изречение <b>(не обязательно, но желательно)</b>', null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='web.tborigin', verbose_name='Источник')),
('tags', taggit.managers.TaggableManager(help_text='Теги через запятую… Регистр не чувствителен… <b>Теги нужны для подстановки картинок и навигации<b>', through='taggit.TaggedItem', to='taggit.Tag', verbose_name='Теги')),
],
options={
'verbose_name': 'ВЫСКАЗЫВАНИЕ',
'verbose_name_plural': 'ВЫСКАЗЫВАНИЯ',
'ordering': ['id'],
},
),
]

View File

416
dicquo/web/models.py Normal file
View File

@ -0,0 +1,416 @@
# -*- coding: utf-8 -*-
from django.db import models
from taggit.managers import TaggableManager
from taggit.models import Tag, TaggedItem
from typus import en_typus, ru_typus
from pathlib import Path
import urllib3
import json
import pytils
# класс для транслитерации русскоязычных slug
# рецепт взят отсюда: https://timonweb.com/django/russian-slugs-for-django-taggit/
class RuTag(Tag):
class Meta:
proxy = True
def slugify(self, tag, i=None):
return pytils.translit.slugify(self.name.lower())[:128]
class RuTaggedItem(TaggedItem):
class Meta:
proxy = True
@classmethod
def tag_model(cls):
return RuTag
class TbImages(models.Model):
# ============================================================
# ТАБЛИЦА TbImages -- Изображения
# ------------------------------------------------------------
# | id -- id | INT(11) | PRIMARY KEY
# | imFile -- Картинка | varchar(128) NOT NULL
# | szCaption -- Заголовок, подпись под картинкой | varchar(136) NULL
# | bIsChecked -- Проверен | tinyint(1) NOT NULL
# | iViewCounter -- Просмотры | int(10) UNSIGNED NOT NULL
# | dtCreated -- Дата создания | datetime(6) NOT NULL
# | dtEdited -- Дата проверки | datetime(6) NOT NULL
# ============================================================
imFile = models.ImageField(
max_length=136,
upload_to="img2",
default=u"",
unique=True,
db_index=True,
verbose_name=u"Картинка",
help_text=u"Файл с картинкой (gif, jpeg, png, bmp)."
)
szCaption = models.CharField(
max_length=128,
default=u"",
unique=True,
db_index=True,
blank=False,
verbose_name=u"Название",
help_text=u"Название, подпись, описание что изображено…"
)
tags = TaggableManager(
blank=True,
through=RuTaggedItem,
verbose_name=u"Теги",
help_text=u"Теги через запятую… Регистр не чувствителен… <b>Теги нужны для подстановки картинок и навигации<b>"
)
bIsChecked = models.BooleanField(
default=True,
db_index=True,
verbose_name=u"Проверен",
help_text=u"Картинку проверили."
)
iViewCounter = models.PositiveIntegerField(
default=0,
verbose_name=u"",
help_text=u"Число просмотров картинки."
)
dtCreated = models.DateTimeField(
db_index=True,
auto_now_add=True, # надо указать False при миграции, после вернуть в True
auto_now=False, # надо указать False при миграции, после вернуть в True
# для выполнения миграций нужно добавлять default, а после убрать (она не нужна)
# default=datetime.datetime.now(pytz.timezone(settings.TIME_ZONE)),
verbose_name=u"Дата создания"
)
dtEdited = models.DateTimeField(
db_index=True,
auto_now=True, # надо указать False при миграции, после вернуть в True
# для выполнения миграций нужно добавлять default, а после она не нужна
# default=datetime.datetime.now(pytz.timezone(settings.TIME_ZONE)),
verbose_name=u"Дата редактирования"
)
def __str__(self):
filename = self.imFile.name
if len(filename) > 15:
filename = filename[:15] + u""
caption = self.szCaption
if len(caption) > 25:
caption = caption[:25] + u""
caption = "%d×%d - %s" % (self.imFile.width, self.imFile.height, caption)
return u"%05d: %s (%s)" % (self.id, filename, caption)
def __unicode__(self):
return self.__str__()
# заменим имя файла картинки
def save(self, *args, **kwargs):
self.imFile.name = pytils.translit.slugify(self.szCaption.lower()) + str(Path(self.imFile.name).suffixes)
super(TbImages, self).save(*args, **kwargs)
class Meta:
verbose_name = u"КАРТИНКА"
verbose_name_plural = u"КАРТИНКИ"
ordering = ['id', ]
class TbOrigin(models.Model):
# ============================================================
# ТАБЛИЦА TbOrigin -- Источник, место откуда взята циатата, высказывание, изречение
# ------------------------------------------------------------
# | id -- id | INT(11) | PRIMARY KEY
# | szOrigin -- Источник | varchar(256) NULL
# | dtCreated -- Дата создания | datetime(6) NOT NULL
# | dtEdited -- Дата проверки | datetime(6) NOT NULL
# ============================================================
szOrigin = models.CharField(
max_length=256,
default=u"",
unique=True,
db_index=True,
verbose_name=u"Источник",
help_text=u"Ссылка или указание источника: книга, URL, просто что-то…"
)
dtCreated = models.DateTimeField(
db_index=True,
auto_now_add=True, # надо указать False при миграции, после вернуть в True
auto_now=False, # надо указать False при миграции, после вернуть в True
# для выполнения миграций нужно добавлять default, а после убрать (она не нужна)
# default=datetime.datetime.now(pytz.timezone(settings.TIME_ZONE)),
verbose_name=u"Дата создания"
)
dtEdited = models.DateTimeField(
db_index=True,
auto_now=True, # надо указать False при миграции, после вернуть в True
# для выполнения миграций нужно добавлять default, а после она не нужна
# default=datetime.datetime.now(pytz.timezone(settings.TIME_ZONE)),
verbose_name=u"Дата редактирования"
)
def __str__(self):
origin = self.szOrigin
if len(origin) > 35:
origin = origin[:35] + u""
return u"%03d: %s" % (self.id, origin)
def __unicode__(self):
return self.__str__()
class Meta:
verbose_name = u"ИСТОЧНИК"
verbose_name_plural = u"ИСТОЧНИКИ"
ordering = ['id', ]
class TbAuthor(models.Model):
# ============================================================
# ТАБЛИЦА TbAuthor -- Автор изречения или цитаты (dictum and quotes)
# ------------------------------------------------------------
# | id -- id | INT(11) | PRIMARY KEY
# | szAuthor -- Автор и, если необходимо, краткая справка | varchar(256) NOT NULL
# | szAuthorHTML -- Автор и... в HTML по правилам типографики | varchar(136) NULL
# | bIsChecked -- Проверен | tinyint(1) NOT NULL
# | iViewCounter -- Просмотры | int(10) UNSIGNED NOT NULL
# | dtCreated -- Дата создания | datetime(6) NOT NULL
# | dtEdited -- Дата проверки | datetime(6) NOT NULL
# ============================================================
szAuthor = models.CharField(
max_length=128,
default=u"",
unique=True,
db_index=True,
verbose_name=u"Автор",
help_text=u"Автор и, если необходимо, краткая справка"
)
szAuthorHTML = models.TextField(
default="",
blank=True,
verbose_name=u"Автор HTML",
help_text=u"Автор и, если необходимо, краткая справка<br />"
u"Свертано в HTML по правилам типографики <small>(рекламные URL вставляются тут)</small>"
)
bIsChecked = models.BooleanField(
default=True,
db_index=True,
verbose_name=u"Проверен",
help_text=u"Автор проверен."
)
tags = TaggableManager(
blank=True,
through=RuTaggedItem,
verbose_name=u"Теги",
help_text=u"Теги через запятую… Регистр не чувствителен… <b>Теги нужны для подстановки картинок и навигации<b>"
)
iViewCounter = models.PositiveIntegerField(
default=0,
verbose_name=u"",
help_text=u"Число просмотров Автора."
)
dtCreated = models.DateTimeField(
db_index=True,
auto_now_add=True, # надо указать False при миграции, после вернуть в True
auto_now=False, # надо указать False при миграции, после вернуть в True
# для выполнения миграций нужно добавлять default, а после убрать (она не нужна)
# default=datetime.datetime.now(pytz.timezone(settings.TIME_ZONE)),
verbose_name=u"Дата создания"
)
dtEdited = models.DateTimeField(
db_index=True,
auto_now=True, # надо указать False при миграции, после вернуть в True
# для выполнения миграций нужно добавлять default, а после она не нужна
# default=datetime.datetime.now(pytz.timezone(settings.TIME_ZONE)),
verbose_name=u"Дата редактирования"
)
def __str__(self):
author = self.szAuthor
if len(author) > 25:
author = author[:25] + u""
return u"%04d: %s" % (self.id, author)
def __unicode__(self):
return self.__str__()
def save(self, *args, **kwargs):
http = urllib3.PoolManager()
# последовательно
# Используем типограф typus (https://github.com/byashimov/typus)
# Используем типограф Eugene Spearance (http://www.typograf.ru/)
# Используем типограф Муравьева (http://mdash.ru/api.v1.php)
self.szAuthor = ru_typus(self.szAuthor)
resp = http.request("POST",
"http://www.typograf.ru/webservice/",
fields={"text": self.szAuthor.encode('cp1251')})
self.szAuthorHTML = resp.data.decode('cp1251')
# print(self.szContentHTML)
resp = http.request("POST",
"http://mdash.ru/api.v1.php",
fields={"text": self.szAuthorHTML.encode('utf-8')})
self.szAuthorHTML = json.loads(resp.data)["result"]
# print(self.szContentHTML)
super(TbAuthor, self).save(*args, **kwargs)
class Meta:
verbose_name = u"АВТОР"
verbose_name_plural = u"АВТОРЫ"
ordering = ['id', ]
class TbDictumAndQuotes(models.Model):
# ============================================================
# ТАБЛИЦА TbDictQuot -- Изречения и Цитаты (dictum and quotes)
# ------------------------------------------------------------
# | id -- id | INT(11) | PRIMARY KEY
# | szIntro -- Вступление | varchar(256) NULL
# | szIntroHTML -- Вступление | (форматированное в HTML) varchar(136) NULL
# | szContent -- Высказывание | varchar(136) NOT NULL
# | szContentHtml -- Высказывание (Сформатированнон в HTML) | varchar(136) NULL
# | bIsChecked -- Проверен | tinyint(1) NOT NULL
# | kImages -- Ссылка на картинку в таблице TbImages |
# | iViewCounter -- Просмотры | int(10) UNSIGNED NOT NULL
# | dtCreated -- Дата создания | datetime(6) NOT NULL
# | dtEdited -- Дата проверки | datetime(6) NOT NULL
# ============================================================
szIntro = models.CharField(
max_length=256,
default=None,
blank=True,
verbose_name=u"Вступление",
help_text=u"Не обязательно. Вступление перед цитатой."
)
szIntroHTML = models.TextField(
default="",
blank=True,
verbose_name=u"Вступление HTML",
help_text=u"Автор и, если необходимо, краткая справка<br />"
u"Вступление перед цитатой, в HTML по правилам типографики</small>"
)
szContent = models.TextField(
max_length=256,
default="",
verbose_name=u"Высказывание",
help_text=u"Не обязательно. Вступление перед цитатой."
)
szContentHTML = models.TextField(
default="",
blank=True,
verbose_name=u"Высказывание HTML",
help_text=u"<b>Высказывание Крылатое</b> -- крылатое, пародоксальное и все такое"
)
kAuthor = models.ForeignKey(
TbAuthor,
default=None,
blank=True,
on_delete=models.DO_NOTHING,
verbose_name=u"Автор",
help_text=u"Автор изречения или цитаты <b>(не обязательно, но желательно)</b>"
)
kOrigin = models.ForeignKey(
TbOrigin,
default=None,
blank=True,
on_delete=models.DO_NOTHING,
verbose_name=u"Источник",
help_text=u"Откуда взята циатата, высказывание, изречение <b>(не обязательно, но желательно)</b>"
)
kImages = models.ForeignKey(
TbImages,
default=None,
blank=True,
on_delete=models.DO_NOTHING,
verbose_name=u"Картинка",
help_text=u"Ссылка на картинку, в табличке картинок <b>(не обязательно)</b><br />"
u"<small>если нужна именно данная картинка, а не выбранная автоматически</small>"
)
imFileOG = models.ImageField(
max_length=136,
upload_to="img2og",
default=u"",
blank=True,
verbose_name=u"OG-image",
help_text=u"Картинка для социальной сети <b>(будет создана автоматически)</b>.<br />"
u"<small>Файл с картинкой (png).<small>"
)
iViewCounter = models.PositiveIntegerField(
default=0,
db_index=True,
verbose_name=u"",
help_text=u"Число просмотров высказывания."
)
tags = TaggableManager(
blank=True,
through=RuTaggedItem,
verbose_name=u"Теги",
help_text=u"Теги через запятую… Регистр не чувствителен… <b>Теги нужны для подстановки картинок и навигации<b>"
)
dtCreated = models.DateTimeField(
db_index=True,
auto_now_add=True, # надо указать False при миграции, после вернуть в True
auto_now=False, # надо указать False при миграции, после вернуть в True
# для выполнения миграций нужно добавлять default, а после убрать (она не нужна)
# default=datetime.datetime.now(pytz.timezone(settings.TIME_ZONE)),
verbose_name=u"Дата создания"
)
dtEdited = models.DateTimeField(
db_index=True,
auto_now=True, # надо указать False при миграции, после вернуть в True
# для выполнения миграций нужно добавлять default, а после она не нужна
# default=datetime.datetime.now(pytz.timezone(settings.TIME_ZONE)),
verbose_name=u"Дата редактирования"
)
def __str__(self):
intro = self.szIntro
if len(intro) > 35:
intro = intro[:35] + u""
content = self.szContent
if len(content) > 55:
content = content[:55] + u""
return u"%05d: %s :: %s" % (self.id, intro, content)
def __unicode__(self):
return self.__str__()
def save(self, *args, **kwargs):
http = urllib3.PoolManager()
# последовательно
# Используем типограф typus (https://github.com/byashimov/typus)
# Используем типограф Eugene Spearance (http://www.typograf.ru/)
# Используем типограф Муравьева (http://mdash.ru/api.v1.php)
if self.szIntro != "" and self.szIntro != ru_typus(self.szIntro):
# сравнение self.szIntro != ru_typus(self.szIntro) нужно для избежания повторных обращений
# к типографам при обновлении щетчиков просмотра
self.szIntro = ru_typus(self.szIntro)
resp = http.request("POST",
"http://www.typograf.ru/webservice/",
fields={"text": self.szIntro.replace("\u202f", " ").replace("\u2009", " ").encode('cp1251')})
self.szIntroHTML = resp.data.decode('cp1251')
# print(self.szIntroHTML)
resp = http.request("POST",
"http://mdash.ru/api.v1.php",
fields={"text": self.szIntroHTML.encode('utf-8')})
self.szIntroHTML = json.loads(resp.data)["result"]
# print(self.szIntroHTML)
else:
self.szIntroHTML = ""
if self.szContent != ru_typus(self.szContent):
# self.szContent != ru_typus(self.szContent) нужно для избежания повторных обращений
# к типографам при обновлении щетчиков просмотра
self.szContent = ru_typus(self.szContent)
resp = http.request("POST",
"http://www.typograf.ru/webservice/",
fields={"text": self.szContent.replace("\u202f", " ").replace("\u2009", " ").encode('cp1251')})
self.szContentHTML = resp.data.decode('cp1251')
print(self.szContentHTML)
resp = http.request("POST",
"http://mdash.ru/api.v1.php",
fields={"text": self.szContentHTML.encode('utf-8')})
self.szContentHTML = json.loads(resp.data)["result"]
# print(self.szContentHTML)
super(TbDictumAndQuotes, self).save(*args, **kwargs)
class Meta:
verbose_name = u"ВЫСКАЗЫВАНИЕ"
verbose_name_plural = u"ВЫСКАЗЫВАНИЯ"
ordering = ['id', ]

4
dicquo/web/tests.py Normal file
View File

@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
from django.test import TestCase
# Create your tests here.

89
dicquo/web/views.py Normal file
View File

@ -0,0 +1,89 @@
# -*- coding: utf-8 -*-
__author__ = "Sergei Erjemin"
__copyright__ = "Copyright 2020, Sergei Erjemin"
__credits__ = ["Sergei Erjemin", ]
__license__ = "GPL"
__version__ = "0.0.1"
__maintainer__ = "Sergei Erjemin"
__email__ = "erjemin@gmail.com"
__status__ = "in progress"
from django.shortcuts import render
from django.core.exceptions import ObjectDoesNotExist
import time
import hashlib
import random
import pytils
from taggit.models import Tag
from web.models import TbOrigin, TbDictumAndQuotes, TbImages, TbAuthor
# Create your views here.
def for_dq(dq):
to_template = {}
num = int(hashlib.blake2s(dq.szContent.encode("utf-8"), digest_size=1).hexdigest(), 16)
clr = sorted([num / 2, num / 3, num / 5, num / 7, num / 11, num / 1.5], key=lambda A: random.random())
to_template.update({'CLR': clr})
to_template.update({'DQ': dq})
try:
au = TbAuthor.objects.get(id=dq.kAuthor_id)
to_template.update({'AUTHOR': au})
tags = au.tags.names()
except ObjectDoesNotExist:
tags = dq.tags.names()
tag_and_slug = []
for i in tags:
tag_and_slug.append({"name": i, "slug": pytils.translit.slugify(i.lower())[:128]})
to_template.update({'TAGS': sorted(tag_and_slug, key=lambda x: x["name"])}) # tag_and_slug
if dq.kImages_id is None:
if len(tags) != 0:
try:
tagged_image = TbImages.objects.filter(tags__name__in=tags).order_by('?')[0]
to_template.update({'IMAGE': tagged_image.imFile})
except IndexError:
pass
else:
to_template.update({'IMAGE': dq.kImages.imFile})
dq.iViewCounter += 1
dq.save()
dq_next = TbDictumAndQuotes.objects.exclude(id=dq.id).order_by('?').first()
to_template.update({"NEXT": dq_next.id})
to_template.update({"NEXT_TXT": pytils.translit.slugify(dq_next.szContent.lower()[:120])})
return to_template
def by_id( request, dq_id):
t_start = time.process_time()
template = "index.html" # шаблон
dq = TbDictumAndQuotes.objects.get(id=dq_id)
to_template = for_dq(dq)
# пероверка, что посетитель согласился со сбором даных через cookies
if request.COOKIES.get('cookie_accept'):
to_template.update({'cookie_accept': 1})
to_template.update({'ticks': float(time.process_time() - t_start)})
response = render(request, template, to_template)
return response
def index(request):
t_start = time.process_time()
# проверка на аутентификацию
# if not request.user.is_authenticated():
# return HttpResponseRedirect("/access")
template = "index.html" # шаблон
dq_ = TbDictumAndQuotes.objects.order_by('?')
if request.GET.get('tag'):
dq = dq_.filter(kAuthor__tags__slug__in=[request.GET['tag']]).first()
if dq is None:
dq = dq_.filter(tags__slug__in=[request.GET['tag']]).first()
if dq is None:
dq = dq_.first()
else:
dq = dq_.first()
to_template = for_dq(dq)
# пероверка, что посетитель согласился со сбором даных через cookies
if request.COOKIES.get('cookie_accept'):
to_template.update({'cookie_accept': 1})
to_template.update({'ticks': float(time.process_time() - t_start)})
response = render(request, template, to_template)
return response

37
passenger_wsgi.py Normal file
View File

@ -0,0 +1,37 @@
#!/home/eserg/dq.cube2.ru/env/bin/python3
import sys, os
INTERP = "/home/eserg/dq.cube2.ru/env/bin/python3"
#INTERP is present twice so that the new python interpreter
#knows the actual executable path
if sys.executable != INTERP:
os.execl(INTERP, INTERP, *sys.argv)
cwd = os.getcwd()
sys.path.append(cwd)
sys.path.append(cwd + '/dicquo') #You must add your project here
sys.path.insert(0,cwd+'/env/bin')
sys.path.insert(0,cwd+'/env/lib/python3.8/site-packages')
os.environ['DJANGO_SETTINGS_MODULE'] = "dicquo.settings"
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()
##!/usr/bin/env python
#import sys, os
#cwd = os.getcwd()
#sys.path.append(cwd)
#sys.path.append(cwd + '/dicquo')
##Switch to new python
##if sys.version < "2.7.8": os.execl(cwd+"/env/bin/python", "python2.7", *sys.argv)
#sys.path.insert(0,cwd+'/env/bin')
#sys.path.insert(0,cwd+'/env/lib/python3.8/site-packages/django')
#sys.path.insert(0,cwd+'/env/lib/python3.8/site-packages')
#os.environ['DJANGO_SETTINGS_MODULE'] = "dicquo.settings"
#from django.core.wsgi import get_wsgi_application
#application = get_wsgi_application()

BIN
public/favicon.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

53
public/favicon.svg Normal file
View File

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Creator: CorelDRAW X6 -->
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="50px" height="46px" version="1.1" style="shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd"
viewBox="0 0 1512 1386"
xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<style type="text/css">
<![CDATA[
.fil6 {fill:#FFD900}
.fil2 {fill:#AE4A84;fill-rule:nonzero}
.fil3 {fill:url(#id0)}
.fil4 {fill:url(#id1)}
.fil1 {fill:url(#id2)}
.fil0 {fill:url(#id3)}
.fil5 {fill:url(#id4)}
]]>
</style>
<linearGradient id="id0" gradientUnits="userSpaceOnUse" x1="1476.52" y1="1395.4" x2="1034.86" y2="872.762">
<stop offset="0" style="stop-color:#EF7F1A"/>
<stop offset="0.34902" style="stop-color:#FFED00"/>
<stop offset="0.94902" style="stop-color:#CC6F3C"/>
<stop offset="1" style="stop-color:#CC6F3C"/>
</linearGradient>
<linearGradient id="id1" gradientUnits="userSpaceOnUse" x1="1023.98" y1="1127.45" x2="575.667" y2="596.929">
<stop offset="0" style="stop-color:#EF7F1A"/>
<stop offset="0.0588235" style="stop-color:#CC6F3C"/>
<stop offset="0.670588" style="stop-color:#FFED00"/>
<stop offset="1" style="stop-color:#CC6F3C"/>
</linearGradient>
<linearGradient id="id2" gradientUnits="userSpaceOnUse" xlink:href="#id0" x1="1398.9" y1="1160.31" x2="613.548" y2="230.976">
</linearGradient>
<linearGradient id="id3" gradientUnits="userSpaceOnUse" xlink:href="#id0" x1="805.595" y1="948.571" x2="21.0238" y2="20.1429">
</linearGradient>
<linearGradient id="id4" gradientUnits="userSpaceOnUse" x1="381.071" y1="958.69" x2="89.0714" y2="613.119">
<stop offset="0" style="stop-color:#EF7F1A"/>
<stop offset="0.831373" style="stop-color:#FFED00"/>
<stop offset="0.94902" style="stop-color:#CC6F3C"/>
<stop offset="1" style="stop-color:#CC6F3C"/>
</linearGradient>
</defs>
<g id="Layer_x0020_1">
<metadata id="CorelCorpID_0Corel-Layer"/>
<path class="fil0" d="M746 677l-341 293c21,-19 37,-44 49,-75 14,-37 20,-83 20,-137 0,-47 -6,-92 -19,-135 -13,-43 -32,-82 -58,-118 -26,-36 -57,-67 -95,-95 -38,-27 -84,-50 -139,-68l-136 -44c-6,-2 -12,-2 -18,1 -1,0 -2,1 -3,2l345 -296c1,-1 2,-2 4,-2 6,-3 12,-3 18,-1l136 44c55,18 101,41 139,68 38,27 69,59 95,95 25,36 45,75 58,118 13,43 19,88 19,135 0,54 -7,100 -20,137 -12,34 -30,60 -53,79z"/>
<path class="fil1" d="M1005 1173c12,-10 22,-22 30,-35 10,-16 18,-34 25,-54 6,-20 11,-41 14,-65 3,-23 4,-48 4,-73 0,-50 -6,-97 -17,-141 -12,-44 -29,-83 -51,-119 -23,-35 -51,-66 -85,-92 -34,-26 -74,-47 -119,-62 -48,-16 -90,-22 -126,-17 -36,4 -66,17 -91,40l345 -295c24,-22 54,-34 90,-39 36,-4 78,2 126,17 45,15 85,35 119,62 34,26 63,57 85,92 23,35 40,75 51,119 11,44 17,90 17,141 0,26 -2,50 -4,73 -3,23 -8,45 -14,65 -6,20 -15,38 -25,54 -9,14 -20,27 -33,37l-341 292z"/>
<path class="fil2" d="M409 739c0,-38 -5,-74 -14,-109 -10,-35 -24,-68 -44,-97 -20,-30 -45,-56 -75,-79 -30,-23 -69,-42 -116,-58l-99 -33 0 538 100 33c44,14 81,21 111,20 30,-1 56,-9 76,-25 20,-16 35,-40 46,-71 10,-31 15,-71 15,-118zm65 18c0,54 -7,100 -20,137 -14,37 -34,65 -60,84 -27,19 -59,30 -98,31 -39,1 -86,-7 -140,-24l-127 -42c-6,-2 -12,-6 -18,-13 -6,-7 -10,-16 -10,-28l0 -583c0,-12 3,-19 10,-22 6,-3 12,-3 18,-1l136 44c55,18 101,41 139,68 38,27 69,59 95,95 25,36 45,75 58,118 13,43 19,88 19,135z"/>
<path class="fil3" d="M1343 884l-333 285c-3,3 -7,6 -10,9 26,30 49,54 68,73 20,18 36,33 48,43 13,10 22,18 29,23 7,5 12,9 15,13 3,4 5,8 6,13 1,5 2,10 2,17 0,5 0,10 -1,13 -1,3 -2,6 -4,8 -1,1 -1,1 -2,2l344 -294c1,0 1,-1 2,-2 2,-2 3,-5 4,-8 1,-4 1,-8 1,-13 0,-7 -1,-12 -2,-17 -1,-5 -3,-9 -6,-13 -3,-4 -8,-8 -15,-13 -7,-5 -17,-13 -29,-23 -13,-10 -29,-25 -48,-43 -20,-19 -42,-43 -68,-73z"/>
<path class="fil2" d="M1015 931c0,-38 -4,-75 -11,-111 -7,-36 -19,-69 -36,-99 -17,-30 -38,-57 -66,-80 -27,-23 -61,-41 -102,-54 -40,-13 -74,-17 -101,-11 -28,6 -50,18 -67,38 -17,19 -29,44 -37,75 -8,31 -11,65 -11,101 0,39 3,77 10,113 7,36 18,69 35,99 16,30 38,57 66,80 27,23 62,41 103,55 41,13 75,17 103,11 28,-6 50,-19 67,-39 17,-20 29,-45 36,-76 7,-31 11,-65 11,-102zm153 430c0,5 0,10 -1,13 -1,3 -2,6 -4,8 -2,2 -3,3 -5,3 -2,1 -3,0 -5,0 -4,-1 -12,-7 -26,-16 -13,-10 -29,-22 -48,-39 -19,-16 -39,-35 -61,-57 -22,-22 -44,-46 -66,-72 -17,6 -39,9 -65,9 -27,0 -58,-6 -94,-18 -48,-16 -89,-37 -124,-63 -35,-27 -63,-57 -85,-93 -22,-35 -38,-75 -49,-119 -10,-44 -16,-91 -16,-142 0,-51 6,-95 18,-132 12,-37 29,-67 53,-88 24,-21 53,-34 89,-38 36,-4 78,2 126,17 45,15 85,35 119,62 34,26 63,57 85,92 23,35 40,75 51,119 11,44 17,90 17,141 0,26 -2,50 -4,73 -3,23 -8,45 -14,65 -6,20 -15,38 -25,54 -10,16 -22,29 -36,40 26,30 49,54 68,73 20,18 36,33 48,43 13,10 22,18 29,23 7,5 12,9 15,13 3,4 5,8 6,13 1,5 2,10 2,17z"/>
<path class="fil4" d="M1015 931c0,-38 -4,-75 -11,-111 -7,-36 -19,-69 -36,-99 -17,-30 -38,-57 -66,-80 -27,-23 -61,-41 -102,-54 -40,-13 -74,-17 -101,-11 -28,6 -50,18 -67,38 -17,19 -29,44 -37,75 -8,31 -11,65 -11,101 0,39 3,77 10,113 7,36 18,69 35,99 16,30 38,57 66,80 27,23 62,41 103,55 41,13 75,17 103,11 28,-6 50,-19 67,-39 17,-20 29,-45 36,-76 7,-31 11,-65 11,-102z"/>
<path class="fil5" d="M61 900l330 -283c1,4 2,8 4,12 9,35 14,72 14,109 0,48 -5,87 -15,118 -10,31 -25,55 -46,71 -20,16 -45,24 -76,25 -31,1 -67,-6 -111,-20l-100 -33z"/>
<path class="fil6" d="M61 900l330 -283c-9,-31 -23,-59 -40,-85 -20,-30 -45,-56 -75,-79 -30,-23 -69,-42 -116,-58l-99 -33 0 538z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 348 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 240 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 212 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 KiB

7
public/robots.txt Normal file
View File

@ -0,0 +1,7 @@
# DicQuo
User-Agent: *
Allow: /
Disallow:
Host: dq.cube2.ru
Sitemap: https://dq.cube2.ru/sitemap.xml

View File

@ -0,0 +1,134 @@
@charset "utf-8";
.tags{
color: silver;
font-size:1.5vh;
line-height:1.9vh;
padding-top: 7vh;
}
/*****************************************************************
* Настройки для анимирования цвета ссылок:
* рецепт взят из: https://habr.com/ru/company/ruvds/blog/491702/
*****************************************************************/
.tags a {
text-decoration: none;
position: relative;
padding: 0 0.5ex;
display: inline-block;
color: white;
border-bottom: dotted 1px silver;
/* градиент для цвета ссылки */
background: linear-gradient(to right, rgba(255,255,255,0.9) 40%, slategray, silver, lightyellow 50%, rgba(255,255,255,0.4));
/* обрезка градиента */
background-clip: initial;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-size: 250% 100%;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=30)";
background-position: 100%;
/* плавное позиионирование градиента */
transition: background-position 0.65s ease;
margin-right: 2vh;
}
.tags a:hover {
color: white;
background-position: 0 100%;
border-bottom: solid 1px white;
}
div[name="cookies_accept"] {
font-family:'Roboto', 'Lucida Grande', Verdana, Arial, sans-serif;
position:fixed;
bottom: 0; left: 0;
width: 100%;
padding: 2vh 2vw;
color: black;
background-color: gray;
text-align: center;
}
div[name="cookies_accept"] button {
padding:0.5vh 0.5vw;
background: silver;
color: black;
margin-left: 2vw;
cursor: pointer;
}
#logo {
margin-top:1vh;
filter: alpha(Opacity=75); /* Полупрозрачность для IE */
opacity: 0.75;
float: left;
}
#logo a {
border: none;
text-decoration: none;
}
table { width: 80%; }
#menu {
display: none;
color: silver;
}
#mm {
text-decoration: none;
color: silver;
}
#image {
width: 30vw;
text-align: center;
vertical-align: center;
}
#image > center > div {
width: 22vw;
height: 22vw;
padding:0.5vw;
border-radius: 50%;
}
#image > center > div > div {
border-radius:50%;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
}
#image > center > div > div > img {
width: auto;
height: 22vw;
}
#author {
color: silver;
font-size: 3.5vh;
line-height: 4vh;
text-align: right;
padding-top: 4vh;
font-style: italic;
}
#info {
color: silver;
font-size: 2.5vh;
line-height: 3vh;
padding-bottom: 2vh;
}
#bb {
color: whitesmoke;
font-size: 4.5vh;
line-height: 5vh
}
#next { float: right; }
#next a { border-bottom: none; }

BIN
public/static/img/cubex.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 299 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

View File

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Creator: CorelDRAW X6 -->
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="50px" height="46px" version="1.1" style="shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd"
viewBox="0 0 1512 1386"
xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<style type="text/css">
<![CDATA[
.fil6 {fill:#FFD900}
.fil2 {fill:#AE4A84;fill-rule:nonzero}
.fil3 {fill:url(#id0)}
.fil4 {fill:url(#id1)}
.fil1 {fill:url(#id2)}
.fil0 {fill:url(#id3)}
.fil5 {fill:url(#id4)}
]]>
</style>
<linearGradient id="id0" gradientUnits="userSpaceOnUse" x1="1476.52" y1="1395.4" x2="1034.86" y2="872.762">
<stop offset="0" style="stop-color:#EF7F1A"/>
<stop offset="0.34902" style="stop-color:#FFED00"/>
<stop offset="0.94902" style="stop-color:#CC6F3C"/>
<stop offset="1" style="stop-color:#CC6F3C"/>
</linearGradient>
<linearGradient id="id1" gradientUnits="userSpaceOnUse" x1="1023.98" y1="1127.45" x2="575.667" y2="596.929">
<stop offset="0" style="stop-color:#EF7F1A"/>
<stop offset="0.0588235" style="stop-color:#CC6F3C"/>
<stop offset="0.670588" style="stop-color:#FFED00"/>
<stop offset="1" style="stop-color:#CC6F3C"/>
</linearGradient>
<linearGradient id="id2" gradientUnits="userSpaceOnUse" xlink:href="#id0" x1="1398.9" y1="1160.31" x2="613.548" y2="230.976">
</linearGradient>
<linearGradient id="id3" gradientUnits="userSpaceOnUse" xlink:href="#id0" x1="805.595" y1="948.571" x2="21.0238" y2="20.1429">
</linearGradient>
<linearGradient id="id4" gradientUnits="userSpaceOnUse" x1="381.071" y1="958.69" x2="89.0714" y2="613.119">
<stop offset="0" style="stop-color:#EF7F1A"/>
<stop offset="0.831373" style="stop-color:#FFED00"/>
<stop offset="0.94902" style="stop-color:#CC6F3C"/>
<stop offset="1" style="stop-color:#CC6F3C"/>
</linearGradient>
</defs>
<g id="Layer_x0020_1">
<metadata id="CorelCorpID_0Corel-Layer"/>
<path class="fil0" d="M746 677l-341 293c21,-19 37,-44 49,-75 14,-37 20,-83 20,-137 0,-47 -6,-92 -19,-135 -13,-43 -32,-82 -58,-118 -26,-36 -57,-67 -95,-95 -38,-27 -84,-50 -139,-68l-136 -44c-6,-2 -12,-2 -18,1 -1,0 -2,1 -3,2l345 -296c1,-1 2,-2 4,-2 6,-3 12,-3 18,-1l136 44c55,18 101,41 139,68 38,27 69,59 95,95 25,36 45,75 58,118 13,43 19,88 19,135 0,54 -7,100 -20,137 -12,34 -30,60 -53,79z"/>
<path class="fil1" d="M1005 1173c12,-10 22,-22 30,-35 10,-16 18,-34 25,-54 6,-20 11,-41 14,-65 3,-23 4,-48 4,-73 0,-50 -6,-97 -17,-141 -12,-44 -29,-83 -51,-119 -23,-35 -51,-66 -85,-92 -34,-26 -74,-47 -119,-62 -48,-16 -90,-22 -126,-17 -36,4 -66,17 -91,40l345 -295c24,-22 54,-34 90,-39 36,-4 78,2 126,17 45,15 85,35 119,62 34,26 63,57 85,92 23,35 40,75 51,119 11,44 17,90 17,141 0,26 -2,50 -4,73 -3,23 -8,45 -14,65 -6,20 -15,38 -25,54 -9,14 -20,27 -33,37l-341 292z"/>
<path class="fil2" d="M409 739c0,-38 -5,-74 -14,-109 -10,-35 -24,-68 -44,-97 -20,-30 -45,-56 -75,-79 -30,-23 -69,-42 -116,-58l-99 -33 0 538 100 33c44,14 81,21 111,20 30,-1 56,-9 76,-25 20,-16 35,-40 46,-71 10,-31 15,-71 15,-118zm65 18c0,54 -7,100 -20,137 -14,37 -34,65 -60,84 -27,19 -59,30 -98,31 -39,1 -86,-7 -140,-24l-127 -42c-6,-2 -12,-6 -18,-13 -6,-7 -10,-16 -10,-28l0 -583c0,-12 3,-19 10,-22 6,-3 12,-3 18,-1l136 44c55,18 101,41 139,68 38,27 69,59 95,95 25,36 45,75 58,118 13,43 19,88 19,135z"/>
<path class="fil3" d="M1343 884l-333 285c-3,3 -7,6 -10,9 26,30 49,54 68,73 20,18 36,33 48,43 13,10 22,18 29,23 7,5 12,9 15,13 3,4 5,8 6,13 1,5 2,10 2,17 0,5 0,10 -1,13 -1,3 -2,6 -4,8 -1,1 -1,1 -2,2l344 -294c1,0 1,-1 2,-2 2,-2 3,-5 4,-8 1,-4 1,-8 1,-13 0,-7 -1,-12 -2,-17 -1,-5 -3,-9 -6,-13 -3,-4 -8,-8 -15,-13 -7,-5 -17,-13 -29,-23 -13,-10 -29,-25 -48,-43 -20,-19 -42,-43 -68,-73z"/>
<path class="fil2" d="M1015 931c0,-38 -4,-75 -11,-111 -7,-36 -19,-69 -36,-99 -17,-30 -38,-57 -66,-80 -27,-23 -61,-41 -102,-54 -40,-13 -74,-17 -101,-11 -28,6 -50,18 -67,38 -17,19 -29,44 -37,75 -8,31 -11,65 -11,101 0,39 3,77 10,113 7,36 18,69 35,99 16,30 38,57 66,80 27,23 62,41 103,55 41,13 75,17 103,11 28,-6 50,-19 67,-39 17,-20 29,-45 36,-76 7,-31 11,-65 11,-102zm153 430c0,5 0,10 -1,13 -1,3 -2,6 -4,8 -2,2 -3,3 -5,3 -2,1 -3,0 -5,0 -4,-1 -12,-7 -26,-16 -13,-10 -29,-22 -48,-39 -19,-16 -39,-35 -61,-57 -22,-22 -44,-46 -66,-72 -17,6 -39,9 -65,9 -27,0 -58,-6 -94,-18 -48,-16 -89,-37 -124,-63 -35,-27 -63,-57 -85,-93 -22,-35 -38,-75 -49,-119 -10,-44 -16,-91 -16,-142 0,-51 6,-95 18,-132 12,-37 29,-67 53,-88 24,-21 53,-34 89,-38 36,-4 78,2 126,17 45,15 85,35 119,62 34,26 63,57 85,92 23,35 40,75 51,119 11,44 17,90 17,141 0,26 -2,50 -4,73 -3,23 -8,45 -14,65 -6,20 -15,38 -25,54 -10,16 -22,29 -36,40 26,30 49,54 68,73 20,18 36,33 48,43 13,10 22,18 29,23 7,5 12,9 15,13 3,4 5,8 6,13 1,5 2,10 2,17z"/>
<path class="fil4" d="M1015 931c0,-38 -4,-75 -11,-111 -7,-36 -19,-69 -36,-99 -17,-30 -38,-57 -66,-80 -27,-23 -61,-41 -102,-54 -40,-13 -74,-17 -101,-11 -28,6 -50,18 -67,38 -17,19 -29,44 -37,75 -8,31 -11,65 -11,101 0,39 3,77 10,113 7,36 18,69 35,99 16,30 38,57 66,80 27,23 62,41 103,55 41,13 75,17 103,11 28,-6 50,-19 67,-39 17,-20 29,-45 36,-76 7,-31 11,-65 11,-102z"/>
<path class="fil5" d="M61 900l330 -283c1,4 2,8 4,12 9,35 14,72 14,109 0,48 -5,87 -15,118 -10,31 -25,55 -46,71 -20,16 -45,24 -76,25 -31,1 -67,-6 -111,-20l-100 -33z"/>
<path class="fil6" d="M61 900l330 -283c-9,-31 -23,-59 -40,-85 -20,-30 -45,-56 -75,-79 -30,-23 -69,-42 -116,-58l-99 -33 0 538z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.5 KiB