diff --git a/myapp/mutations/tag.py b/myapp/mutations/tag.py
new file mode 100644
index 0000000..015278c
--- /dev/null
+++ b/myapp/mutations/tag.py
@@ -0,0 +1,45 @@
+__author__ = 'RemiZOffAlex'
+__email__ = 'remizoffalex@mail.ru'
+
+import logging
+
+from .. import lib, models
+
+
+log = logging.getLogger(__name__)
+
+
+def tag_as_dict(
+ tag: models.Tag,
+ fields: list = ['id', 'name']
+):
+ """Тег в словарь
+ """
+ def field_pages(tag):
+ # Теги
+ result = []
+ for tagLink in tag.tags:
+ newTag = tagLink.tag.as_dict()
+ result.append(newTag)
+ return result
+
+ def field_user(tag):
+ # Пользователь
+ return tag.user.as_dict()
+
+ funcs = {
+ 'pages': field_pages,
+ 'user': field_user,
+ }
+ result = {}
+
+ for column in tag.__table__.columns:
+ if column.name in fields:
+ result[column.name] = getattr(tag, column.name)
+
+ for field in fields:
+ if field in funcs:
+ func = funcs[field]
+ result[field] = func(tag)
+
+ return result
diff --git a/myapp/ns_api/tag/__init__.py b/myapp/ns_api/tag/__init__.py
index 15b67cb..085e295 100644
--- a/myapp/ns_api/tag/__init__.py
+++ b/myapp/ns_api/tag/__init__.py
@@ -4,7 +4,7 @@ __email__ = 'remizoffalex@mail.ru'
from . import ( # noqa F401
+ common,
note,
page,
- tag
)
diff --git a/myapp/ns_api/tag/tag.py b/myapp/ns_api/tag/common.py
similarity index 85%
rename from myapp/ns_api/tag/tag.py
rename to myapp/ns_api/tag/common.py
index 42353d1..be20a33 100644
--- a/myapp/ns_api/tag/tag.py
+++ b/myapp/ns_api/tag/common.py
@@ -4,6 +4,25 @@ __email__ = 'remizoffalex@mail.ru'
from .. import jsonrpc, login_required
from ... import models
+from ...mutations.tag import tag_as_dict
+
+@jsonrpc.method('tag')
+def tag_id(
+ id: int,
+ fields: list = ['id', 'name']
+) -> dict:
+ """Тег
+ """
+ tag = models.db_session.query(
+ models.Tag
+ ).filter(
+ models.Tag.id == id
+ ).first()
+ if tag is None:
+ raise ValueError
+
+ result = tag_as_dict(tag, fields)
+ return result
@jsonrpc.method('tag.add')
diff --git a/myapp/ns_api/tag/page.py b/myapp/ns_api/tag/page.py
index 4aefa42..a0165ca 100644
--- a/myapp/ns_api/tag/page.py
+++ b/myapp/ns_api/tag/page.py
@@ -62,7 +62,12 @@ def tag_page_delete(tag: int, id: int) -> bool:
@jsonrpc.method('tag.pages')
-def tag_pages_list(id: int, page: int) -> list:
+def tag_pages_list(
+ id: int,
+ page: int = 1,
+ order_by: dict = {'field': 'title', 'order': 'asc'},
+ fields: list = ['id', 'title', 'tags', 'user']
+) -> list:
"""Список статей
"""
tag = models.db_session.query(
@@ -81,9 +86,19 @@ def tag_pages_list(id: int, page: int) -> list:
models.Page
).filter(
models.Page.id.in_(indexes)
- ).order_by(
- models.Page.title.asc()
)
+
+ # Сортировка
+ if order_by['field'] not in ['created', 'id', 'title', 'updated']:
+ raise ValueError
+ if order_by['order'] not in ['asc', 'desc']:
+ raise ValueError
+ field = getattr(models.Page, order_by['field'])
+ order = getattr(field, order_by['order'])
+ pages = pages.order_by(
+ order()
+ )
+
pages = lib.getpage(
pages,
page,
diff --git a/myapp/ns_tag/templates/user/tag.html b/myapp/ns_tag/templates/user/tag.html
deleted file mode 100644
index c9921aa..0000000
--- a/myapp/ns_tag/templates/user/tag.html
+++ /dev/null
@@ -1,103 +0,0 @@
-{% extends "private/skeleton.html" %}
-{% block content %}
-
-{% raw %}
-
-
-Тег {{ tag.name }}
-
-{% endraw %}
-{% include '/user/tag_menu.html' %}
-
-
-
-{% include '/inc/pages.html' %}
-
-
-
-{% endblock %}
-
-{% block breadcrumb %}
-{% raw %}
-
-
- - Список тегов
- - {{ tag.name }}
-
-{% endraw %}
-{% endblock %}
-
-{% block script %}
-
-{% endblock %}
diff --git a/myapp/ns_tag/templates/user/tag_menu.html b/myapp/ns_tag/templates/user/tag_menu.html
deleted file mode 100644
index fe1cade..0000000
--- a/myapp/ns_tag/templates/user/tag_menu.html
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
diff --git a/myapp/ns_tag/templates/user/tag_notes.html b/myapp/ns_tag/templates/user/tag_notes.html
deleted file mode 100644
index 05ef41e..0000000
--- a/myapp/ns_tag/templates/user/tag_notes.html
+++ /dev/null
@@ -1,105 +0,0 @@
-{% extends "private/skeleton.html" %}
-{% block content %}
-
-{% raw %}
-
-
-Тег {{ tag.name }}
-
-{% endraw %}
-
-{% include 'user/tag_menu.html' %}
-
-
-
-{% include '/inc/notes.html' %}
-
-
-
-{% endblock %}
-
-{% block breadcrumb %}
-{% raw %}
-
-
- - Список тегов
- - {{ tag.name }}
- - Заметки с тегом
-
-{% endraw %}
-{% endblock %}
-
-{% block script %}
-
-
-
-{% endblock %}
diff --git a/myapp/ns_tag/templates/user/tags.html b/myapp/ns_tag/templates/user/tags.html
deleted file mode 100644
index bd2b9b8..0000000
--- a/myapp/ns_tag/templates/user/tags.html
+++ /dev/null
@@ -1,115 +0,0 @@
-{% extends "private/skeleton.html" %}
-{% block content %}
-
-
-
-Список тегов
-
-
-{% raw %}
-
-
-
-{% endraw %}
-
-{% endblock %}
-
-{% block breadcrumb %}
-
-
- - Список тегов
-
-{% endblock %}
-
-{% block script %}
-
-{% endblock %}
diff --git a/myapp/ns_tag/views_user.py b/myapp/ns_tag/views_user.py
index 2987b92..b787e32 100644
--- a/myapp/ns_tag/views_user.py
+++ b/myapp/ns_tag/views_user.py
@@ -12,7 +12,7 @@ def tags():
"""
pagedata = {}
pagedata['title'] = 'Список меток - ' + app.config['TITLE']
- body = render_template('user/tags.html', pagedata=pagedata)
+ body = render_template('/private/skeleton.html', pagedata=pagedata)
return body
@@ -32,15 +32,8 @@ def tag_id(id):
tag.name,
app.config['TITLE']
)
- pagedata['tag'] = tag.as_dict()
- pagedata['pagination'] = {
- "page": 1,
- "per_page": app.config['ITEMS_ON_PAGE'],
- "size": 0
- }
-
- body = render_template('user/tag.html', pagedata=pagedata)
+ body = render_template('/private/skeleton.html', pagedata=pagedata)
return body
@@ -60,13 +53,6 @@ def tag_notes(id):
tag.name,
app.config['TITLE']
)
- pagedata['tag'] = tag.as_dict()
- pagedata['pagination'] = {
- "page": 1,
- "per_page": app.config['ITEMS_ON_PAGE'],
- "size": 0
- }
-
- body = render_template('user/tag_notes.html', pagedata=pagedata)
+ body = render_template('/private/skeleton.html', pagedata=pagedata)
return body
diff --git a/myapp/templates/error.html b/myapp/templates/error.html
index 35737a7..4720bee 100644
--- a/myapp/templates/error.html
+++ b/myapp/templates/error.html
@@ -1,4 +1,8 @@
-{% extends "skeleton.html" %}
+{% if user %}
+{% extends "/public/skeleton.html" %}
+{% else %}
+{% extends "/private/skeleton.html" %}
+{% endif %}
{% block content %}
{{ error_code }}: {{ error_message }}
diff --git a/myapp/templates/public/domains/tag/inc.j2 b/myapp/templates/public/domains/tag/inc.j2
index d39bc14..8b47567 100644
--- a/myapp/templates/public/domains/tag/inc.j2
+++ b/myapp/templates/public/domains/tag/inc.j2
@@ -1,3 +1,5 @@
+{% include '/public/domains/tag/menu.js' %}
+{% include '/public/domains/tag/pages.js' %}
{% include '/public/domains/tag/tag.js' %}
{% include '/public/domains/tag/tags.js' %}
@@ -5,6 +7,8 @@ Object.assign(
routes,
{
"/tag/:id": layout_decorator(Tag),
+ "/tag/:id/pages": layout_decorator(TagPages),
+ "/tag/:id/pages/:page": layout_decorator(TagPages),
"/tags": layout_decorator(Tags),
}
);
diff --git a/myapp/templates/public/domains/tag/menu.js b/myapp/templates/public/domains/tag/menu.js
new file mode 100644
index 0000000..dd59060
--- /dev/null
+++ b/myapp/templates/public/domains/tag/menu.js
@@ -0,0 +1,45 @@
+function MenuTag() {
+ let data = {
+ menuitem: null,
+ tag: null,
+ };
+ function button_common() {
+ if (data.menuitem===null) {
+ return {tag: '<', children: '
'};
+ } else {
+ return m(m.route.Link, {class: "btn btn-outline-secondary me-2 text-decoration-none", href: `/tag/${data.tag.id}`, title: data.tag.name}, m('i', {class: 'fa fa-bars'}))
+ }
+ };
+ function button_pages() {
+ if (data.menuitem==='pages') {
+ return {tag: '<', children: 'Статьи
'};
+ } else {
+ return m(m.route.Link, {class: "btn btn-outline-secondary me-2 text-decoration-none", href: `/tag/${data.tag.id}/pages`}, 'Статьи')
+ }
+ };
+ return {
+ oninit: function(vnode) {
+ console.log('MenuTag.oninit');
+ for (let key in vnode.attrs){
+ data[key] = vnode.attrs[key];
+ };
+ },
+ onupdate: function(vnode) {
+ console.log('MenuTag.onupdate');
+ for (let key in vnode.attrs){
+ data[key] = vnode.attrs[key];
+ };
+ },
+ view: function(vnode) {
+ console.log('MenuTag.view');
+ if (data.tag!=null) {
+ return m('div', {class: 'row'},
+ m('div', {class: 'col py-2'}, [
+ button_common(),
+ button_pages(),
+ ]),
+ );
+ };
+ }
+ };
+};
diff --git a/myapp/templates/public/domains/tag/pages.js b/myapp/templates/public/domains/tag/pages.js
new file mode 100644
index 0000000..1ca5adc
--- /dev/null
+++ b/myapp/templates/public/domains/tag/pages.js
@@ -0,0 +1,162 @@
+function TagPages() {
+ let data = {
+ filter: PanelFilter(),
+ order_by: PanelOrderBy({
+ field: 'title',
+ fields: [
+ {value: 'id', text: 'ID'},
+ {value: 'title', text: 'заголовку'},
+ {value: 'created', text: 'дате создания'},
+ {value: 'updated', text: 'дате обновления'}
+ ],
+ clickHandler: pages_get,
+ order: 'asc',
+ }),
+ tag: null,
+ raw_pages: [],
+ get pages() {
+ let result = data.raw_pages.filter(page_filter);
+ return result;
+ },
+ pagination: {
+ page: 1,
+ size: 0,
+ prefix_url: '/pages'
+ },
+ };
+ function breadcrumbs_render() {
+ let result = m('ul', {class: 'breadcrumb mt-2'}, [
+ m('li', {class: 'breadcrumb-item'}, m(m.route.Link, {href: '/'}, m('i', {class: 'fa fa-home'}))),
+ m('li', {class: 'breadcrumb-item'}, m(m.route.Link, {href: '/tags'}, 'Список тегов')),
+ m('li', {class: 'breadcrumb-item'}, m(m.route.Link, {href: `/tag/${data.tag.id}`}, data.tag.name)),
+ m('li', {class: 'breadcrumb-item active'}, 'Список статей'),
+ ]);
+ return result;
+ };
+ function page_filter(page) {
+ let filter = data.filter.data;
+ let value = filter.value;
+ if ( value.length<1 ) {
+ return true;
+ }
+ if ( page.title.toLowerCase().includes(value.toLowerCase()) ) {
+ return true;
+ }
+ return false;
+ };
+ function tag_get(id) {
+ m.request({
+ url: '/api',
+ method: "POST",
+ body: {
+ "jsonrpc": "2.0",
+ "method": 'tag',
+ "params": {
+ "id": id
+ },
+ "id": get_id()
+ }
+ }).then(
+ function(response) {
+ if ('result' in response) {
+ data.tag = response['result'];
+ data.pagination.prefix_url = `/tag/${data.tag.id}/pages`;
+ document.title = `Статьи с тегом [${data.tag.name}`;
+ pages_get();
+ }
+ }
+ );
+ };
+ function pages_get() {
+ m.request({
+ url: '/api',
+ method: "POST",
+ body: [
+ {
+ "jsonrpc": "2.0",
+ "method": 'tag.pages',
+ "params": {
+ "id": data.tag.id,
+ "page": data.pagination.page,
+ "order_by": data.order_by.value,
+ "fields": ["id", "title", "tags"]
+ },
+ "id": get_id()
+ },
+ {
+ "jsonrpc": "2.0",
+ "method": 'tag.pages.count',
+ "params": {
+ "id": data.tag.id,
+ },
+ "id": get_id()
+ }
+ ]
+
+ }).then(
+ function(response) {
+ if ('result' in response[0]) {
+ data.raw_pages = response[0]['result'];
+ }
+ if ('result' in response[1]) {
+ data.pagination.size = response[1]['result'];
+ }
+ }
+ );
+ }
+ return {
+ oninit: function(vnode) {
+ console.log('TagPages.oninit');
+ if (vnode.attrs.page!==undefined) {
+ data.pagination.page = Number(vnode.attrs.page);
+ };
+ tag_get(vnode.attrs.id);
+ },
+ onbeforeupdate: function(vnode) {
+ console.log('TagPages.onbeforeupdate');
+ if (vnode.attrs.page!==undefined) {
+ if (data.pagination.page.toString() != vnode.attrs.page) {
+ data.pagination.page = Number(vnode.attrs.page);
+ pages_get();
+ }
+ };
+ },
+ view: function(vnode) {
+ console.log('TagPages.view');
+ result = [];
+ if (data.tag!=null) {
+ result.push(
+ breadcrumbs_render(),
+ m('div', {class: 'row'},
+ m('div', {class: 'col h1 py-2'}, [
+ m('div', {class: "btn-group btn-group-lg me-2"}, [
+ m(m.route.Link, {class: "btn btn-outline-secondary", href: `/tag/${data.tag.id}`, title: "Вернуться"}, m('i', {class: "fa fa-chevron-left"})),
+ m('button', {type: "button", class: "btn btn-outline-secondary", onclick: function() { panel_show(data.filter.data) }},
+ m('i', {class: "fa fa-filter"})
+ ),
+ m('button', {type: "button", class: "btn btn-outline-secondary", onclick: function() { panel_show(data.order_by.data) }},
+ m('i', {class: "fa fa-sort-alpha-asc"})
+ )
+ ]),
+ `Статьи с тегом [${data.tag.name}]`
+ ]),
+ m('hr'),
+ )
+ );
+
+ // result.push(m(MenuTag, {menuitem: 'pages', tag: data.tag}));
+ result.push({tag: MenuTag, attrs: {menuitem: 'pages', tag: data.tag}});
+
+ result.push(m(data.filter));
+ result.push(m(data.order_by));
+ result.push(m(Pagination, data.pagination));
+ if (data.pages.length>0) {
+ result.push(m(ComponentPages, {pages: data.pages}));
+ result.push(m(Pagination, data.pagination));
+ };
+ result.push(breadcrumbs_render());
+ };
+ return result;
+ }
+ }
+};
diff --git a/myapp/templates/public/domains/tag/tag.js b/myapp/templates/public/domains/tag/tag.js
index b68817e..964d105 100644
--- a/myapp/templates/public/domains/tag/tag.js
+++ b/myapp/templates/public/domains/tag/tag.js
@@ -58,17 +58,6 @@ function Tag() {
// result.push(m(MenuTag, {"tag1": data.tag}));
result.push({ tag: MenuTag, attrs: { tag: data.tag } });
- result.push(
- m('div', { class: 'row' }, [
- m('div', { class: "col-md-4 py-2" },
- m(m.route.Link, { class: "btn btn-outline-secondary btn-lg w-100", href: `/tag/${data.tag.id}/notes` }, 'Заметки с тегом'),
- ),
- m('div', { class: "col-md-4 py-2" },
- m(m.route.Link, { class: "btn btn-outline-secondary btn-lg w-100", href: `/tag/${data.tag.id}/pages` }, 'Статьи с тегом'),
- ),
- ])
- );
-
result.push(
m('div', { class: 'row' },
m('div', { class: "col py-2" }, m.trust(data.tag.description)),