Вынес статику html из футера в конфиг, Вынес меню и приватные линки в апп.конфиг. Поправил отображение title в постах для отображения без тэгов разметки

main
Сергей Ванюшкин 2023-10-07 21:44:33 +03:00
parent 19dec390c3
commit dfea8eff48
9 changed files with 172 additions and 107 deletions

View File

@ -0,0 +1,36 @@
"""empty message
Revision ID: ea0fde3014d7
Revises: 5e6d181b4b74
Create Date: 2023-10-07 14:32:08.410786
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = 'ea0fde3014d7'
down_revision = '5e6d181b4b74'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('site_headers',
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
sa.Column('name', sa.String(length=20), nullable=True),
sa.Column('description', sa.Text(), nullable=True),
sa.Column('content', sa.Text(), nullable=True),
sa.Column('enabled', sa.Boolean(), nullable=True),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('id')
)
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_table('site_headers')
# ### end Alembic commands ###

View File

@ -99,3 +99,16 @@ class PageView(MyAdminView):
form_overrides = dict(text=CKEditorField)
create_template = "admin/edit.html"
edit_template = "admin/edit.html"
class HeadersView(MyAdminView):
column_labels = dict(
name="Название",
description="Описание содержимого",
content="Содержимое включаемое в header",
enabled="Включить код в страницы сайта",
)
column_list = (
"name",
"description",
)

View File

@ -8,7 +8,8 @@ from flask_migrate import Migrate
from flask_security.core import Security
from pyproger.dbase import Role, User, db, user_datastore
from pyproger.dbase.models import Page, Post, Tag
from pyproger.dbase.database import get_headers, get_menu_items
from pyproger.dbase.models import Page, Post, SiteHeaders, Tag
def create_app(test_config=None):
@ -21,11 +22,7 @@ def create_app(test_config=None):
load_dotenv(dotenv_path)
app.config["SECRET_KEY"] = os.getenv("SECRET_KEY")
app.config["SECURITY_PASSWORD_SALT"] = os.getenv("SECURITY_PASSWORD_SALT")
if os.getenv("SQLALCHEMY_DATABASE_URI") is not None:
app.config["SQLALCHEMY_DATABASE_URI"] = os.getenv(
"SQLALCHEMY_DATABASE_URI"
)
app.config["SQLALCHEMY_DATABASE_URI"] = os.getenv("SQLALCHEMY_DATABASE_URI")
else:
app.config.from_mapping(test_config)
@ -50,8 +47,8 @@ def create_app(test_config=None):
admin.init_app(app)
from pyproger.admin.views import (PageView, PostView, RoleView, TagView,
UserView)
from pyproger.admin.views import (HeadersView, PageView, PostView,
RoleView, TagView, UserView)
admin.add_view(
RoleView(
@ -90,7 +87,15 @@ def create_app(test_config=None):
Page,
db.session,
category="Страницы",
name="Страницы блога",
name="Статические страницы блога",
)
)
admin.add_view(
HeadersView(
SiteHeaders,
db.session,
category="Страницы",
name="Включаемые в html заголовки",
)
)
@ -104,6 +109,12 @@ def create_app(test_config=None):
app.register_blueprint(bp_errors)
app.register_blueprint(bp_robots)
with app.app_context():
site_headers = get_headers()
app.config["SITE_HEADERS"] = site_headers
menu_items = get_menu_items()
app.config["MENU_ITEMS"] = menu_items
@security.context_processor
def security_context_processor():
return dict(

View File

@ -1,23 +1,11 @@
import locale
import re
from flask import (
abort,
current_app,
redirect,
render_template,
request,
session,
url_for,
)
from flask import (abort, current_app, redirect, render_template, request,
session, url_for)
from ..dbase.database import (
get_all_posts_by_tag,
get_menu_items,
get_page,
get_paginated_posts,
get_post,
get_tags,
)
from ..dbase.database import (get_all_posts_by_tag, get_page,
get_paginated_posts, get_post, get_tags)
from .blog import bp
locale.setlocale(locale.LC_ALL, "")
@ -33,37 +21,46 @@ def index(page=1):
list_pages = [
x for x in range(1, total_pages + 1) if x >= page - 2 and x <= page + 2
]
menu_items = get_menu_items()
return render_template(
"blog/index.html",
title="pyproger - разговоры про питон",
menu_title="pyproger",
menu_items=menu_items,
title=f'{current_app.config.get("BRAND")} - разговоры про питон',
headers=current_app.config.get("SITE_HEADERS"),
menu_title=current_app.config.get("BRAND"),
menu_items=current_app.config.get("MENU_ITEMS"),
posts=posts,
page=page,
total_pages=total_pages,
list_pages=list_pages,
mylinks=current_app.config.get("MYLINKS"),
copyright=current_app.config.get("COPYRIGHT"),
)
@bp.route("/post/")
@bp.route("/post/<path:slug>")
def post(slug=None):
back_url = session.get("back_url")
if slug is not None:
current_post = get_post(slug)
if current_post is None:
return abort(404)
menu_items = get_menu_items()
TAG_RE = re.compile(r"<[^>]+>")
def remove_tags(text):
return TAG_RE.sub("", text)
title = remove_tags(current_post.Post.title)
return render_template(
"blog/postview.html",
title=f"pyproger - {current_post.Post.title}",
menu_title="pyproger",
menu_items=menu_items,
title=f'{current_app.config.get("BRAND")} - {title}',
headers=current_app.config.get("SITE_HEADERS"),
menu_title=current_app.config.get("BRAND"),
menu_items=current_app.config.get("MENU_ITEMS"),
post=current_post,
back_url=back_url,
mylinks=current_app.config.get("MYLINKS"),
copyright=current_app.config.get("COPYRIGHT"),
)
else:
abort(404)
@ -72,13 +69,15 @@ def post(slug=None):
@bp.route("/tags/")
def get_all_tags():
tags = get_tags()
menu_items = get_menu_items()
return render_template(
"blog/tags.html",
title="pyproger - поиск по тэгу",
menu_title="pyproger",
title=f'{current_app.config.get("BRAND")} - поиск по тэгу',
headers=current_app.config.get("SITE_HEADERS"),
menu_title=current_app.config.get("BRAND"),
tags=tags,
menu_items=menu_items,
menu_items=current_app.config.get("MENU_ITEMS"),
mylinks=current_app.config.get("MYLINKS"),
copyright=current_app.config.get("COPYRIGHT"),
)
@ -89,25 +88,29 @@ def get_posts_by_tag(page=1, tag=None):
tag = request.args.get("tag")
if tag is None:
return redirect(url_for(".get_all_tags"))
per_page = current_app.config.get("POSTS_ON_PAGE")
posts, total_pages = get_all_posts_by_tag(tag, page, per_page)
per_page = current_app.config.get("POSTS_ON_PAGE")
posts, total = get_all_posts_by_tag(tag, page, per_page)
total_pages = total // per_page + [0, 1][total % per_page != 0]
if posts is None:
abort(404)
list_pages = [
x for x in range(1, total_pages + 1) if x >= page - 2 and x <= page + 2
]
menu_items = get_menu_items()
return render_template(
"blog/index.html",
title=f"pyproger - посты по {tag}",
menu_title="pyproger",
menu_items=menu_items,
title=f'{current_app.config.get("BRAND")} - посты по {tag}',
headers=current_app.config.get("SITE_HEADERS"),
menu_title=current_app.config.get("BRAND"),
menu_items=current_app.config.get("MENU_ITEMS"),
posts=posts,
page=page,
total_pages=total_pages,
list_pages=list_pages,
mylinks=current_app.config.get("MYLINKS"),
copyright=current_app.config.get("COPYRIGHT"),
)
@ -116,11 +119,13 @@ def page(slug=None):
page = get_page(slug)
if page is None:
abort(404)
menu_items = get_menu_items()
return render_template(
"blog/page.html",
title=f"pyproger - {page.name}",
menu_title="pyproger",
menu_items=menu_items,
title=f'{current_app.config.get("BRAND")} - {page.name}',
headers=current_app.config.get("SITE_HEADERS"),
menu_title=current_app.config.get("BRAND"),
menu_items=current_app.config.get("MENU_ITEMS"),
content_body=page.text,
mylinks=current_app.config.get("MYLINKS"),
copyright=current_app.config.get("COPYRIGHT"),
)

View File

@ -1,14 +1,28 @@
import os
# Настройки блога
BRAND = "pyproger"
COPYRIGHT = {
"year": "2023",
"name": "Сергей Вaнюшкин",
"link": "https://pi3c.ru",
"city": "г.Нарьян-Мар, Ненецкий А.О.",
}
MYLINKS = (
{"icon": "fab fa-telegram", "link": "https://t.me/pi3c_nao"},
{"icon": "fab fa-vk", "link": "https://m.vk.com/pi3c_nao"},
{"icon": "fab fa-yandex", "link": "mailto:pi3c@yandex.ru"},
{"icon": "fab fa-github", "link": "https://github.com/pi3c"},
{"icon": "fa fa-gitea", "link": "https://git.pi3c.ru"},
)
POSTS_ON_PAGE = 6
# Тема оформления админ панели
FLASK_ADMIN_SWATCH = "slate"
# Тестовый ключ
SECRET_KEY = "Test_secret_key"
# Настройки подключения к бд
SQLALCHEMY_DATABASE_URI = "sqlite:///sqlite.db"
# For debug - show every DB query
SQLALCHEMY_ECHO = False
# Настройки Flask-Security
@ -44,6 +58,3 @@ CKEDITOR_PKG_TYPE = "full"
CKEDITOR_SERVE_LOCAL = True
CKEDITOR_ENABLE_CODESNIPPET = True
CKEDITOR_CODE_THEME = "monokai_sublime"
# Настройки блога
POSTS_ON_PAGE = 6

View File

@ -1,9 +1,5 @@
from datetime import datetime, timezone
from sqlalchemy import func
from . import db
from .models import Page, Post, Tag, User
from .models import Page, Post, SiteHeaders, Tag, User
def get_paginated_posts(page, per_page):
@ -13,11 +9,7 @@ def get_paginated_posts(page, per_page):
.order_by(Post.create_datetime.desc())
.paginate(page=page, per_page=per_page, error_out=True)
)
total_pages = (
all_post_query.total // per_page + [0, 1][all_post_query.total % per_page != 0]
)
return all_post_query, total_pages
return all_post_query, all_post_query.total
def get_post(slug):
@ -71,3 +63,12 @@ def get_posts_for_sitemap():
.all()
)
return posts
def get_headers():
headers = (
db.session.query(SiteHeaders.content)
.filter(SiteHeaders.enabled.is_(True))
.all()
)
return headers

View File

@ -107,3 +107,18 @@ class Page(db.Model):
default=func.now(),
onupdate=func.now(),
)
class SiteHeaders(db.Model):
__tablename__ = "site_headers"
id = Column(
Integer,
primary_key=True,
nullable=False,
unique=True,
autoincrement=True,
)
name = Column(String(20))
description = Column(Text)
content = Column(Text)
enabled = Column(Boolean, default=False)

View File

@ -1,14 +1,14 @@
<!doctype html>
<html lang="{{page_lang}}">
<html lang="ru">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
<title>
{% block title %}
{% endblock title %}
</title>
<title>{% block title %}{% endblock title %}</title>
{% for h in headers %}
{{h.content | safe}}
{% endfor %}
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous">
<!-- Font Awesome -->
@ -67,40 +67,13 @@
<div class="container p-2">
<!-- Section: Social media -->
<section class="mb-2">
<!-- Telegram -->
{% for l in mylinks %}
<a class="btn btn-outline-light btn-floating m-2"
href="https://t.me/pi3c_nao"
href="{{ l.link }}"
role="button"
><i class="fab fa-telegram"></i
></a>
<!-- VK -->
<a class="btn btn-outline-light btn-floating m-2"
href="https://m.vk.com/pi3c_nao"
role="button"
><i class="fab fa-vk"></i
></a>
<!-- Yandex -->
<a class="btn btn-outline-light btn-floating m-2"
href="mailto:pi3c@yandex.ru"
role="button"
><i class="fab fa-yandex"></i
></a>
<!-- Github -->
<a class="btn btn-outline-light btn-floating m-2"
href="https://github.com/pi3c"
role="button"
><i class="fab fa-github"></i
></a>
<!-- Gitea -->
<a class="btn btn-outline-light btn-floating m-2"
href="https://git.pi3c.ru"
role="button"
><i class="fa fa-gitea"></i
><i class="{{ l.icon }}"></i
></a>
{% endfor %}
</section>
<!-- Section: Social media -->
@ -168,10 +141,10 @@
<!-- Copyright -->
<small class="text-center text-body">
&copy; 2023
<a class="link-offset-2 link-underline link-underline-opacity-0 text-white" href="https://pi3c.ru/">Сергей Ванюшкин</a>
&copy; {{ copyright.year}}
<a class="link-offset-2 link-underline link-underline-opacity-0 text-white" href="{{ copyright.link }}">{{ copyright.name}}</a>
<br>
г.Нарьян-Мар Ненецкий А.О
{{copyright.city}}
</small>
<!-- Copyright -->
</footer>