platzky 0.2.18__tar.gz → 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {platzky-0.2.18 → platzky-0.3.0}/PKG-INFO +1 -2
- platzky-0.3.0/platzky/plugin_loader.py +43 -0
- {platzky-0.2.18 → platzky-0.3.0}/pyproject.toml +3 -4
- platzky-0.2.18/platzky/plugin_loader.py +0 -81
- platzky-0.2.18/platzky/plugins/google-tag-manager/entrypoint.py +0 -30
- platzky-0.2.18/platzky/plugins/redirections/entrypoint.py +0 -64
- {platzky-0.2.18 → platzky-0.3.0}/README.md +0 -0
- {platzky-0.2.18 → platzky-0.3.0}/platzky/__init__.py +0 -0
- {platzky-0.2.18 → platzky-0.3.0}/platzky/blog/__init__.py +0 -0
- {platzky-0.2.18 → platzky-0.3.0}/platzky/blog/blog.py +0 -0
- {platzky-0.2.18 → platzky-0.3.0}/platzky/blog/comment_form.py +0 -0
- {platzky-0.2.18 → platzky-0.3.0}/platzky/config.py +0 -0
- {platzky-0.2.18 → platzky-0.3.0}/platzky/db/__init__.py +0 -0
- {platzky-0.2.18 → platzky-0.3.0}/platzky/db/db.py +0 -0
- {platzky-0.2.18 → platzky-0.3.0}/platzky/db/db_loader.py +0 -0
- {platzky-0.2.18 → platzky-0.3.0}/platzky/db/google_json_db.py +0 -0
- {platzky-0.2.18 → platzky-0.3.0}/platzky/db/graph_ql_db.py +0 -0
- {platzky-0.2.18 → platzky-0.3.0}/platzky/db/json_db.py +0 -0
- {platzky-0.2.18 → platzky-0.3.0}/platzky/db/json_file_db.py +0 -0
- {platzky-0.2.18 → platzky-0.3.0}/platzky/locale/en/LC_MESSAGES/messages.po +0 -0
- {platzky-0.2.18 → platzky-0.3.0}/platzky/locale/pl/LC_MESSAGES/messages.po +0 -0
- {platzky-0.2.18 → platzky-0.3.0}/platzky/models.py +0 -0
- {platzky-0.2.18 → platzky-0.3.0}/platzky/platzky.py +0 -0
- {platzky-0.2.18 → platzky-0.3.0}/platzky/seo/seo.py +0 -0
- {platzky-0.2.18 → platzky-0.3.0}/platzky/static/blog.css +0 -0
- {platzky-0.2.18 → platzky-0.3.0}/platzky/static/styles.css +0 -0
- {platzky-0.2.18 → platzky-0.3.0}/platzky/templates/404.html +0 -0
- {platzky-0.2.18 → platzky-0.3.0}/platzky/templates/base.html +0 -0
- {platzky-0.2.18 → platzky-0.3.0}/platzky/templates/blog.html +0 -0
- {platzky-0.2.18 → platzky-0.3.0}/platzky/templates/body_meta.html +0 -0
- {platzky-0.2.18 → platzky-0.3.0}/platzky/templates/dynamic_css.html +0 -0
- {platzky-0.2.18 → platzky-0.3.0}/platzky/templates/feed.xml +0 -0
- {platzky-0.2.18 → platzky-0.3.0}/platzky/templates/head_meta.html +0 -0
- {platzky-0.2.18 → platzky-0.3.0}/platzky/templates/page.html +0 -0
- {platzky-0.2.18 → platzky-0.3.0}/platzky/templates/post.html +0 -0
- {platzky-0.2.18 → platzky-0.3.0}/platzky/templates/robots.txt +0 -0
- {platzky-0.2.18 → platzky-0.3.0}/platzky/templates/sitemap.xml +0 -0
- {platzky-0.2.18 → platzky-0.3.0}/platzky/www_handler.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: platzky
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Not only blog engine
|
|
5
5
|
License: MIT
|
|
6
6
|
Requires-Python: >=3.10,<4.0
|
|
@@ -19,7 +19,6 @@ Requires-Dist: aiohttp (>=3.9.5,<4.0.0)
|
|
|
19
19
|
Requires-Dist: google-cloud-storage (>=2.5.0,<3.0.0)
|
|
20
20
|
Requires-Dist: gql (>=3.4.0,<4.0.0)
|
|
21
21
|
Requires-Dist: humanize (>=4.9.0,<5.0.0)
|
|
22
|
-
Requires-Dist: platzky-sendmail (>=0.1.1,<0.2.0)
|
|
23
22
|
Requires-Dist: pydantic (>=2.7.1,<3.0.0)
|
|
24
23
|
Description-Content-Type: text/markdown
|
|
25
24
|
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import importlib.util
|
|
2
|
+
import logging
|
|
3
|
+
|
|
4
|
+
logger = logging.getLogger(__name__)
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class PluginError(Exception):
|
|
8
|
+
pass
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def find_plugin(plugin_name):
|
|
12
|
+
"""Find plugin by name and return it as module.
|
|
13
|
+
:param plugin_name: name of plugin to find
|
|
14
|
+
:raises PluginError: if plugin cannot be imported
|
|
15
|
+
:return: module of plugin
|
|
16
|
+
"""
|
|
17
|
+
try:
|
|
18
|
+
return importlib.import_module(f"platzky_{plugin_name}")
|
|
19
|
+
except ImportError as e:
|
|
20
|
+
raise PluginError(
|
|
21
|
+
f"Plugin {plugin_name} not found. Ensure it's installed and follows "
|
|
22
|
+
f"the 'platzky_<plugin_name>' naming convention"
|
|
23
|
+
) from e
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def plugify(app):
|
|
27
|
+
"""Load plugins and run their entrypoints.
|
|
28
|
+
:param app: Flask app
|
|
29
|
+
:return: Flask app
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
plugins_data = app.db.get_plugins_data()
|
|
33
|
+
|
|
34
|
+
for plugin_data in plugins_data:
|
|
35
|
+
plugin_config = plugin_data["config"]
|
|
36
|
+
plugin_name = plugin_data["name"]
|
|
37
|
+
try:
|
|
38
|
+
plugin = find_plugin(plugin_name)
|
|
39
|
+
plugin.process(app, plugin_config)
|
|
40
|
+
except Exception as e:
|
|
41
|
+
raise PluginError(f"Error processing plugin {plugin_name}: {e}") from e
|
|
42
|
+
|
|
43
|
+
return app
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "platzky"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.3.0"
|
|
4
4
|
description = "Not only blog engine"
|
|
5
5
|
authors = []
|
|
6
6
|
license = "MIT"
|
|
@@ -18,7 +18,6 @@ Flask-Minify = "^0.42"
|
|
|
18
18
|
google-cloud-storage = "^2.5.0"
|
|
19
19
|
humanize = "^4.9.0"
|
|
20
20
|
pydantic = "^2.7.1"
|
|
21
|
-
platzky-sendmail = "^0.1.1"
|
|
22
21
|
|
|
23
22
|
[tool.poetry.group.dev.dependencies]
|
|
24
23
|
pytest = "^8.2.1"
|
|
@@ -73,14 +72,14 @@ target-version = ["py310"]
|
|
|
73
72
|
line-length = 100
|
|
74
73
|
target-version = "py310"
|
|
75
74
|
show-fixes = true
|
|
76
|
-
select = [
|
|
75
|
+
lint.select = [
|
|
77
76
|
"I", # isort
|
|
78
77
|
"F", # Pyflakes
|
|
79
78
|
"E", # pycodestyle Error
|
|
80
79
|
"W", # pycodestyle Warning
|
|
81
80
|
"RUF", # Ruff-specific rules
|
|
82
81
|
]
|
|
83
|
-
ignore = []
|
|
82
|
+
lint.ignore = []
|
|
84
83
|
|
|
85
84
|
[tool.pytest.ini_options]
|
|
86
85
|
markers = [
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
import importlib.util
|
|
2
|
-
import logging
|
|
3
|
-
import os
|
|
4
|
-
import sys
|
|
5
|
-
from os.path import abspath, dirname
|
|
6
|
-
|
|
7
|
-
logger = logging.getLogger(__name__)
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
class PluginError(Exception):
|
|
11
|
-
pass
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
# TODO remove find_local_plugin after all plugins will be extracted
|
|
15
|
-
def find_local_plugin(plugin_name):
|
|
16
|
-
"""Find plugin by name and return it as module.
|
|
17
|
-
:param plugin_name: name of plugin to find
|
|
18
|
-
:return: module of plugin
|
|
19
|
-
"""
|
|
20
|
-
plugins_dir = os.path.join(dirname(abspath(__file__)), "plugins")
|
|
21
|
-
module_name = plugin_name.removesuffix(".py")
|
|
22
|
-
spec = importlib.util.spec_from_file_location(
|
|
23
|
-
module_name, os.path.join(plugins_dir, plugin_name, "entrypoint.py")
|
|
24
|
-
)
|
|
25
|
-
assert spec is not None
|
|
26
|
-
plugin = importlib.util.module_from_spec(spec)
|
|
27
|
-
sys.modules[module_name] = plugin
|
|
28
|
-
assert spec.loader is not None
|
|
29
|
-
spec.loader.exec_module(plugin)
|
|
30
|
-
return plugin
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
def find_installed_plugin(plugin_name):
|
|
34
|
-
"""Find plugin by name and return it as module.
|
|
35
|
-
:param plugin_name: name of plugin to find
|
|
36
|
-
:raises PluginError: if plugin cannot be imported
|
|
37
|
-
:return: module of plugin
|
|
38
|
-
"""
|
|
39
|
-
try:
|
|
40
|
-
return importlib.import_module(f"platzky_{plugin_name}")
|
|
41
|
-
except ImportError as e:
|
|
42
|
-
raise PluginError(
|
|
43
|
-
f"Plugin {plugin_name} not found. Ensure it's installed and follows "
|
|
44
|
-
f"the 'platzky_<plugin_name>' naming convention"
|
|
45
|
-
) from e
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
def find_plugin(plugin_name):
|
|
49
|
-
"""Find plugin by name and return it as module.
|
|
50
|
-
:param plugin_name: name of plugin to find
|
|
51
|
-
:raises PluginError: if plugin cannot be found or imported
|
|
52
|
-
:return: module of plugin
|
|
53
|
-
"""
|
|
54
|
-
plugin = None
|
|
55
|
-
try:
|
|
56
|
-
plugin = find_local_plugin(plugin_name)
|
|
57
|
-
except FileNotFoundError:
|
|
58
|
-
logger.info(f"Local plugin {plugin_name} not found, trying installed version")
|
|
59
|
-
plugin = find_installed_plugin(plugin_name)
|
|
60
|
-
|
|
61
|
-
return plugin
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
def plugify(app):
|
|
65
|
-
"""Load plugins and run their entrypoints.
|
|
66
|
-
:param app: Flask app
|
|
67
|
-
:return: Flask app
|
|
68
|
-
"""
|
|
69
|
-
|
|
70
|
-
plugins_data = app.db.get_plugins_data()
|
|
71
|
-
|
|
72
|
-
for plugin_data in plugins_data:
|
|
73
|
-
plugin_config = plugin_data["config"]
|
|
74
|
-
plugin_name = plugin_data["name"]
|
|
75
|
-
try:
|
|
76
|
-
plugin = find_plugin(plugin_name)
|
|
77
|
-
plugin.process(app, plugin_config)
|
|
78
|
-
except Exception as e:
|
|
79
|
-
raise PluginError(f"Error processing plugin {plugin_name}: {e}") from e
|
|
80
|
-
|
|
81
|
-
return app
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
def process(app, plugin_config):
|
|
2
|
-
gtm_id = plugin_config["ID"]
|
|
3
|
-
|
|
4
|
-
head_code = (
|
|
5
|
-
"""<!-- Google Tag Manager -->
|
|
6
|
-
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
|
|
7
|
-
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
|
|
8
|
-
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
|
|
9
|
-
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
|
|
10
|
-
})(window,document,'script','dataLayer','"""
|
|
11
|
-
+ gtm_id
|
|
12
|
-
+ """');</script>
|
|
13
|
-
<!-- End Google Tag Manager -->
|
|
14
|
-
"""
|
|
15
|
-
)
|
|
16
|
-
app.add_dynamic_head(head_code)
|
|
17
|
-
|
|
18
|
-
body = (
|
|
19
|
-
"""<!-- Google Tag Manager (noscript) -->
|
|
20
|
-
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id="""
|
|
21
|
-
+ gtm_id
|
|
22
|
-
+ """
|
|
23
|
-
"
|
|
24
|
-
height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
|
|
25
|
-
<!-- End Google Tag Manager (noscript) -->
|
|
26
|
-
"""
|
|
27
|
-
)
|
|
28
|
-
app.add_dynamic_body(body)
|
|
29
|
-
|
|
30
|
-
return app
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
from flask import redirect
|
|
2
|
-
from gql import gql
|
|
3
|
-
from pydantic import BaseModel
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
def json_db_get_redirections(self):
|
|
7
|
-
return self.data.get("redirections", {})
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
def json_file_db_get_redirections(self):
|
|
11
|
-
return json_db_get_redirections(self)
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
def google_json_db_get_redirections(self):
|
|
15
|
-
return self.data.get("redirections", {})
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
def graph_ql_db_get_redirections(self):
|
|
19
|
-
redirections = gql(
|
|
20
|
-
"""
|
|
21
|
-
query MyQuery{
|
|
22
|
-
redirections(stage: PUBLISHED){
|
|
23
|
-
source
|
|
24
|
-
destination
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
"""
|
|
28
|
-
)
|
|
29
|
-
return {
|
|
30
|
-
x["source"]: x["destination"] for x in self.client.execute(redirections)["redirections"]
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
class Redirection(BaseModel):
|
|
35
|
-
source: str
|
|
36
|
-
destiny: str
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
def parse_redirections(config: dict[str, str]) -> list[Redirection]:
|
|
40
|
-
return [Redirection(source=source, destiny=destiny) for source, destiny in config.items()]
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
def setup_routes(app, redirections):
|
|
44
|
-
for redirection in redirections:
|
|
45
|
-
func = redirect_with_name(
|
|
46
|
-
redirection.destiny,
|
|
47
|
-
code=301,
|
|
48
|
-
name=f"{redirection.source}-{redirection.destiny}",
|
|
49
|
-
)
|
|
50
|
-
app.route(rule=redirection.source)(func)
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
def redirect_with_name(destiny, code, name):
|
|
54
|
-
def named_redirect(*args, **kwargs):
|
|
55
|
-
return redirect(destiny, code, *args, **kwargs)
|
|
56
|
-
|
|
57
|
-
named_redirect.__name__ = name
|
|
58
|
-
return named_redirect
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
def process(app, config: dict[str, str]) -> object:
|
|
62
|
-
redirections = parse_redirections(config)
|
|
63
|
-
setup_routes(app, redirections)
|
|
64
|
-
return app
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|