wordpress-markdown-blog-loader 1.7.3__tar.gz → 1.7.4__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.
Files changed (24) hide show
  1. {wordpress_markdown_blog_loader-1.7.3 → wordpress_markdown_blog_loader-1.7.4}/PKG-INFO +2 -2
  2. {wordpress_markdown_blog_loader-1.7.3 → wordpress_markdown_blog_loader-1.7.4}/README.md +1 -1
  3. {wordpress_markdown_blog_loader-1.7.3 → wordpress_markdown_blog_loader-1.7.4}/pyproject.toml +1 -1
  4. {wordpress_markdown_blog_loader-1.7.3 → wordpress_markdown_blog_loader-1.7.4}/src/wordpress_markdown_blog_loader/api.py +24 -12
  5. {wordpress_markdown_blog_loader-1.7.3 → wordpress_markdown_blog_loader-1.7.4}/src/wordpress_markdown_blog_loader/blog.py +9 -0
  6. {wordpress_markdown_blog_loader-1.7.3 → wordpress_markdown_blog_loader-1.7.4}/src/wordpress_markdown_blog_loader/html_to_gutenberg.py +2 -3
  7. {wordpress_markdown_blog_loader-1.7.3 → wordpress_markdown_blog_loader-1.7.4}/src/wordpress_markdown_blog_loader/new.py +20 -17
  8. {wordpress_markdown_blog_loader-1.7.3 → wordpress_markdown_blog_loader-1.7.4}/src/wordpress_markdown_blog_loader.egg-info/PKG-INFO +2 -2
  9. {wordpress_markdown_blog_loader-1.7.3 → wordpress_markdown_blog_loader-1.7.4}/tests/test_html_to_gutenberg.py +5 -1
  10. {wordpress_markdown_blog_loader-1.7.3 → wordpress_markdown_blog_loader-1.7.4}/LICENSE +0 -0
  11. {wordpress_markdown_blog_loader-1.7.3 → wordpress_markdown_blog_loader-1.7.4}/setup.cfg +0 -0
  12. {wordpress_markdown_blog_loader-1.7.3 → wordpress_markdown_blog_loader-1.7.4}/src/wordpress_markdown_blog_loader/__init__.py +0 -0
  13. {wordpress_markdown_blog_loader-1.7.3 → wordpress_markdown_blog_loader-1.7.4}/src/wordpress_markdown_blog_loader/__main__.py +0 -0
  14. {wordpress_markdown_blog_loader-1.7.3 → wordpress_markdown_blog_loader-1.7.4}/src/wordpress_markdown_blog_loader/check_links.py +0 -0
  15. {wordpress_markdown_blog_loader-1.7.3 → wordpress_markdown_blog_loader-1.7.4}/src/wordpress_markdown_blog_loader/download.py +0 -0
  16. {wordpress_markdown_blog_loader-1.7.3 → wordpress_markdown_blog_loader-1.7.4}/src/wordpress_markdown_blog_loader/name_to_email.py +0 -0
  17. {wordpress_markdown_blog_loader-1.7.3 → wordpress_markdown_blog_loader-1.7.4}/src/wordpress_markdown_blog_loader/remove_newlines.py +0 -0
  18. {wordpress_markdown_blog_loader-1.7.3 → wordpress_markdown_blog_loader-1.7.4}/src/wordpress_markdown_blog_loader/upload.py +0 -0
  19. {wordpress_markdown_blog_loader-1.7.3 → wordpress_markdown_blog_loader-1.7.4}/src/wordpress_markdown_blog_loader.egg-info/SOURCES.txt +0 -0
  20. {wordpress_markdown_blog_loader-1.7.3 → wordpress_markdown_blog_loader-1.7.4}/src/wordpress_markdown_blog_loader.egg-info/dependency_links.txt +0 -0
  21. {wordpress_markdown_blog_loader-1.7.3 → wordpress_markdown_blog_loader-1.7.4}/src/wordpress_markdown_blog_loader.egg-info/entry_points.txt +0 -0
  22. {wordpress_markdown_blog_loader-1.7.3 → wordpress_markdown_blog_loader-1.7.4}/src/wordpress_markdown_blog_loader.egg-info/requires.txt +0 -0
  23. {wordpress_markdown_blog_loader-1.7.3 → wordpress_markdown_blog_loader-1.7.4}/src/wordpress_markdown_blog_loader.egg-info/top_level.txt +0 -0
  24. {wordpress_markdown_blog_loader-1.7.3 → wordpress_markdown_blog_loader-1.7.4}/tests/test_blog.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wordpress-markdown-blog-loader
3
- Version: 1.7.3
3
+ Version: 1.7.4
4
4
  Summary: load markdown blogs into wordpress
5
5
  Author-email: Mark van Holsteijn <markvanholsteijn@binx.io>
6
6
  License: APL2
@@ -119,7 +119,7 @@ alias wp-md='docker run \
119
119
  -v $HOME:$HOME \
120
120
  -v $HOME/.wordpress.ini:/root/.wordpress.ini \
121
121
  -v $PWD:/$PWD \
122
- -w $PWD ghcr.io/binxio/wordpress-markdown-blog-loader:1.7.3
122
+ -w $PWD ghcr.io/binxio/wordpress-markdown-blog-loader:1.7.4
123
123
  ```'
124
124
  Assuming that your WordPress app password is stored in the 1password Private vault under the name `wordpress app password`
125
125
 
@@ -68,7 +68,7 @@ alias wp-md='docker run \
68
68
  -v $HOME:$HOME \
69
69
  -v $HOME/.wordpress.ini:/root/.wordpress.ini \
70
70
  -v $PWD:/$PWD \
71
- -w $PWD ghcr.io/binxio/wordpress-markdown-blog-loader:1.7.3
71
+ -w $PWD ghcr.io/binxio/wordpress-markdown-blog-loader:1.7.4
72
72
  ```'
73
73
  Assuming that your WordPress app password is stored in the 1password Private vault under the name `wordpress app password`
74
74
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "wordpress-markdown-blog-loader"
7
- version = "1.7.3"
7
+ version = "1.7.4"
8
8
  authors = [{name = "Mark van Holsteijn", email = "markvanholsteijn@binx.io"}]
9
9
  license = {text = "APL2"}
10
10
  description = "load markdown blogs into wordpress"
@@ -1,12 +1,11 @@
1
1
  import configparser
2
- import json
3
2
  import logging
4
3
  import mimetypes
5
4
  import os
6
5
  import re
7
- import sys
6
+ import subprocess
8
7
  from datetime import datetime
9
- from functools import cache
8
+ from functools import cache, lru_cache
10
9
  from os.path import expanduser
11
10
  from pathlib import Path
12
11
  from typing import List, Dict, Iterator
@@ -26,6 +25,21 @@ def get_default_host() -> Optional[str]:
26
25
  return config.defaults().get("host")
27
26
 
28
27
 
28
+ @lru_cache
29
+ def get_from_1password(password: str) -> str:
30
+ """
31
+ returns the password from 1password vault, if the password has the op:// prefix.
32
+ """
33
+ if not password.startswith("op://"):
34
+ return password
35
+ result = subprocess.run(
36
+ ["op", "read", password],
37
+ check=True,
38
+ capture_output=True,
39
+ )
40
+ return result.stdout.decode("utf-8").rstrip("\n")
41
+
42
+
29
43
  def get_password(host: str) -> Optional[str]:
30
44
  """
31
45
  Returns a password from the environment variable for the specified host.
@@ -46,10 +60,10 @@ def get_password(host: str) -> Optional[str]:
46
60
  'default_password'
47
61
  """
48
62
  h = re.sub(r"[^a-zA-Z-0-9]", "_", host).upper()
49
- if result := os.getenv(f"WP_APP_PASSWORD_{h}"):
50
- return result
63
+ if result := os.getenv(f"WP_APP_PASSWORD_{h}", os.getenv("WP_APP_PASSWORD")):
64
+ return get_from_1password(result)
51
65
 
52
- return os.getenv("WP_APP_PASSWORD")
66
+ return None
53
67
 
54
68
 
55
69
  class WordpressEndpoint:
@@ -290,7 +304,7 @@ class Wordpress(object):
290
304
  self._media: List[Medium] = {}
291
305
  self.headers = {
292
306
  "accept": "application/json",
293
- "User-Agent": "wordpress-blog-uploader/" + self.app_version
307
+ "User-Agent": "wordpress-blog-uploader/" + self.app_version,
294
308
  }
295
309
  self.session = requests.Session()
296
310
 
@@ -436,7 +450,7 @@ class Wordpress(object):
436
450
  @property
437
451
  @cache
438
452
  def industries_taxonomy_by_id(self) -> Dict[str, int]:
439
- return {id: slug for slug, id in self.industries_taxonomy.items()}
453
+ return {id: slug for slug, id in self.industries_taxonomy.items()}
440
454
 
441
455
  @property
442
456
  @cache
@@ -446,7 +460,7 @@ class Wordpress(object):
446
460
  @property
447
461
  @cache
448
462
  def partners_taxonomy_by_id(self) -> Dict[str, int]:
449
- return {id: slug for slug, id in self.partners_taxonomy.items()}
463
+ return {id: slug for slug, id in self.partners_taxonomy.items()}
450
464
 
451
465
  @property
452
466
  @cache
@@ -456,8 +470,7 @@ class Wordpress(object):
456
470
  @property
457
471
  @cache
458
472
  def capabilities_by_id(self) -> Dict[str, int]:
459
- return {id: slug for slug, id in self.capabilities.items()}
460
-
473
+ return {id: slug for slug, id in self.capabilities.items()}
461
474
 
462
475
  @property
463
476
  @cache
@@ -647,7 +660,6 @@ class Wordpress(object):
647
660
  )
648
661
  )
649
662
 
650
-
651
663
  def get_tag_id_by_name(self, tag: str) -> str:
652
664
  if tag in self.tags:
653
665
  return self.tags[tag]
@@ -230,6 +230,14 @@ class Blog(object):
230
230
  def tags(self, tags: list[str]):
231
231
  self.blog.metadata["tags"] = tags
232
232
 
233
+ @property
234
+ def capabilities(self):
235
+ return self.blog.metadata.get("capabilities", [])
236
+
237
+ @capabilities.setter
238
+ def capabilities(self, capabilities: list[str]):
239
+ self.blog.metadata["capabilities"] = capabilities
240
+
233
241
  @property
234
242
  def guid(self):
235
243
  return self.blog.metadata.get("guid")
@@ -401,6 +409,7 @@ class Blog(object):
401
409
  "status": self.status,
402
410
  "author": author.id,
403
411
  "categories": [wp.get_category_id_by_name(c) for c in self.categories],
412
+ "capabilities": [wp.get_capability_id_by_name(c) for c in self.capabilities],
404
413
  "tags": [wp.get_tag_id_by_name(c) for c in self.tags],
405
414
  "acf": {"show_header_image": bool(self.image)},
406
415
  "industries_taxonomy": [wp.get_industry_by_name(c) for c in self.industries],
@@ -24,7 +24,7 @@ def _wrap_paragraph(element):
24
24
 
25
25
 
26
26
  def _wrap_quote(element):
27
- element["class"] = ["wp-block-quote"]
27
+ element["class"] = ["wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"]
28
28
  # Wrap nested elements
29
29
  for child in list(element.contents):
30
30
  if isinstance(child, (NavigableString, Comment)):
@@ -34,8 +34,7 @@ def _wrap_quote(element):
34
34
  # Since _wrap_in_gutenberg_comments returns a string,
35
35
  # we replace the child with a NavigableString of that result
36
36
  wrapped_child = _wrap_in_gutenberg_comments(child)
37
- if wrapped_child != str(child):
38
- child.replace_with(BeautifulSoup(wrapped_child, "html.parser"))
37
+ child.replace_with(BeautifulSoup(wrapped_child, "html.parser"))
39
38
 
40
39
  return f"<!-- wp:quote -->\n{str(element)}\n<!-- /wp:quote -->"
41
40
 
@@ -42,6 +42,7 @@ class ImageType(click.ParamType):
42
42
  @click.option("--email", required=False, help="of the author")
43
43
  @click.option("--image", required=False, type=ImageType(), help="for the banner")
44
44
  @click.option("--image-credits", required=False, type=str, help="for the used image")
45
+ @click.option("--capability", required=False, multiple=True, help="for the used capabilities selection")
45
46
  @click.option(
46
47
  "--brand",
47
48
  type=click.Choice(["xebia.com", "binx.io"]),
@@ -49,12 +50,12 @@ class ImageType(click.ParamType):
49
50
  default="xebia.com",
50
51
  help="of the banner",
51
52
  )
52
- def command(title, subtitle, author, image, brand, email, image_credits):
53
+ def command(title, subtitle, author, image, brand, email, image_credits, capability):
53
54
  """
54
55
  a new frontmatter blog
55
56
 
56
57
  the index.md will be written in a subdirectory with the name of the slug for the blog.
57
- The slug is created from the title. The image will be resized and cropped to 1200x630.
58
+ The slug is created from the title. The image will be resized and cropped to 1440x460.
58
59
  """
59
60
  slug = slugify(title)
60
61
 
@@ -78,6 +79,8 @@ def command(title, subtitle, author, image, brand, email, image_credits):
78
79
  blog.date = (datetime.now().astimezone() + timedelta(days=7)).replace(
79
80
  hour=0, minute=0, second=0, microsecond=0
80
81
  )
82
+ if capability:
83
+ blog.capabilities = list(capability)
81
84
 
82
85
  if not blog.title:
83
86
  click.echo("a title is required", err=True)
@@ -100,26 +103,26 @@ def command(title, subtitle, author, image, brand, email, image_credits):
100
103
 
101
104
  def save_og_image(image: Image, path: Path) -> Path:
102
105
  """
103
- save the image to be the perfect og image size: 1200x630px
106
+ save the image to be the perfect og image size: 1440x460px
104
107
  """
105
108
  width, height = image.size
106
- if width != 1200:
107
- new_height = int(height * 1200 / width)
108
- logging.info("resizing %dx%d to %dx%d", width, height, 1200, new_height)
109
- image = image.resize((1200, new_height))
110
- width = 1200
109
+ if width != 1440:
110
+ new_height = int(height * 1440 / width)
111
+ logging.info("resizing %dx%d to %dx%d", width, height, 1440, new_height)
112
+ image = image.resize((1440, new_height))
113
+ width = 1440
111
114
  width, height = image.size
112
115
 
113
- if height > 630:
114
- logging.info("cropping to maximum height of 630px")
115
- top = int((height - 630) / 2)
116
- bottom = 630 + top
117
- image = image.crop((0, top, 1200, bottom))
116
+ if height > 460:
117
+ logging.info("cropping to maximum height of 460px")
118
+ top = int((height - 460) / 2)
119
+ bottom = 460 + top
120
+ image = image.crop((0, top, 1440, bottom))
118
121
  width, height = image.size
119
122
 
120
- if height < 630:
121
- new_image = Image.new("RGBA", (1200, 630), (255, 0, 0, 0))
122
- new_image.paste(image, (0, int((630 - height) / 2)))
123
+ if height < 460:
124
+ new_image = Image.new("RGBA", (1440, 460), (255, 0, 0, 0))
125
+ new_image.paste(image, (0, int((460 - height) / 2)))
123
126
  image = new_image
124
127
 
125
128
  path.parent.mkdir(exist_ok=True, parents=True)
@@ -144,7 +147,7 @@ def update_banner_command(blog, image, brand):
144
147
  """
145
148
  of the blog.
146
149
 
147
- reads the image, crops it to the 1200x630 dimensions and updates the blog's banner property.
150
+ reads the image, crops it to the 1440x460 dimensions and updates the blog's banner property.
148
151
  Regenerates and updates the og-banner too.
149
152
  """
150
153
  path = Path(blog).joinpath("index.md")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wordpress-markdown-blog-loader
3
- Version: 1.7.3
3
+ Version: 1.7.4
4
4
  Summary: load markdown blogs into wordpress
5
5
  Author-email: Mark van Holsteijn <markvanholsteijn@binx.io>
6
6
  License: APL2
@@ -119,7 +119,7 @@ alias wp-md='docker run \
119
119
  -v $HOME:$HOME \
120
120
  -v $HOME/.wordpress.ini:/root/.wordpress.ini \
121
121
  -v $PWD:/$PWD \
122
- -w $PWD ghcr.io/binxio/wordpress-markdown-blog-loader:1.7.3
122
+ -w $PWD ghcr.io/binxio/wordpress-markdown-blog-loader:1.7.4
123
123
  ```'
124
124
  Assuming that your WordPress app password is stored in the 1password Private vault under the name `wordpress app password`
125
125
 
@@ -97,7 +97,10 @@ class TestGutenbergWrapFunctions(unittest.TestCase):
97
97
  soup = BeautifulSoup("<blockquote>quotie quote</blockquote>", "html.parser")
98
98
  elem = soup.blockquote
99
99
  result = _wrap_quote(elem)
100
- self.assertEqual(result, '<!-- wp:quote -->\n<blockquote class="wp-block-quote">quotie quote</blockquote>\n<!-- /wp:quote -->')
100
+ self.assertEqual(
101
+ result,
102
+ '<!-- wp:quote -->\n<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">quotie quote</blockquote>\n<!-- /wp:quote -->',
103
+ )
101
104
 
102
105
  def test_wrap_quote_nested_elements(self):
103
106
  html = "<blockquote><p>Quote line 1</p><p>Quote line 2</p></blockquote>"
@@ -154,5 +157,6 @@ class TestConvertFunction(unittest.TestCase):
154
157
  self.assertIn("<!-- wp:heading -->", result)
155
158
  self.assertIn("<!-- wp:code -->", result)
156
159
 
160
+
157
161
  if __name__ == "__main__":
158
162
  unittest.main()