server/posts: add preload directive to post HTML
This commit is contained in:
parent
36a614d954
commit
17152f68a4
5 changed files with 86 additions and 65 deletions
|
@ -63,18 +63,17 @@ _apple_touch_startup_images = {
|
|||
|
||||
def _get_html_template(
|
||||
title: str,
|
||||
meta_tags: Dict = {},
|
||||
header_content: str = "",
|
||||
) -> Doc:
|
||||
doc = Doc()
|
||||
doc.asis("<!DOCTYPE html>")
|
||||
with doc.tag("html"):
|
||||
with doc.tag("head"):
|
||||
doc.stag("meta", charset="utf-8")
|
||||
for name, content in {**_default_meta_tags, **meta_tags}.items():
|
||||
for name, content in _default_meta_tags.items():
|
||||
doc.stag("meta", name=name, content=content)
|
||||
with doc.tag("title"):
|
||||
doc.text(title)
|
||||
doc.stag("base", href=util.add_url_prefix())
|
||||
doc.stag(
|
||||
"link",
|
||||
rel="manifest",
|
||||
|
@ -115,6 +114,8 @@ def _get_html_template(
|
|||
f"({k}: {v})" for k, v in media.items()
|
||||
),
|
||||
)
|
||||
doc.stag("base", href=util.add_url_prefix())
|
||||
doc.asis(header_content)
|
||||
with doc.tag("body"):
|
||||
with doc.tag("div", id="top-navigation-holder"):
|
||||
pass
|
||||
|
@ -154,47 +155,73 @@ def get_post_html(
|
|||
) -> rest.Response:
|
||||
try:
|
||||
post = _get_post(params)
|
||||
title = f"{config.config['name']} - post {_get_post_id(params)}"
|
||||
title = f"{config.config['name']} - Post #{_get_post_id(params)}"
|
||||
except posts.InvalidPostIdError:
|
||||
# Return the default template and let the browser JS handle the 404
|
||||
return _get_html_template()
|
||||
|
||||
metadata = {
|
||||
"og:site_name": config.config["name"],
|
||||
"og:url": util.add_url_prefix(f"post/{params['post_id']}"),
|
||||
"og:title": title,
|
||||
"twitter:title": title,
|
||||
"og:type": "article",
|
||||
}
|
||||
# Note: ctx.user will always be the anonymous user
|
||||
if auth.has_privilege(ctx.user, "posts:view"):
|
||||
content_url = util.add_data_prefix(posts.get_post_content_path(post))
|
||||
thumbnail_url = util.add_data_prefix(
|
||||
posts.get_post_thumbnail_path(post)
|
||||
doc = Doc()
|
||||
doc.stag("meta", name="og:site_name", content=config.config["name"])
|
||||
doc.stag(
|
||||
"meta",
|
||||
name="og:url",
|
||||
content=util.add_url_prefix(f"post/{params['post_id']}"),
|
||||
)
|
||||
doc.stag("meta", name="og:title", content=title),
|
||||
doc.stag("meta", name="twitter:title", content=title),
|
||||
doc.stag("meta", name="og:type", content="article"),
|
||||
|
||||
if not auth.anon_has_privilege("posts:view"):
|
||||
return _get_html_template(title=title, header_content=doc.getvalue())
|
||||
|
||||
content_url = util.add_data_prefix(posts.get_post_content_path(post))
|
||||
thumbnail_url = util.add_data_prefix(posts.get_post_thumbnail_path(post))
|
||||
tag_string = " ".join(tag.first_name for tag in post.tags)
|
||||
|
||||
doc.stag("meta", name="og:image:alt", content=tag_string)
|
||||
doc.stag(
|
||||
"meta",
|
||||
name="og:article:published_time",
|
||||
content=post.creation_time.isoformat(),
|
||||
)
|
||||
if post.last_edit_time:
|
||||
doc.stag(
|
||||
"meta",
|
||||
name="og:article:modified_time",
|
||||
content=post.last_edit_time.isoformat(),
|
||||
)
|
||||
metadata["og:article:published_time"] = post.creation_time.isoformat()
|
||||
if post.last_edit_time:
|
||||
metadata[
|
||||
"og:article:modified_time"
|
||||
] = post.last_edit_time.isoformat()
|
||||
metadata["og:image:alt"] = " ".join(
|
||||
tag.first_name for tag in post.tags
|
||||
)
|
||||
if post.type in (model.Post.TYPE_VIDEO):
|
||||
metadata["twitter:card"] = "player"
|
||||
metadata["og:video:url"] = content_url
|
||||
metadata["twitter:player:stream"] = content_url
|
||||
metadata["og:image:url"] = thumbnail_url
|
||||
if post.canvas_width and post.canvas_height:
|
||||
metadata["og:video:width"] = str(post.canvas_width)
|
||||
metadata["og:video:height"] = str(post.canvas_height)
|
||||
metadata["twitter:player:width"] = str(post.canvas_width)
|
||||
metadata["twitter:player:height"] = str(post.canvas_height)
|
||||
else:
|
||||
metadata["twitter:card"] = "summary_large_image"
|
||||
metadata["og:image:url"] = content_url
|
||||
metadata["twitter:image"] = content_url
|
||||
return _get_html_template(title=title, meta_tags=metadata)
|
||||
for tag in post.tags:
|
||||
doc.stag("meta", name="article:tag", content=tag.first_name)
|
||||
if post.type in (model.Post.TYPE_VIDEO,):
|
||||
doc.stag("meta", name="twitter:card", content="player")
|
||||
doc.stag("meta", name="og:video:url", content=content_url)
|
||||
doc.stag("meta", name="twitter:player:stream", content=content_url)
|
||||
doc.stag("meta", name="og:image:url", content=thumbnail_url)
|
||||
if post.canvas_width and post.canvas_height:
|
||||
doc.stag(
|
||||
"meta", name="og:video:width", content=str(post.canvas_width)
|
||||
)
|
||||
doc.stag(
|
||||
"meta", name="og:video:height", content=str(post.canvas_height)
|
||||
)
|
||||
doc.stag(
|
||||
"meta",
|
||||
name="twitter:player:width",
|
||||
content=str(post.canvas_width),
|
||||
)
|
||||
doc.stag(
|
||||
"meta",
|
||||
name="twitter:player:height",
|
||||
content=str(post.canvas_height),
|
||||
)
|
||||
doc.stag("link", name="preload", href=content_url, **{"as": "video"})
|
||||
else:
|
||||
doc.stag("meta", name="twitter:card", content="summary_large_image")
|
||||
doc.stag("meta", name="og:image:url", content=content_url)
|
||||
doc.stag("meta", name="twitter:image", content=content_url)
|
||||
doc.stag("link", name="preload", href=content_url, **{"as": "image"})
|
||||
|
||||
return _get_html_template(title=title, header_content=doc.getvalue())
|
||||
|
||||
|
||||
@rest.routes.get("/html/.*", accept="text/html")
|
||||
|
|
|
@ -106,6 +106,16 @@ def is_valid_token(user_token: Optional[model.UserToken]) -> bool:
|
|||
return True
|
||||
|
||||
|
||||
def anon_has_privilege(privilege_name: str) -> bool:
|
||||
all_ranks = list(RANK_MAP.keys())
|
||||
assert privilege_name in config.config["privileges"]
|
||||
minimal_rank = util.flip(RANK_MAP)[
|
||||
config.config["privileges"][privilege_name]
|
||||
]
|
||||
good_ranks = all_ranks[all_ranks.index(minimal_rank) :]
|
||||
return model.User.RANK_ANONYMOUS in good_ranks
|
||||
|
||||
|
||||
def has_privilege(user: model.User, privilege_name: str) -> bool:
|
||||
assert user
|
||||
all_ranks = list(RANK_MAP.keys())
|
||||
|
|
|
@ -73,11 +73,10 @@ def _get_user(ctx: rest.Context, bump_login: bool) -> Optional[model.User]:
|
|||
|
||||
def process_request(ctx: rest.Context) -> None:
|
||||
""" Bind the user to request. Update last login time if needed. """
|
||||
if ctx.accept == "application/json":
|
||||
bump_login = ctx.get_param_as_bool("bump-login", default=False)
|
||||
auth_user = _get_user(ctx, bump_login)
|
||||
if auth_user:
|
||||
ctx.user = auth_user
|
||||
bump_login = ctx.get_param_as_bool("bump-login", default=False)
|
||||
auth_user = _get_user(ctx, bump_login)
|
||||
if auth_user:
|
||||
ctx.user = auth_user
|
||||
|
||||
|
||||
@rest.middleware.pre_hook
|
||||
|
|
|
@ -22,7 +22,7 @@ def test_get_post_html(
|
|||
):
|
||||
config_injector(
|
||||
{
|
||||
"name": "test installation",
|
||||
"name": "testing",
|
||||
"base_url": "/someprefix",
|
||||
"data_url": "data",
|
||||
}
|
||||
|
@ -32,20 +32,20 @@ def test_get_post_html(
|
|||
post.canvas_height = 1080
|
||||
db.session.add(post)
|
||||
db.session.flush()
|
||||
with patch("szurubooru.func.auth.has_privilege"), patch(
|
||||
with patch("szurubooru.func.auth.anon_has_privilege"), patch(
|
||||
"szurubooru.func.posts.get_post_content_path"
|
||||
), patch("szurubooru.func.posts.get_post_thumbnail_path"):
|
||||
auth.has_privilege.return_value = view_priv
|
||||
auth.anon_has_privilege.return_value = view_priv
|
||||
posts.get_post_content_path.return_value = "content-url"
|
||||
posts.get_post_thumbnail_path.return_value = "thumbnail-url"
|
||||
ret = api.opengraph_api.get_post_html(
|
||||
context_factory(), {"post_id": 1}
|
||||
)
|
||||
|
||||
assert _make_meta_tag("og:site_name", "test installation") in ret
|
||||
assert _make_meta_tag("og:site_name", "testing") in ret
|
||||
assert _make_meta_tag("og:url", "/someprefix/post/1") in ret
|
||||
assert _make_meta_tag("og:title", "test installation - post 1") in ret
|
||||
assert _make_meta_tag("twitter:title", "test installation - post 1") in ret
|
||||
assert _make_meta_tag("og:title", "testing - Post #1") in ret
|
||||
assert _make_meta_tag("twitter:title", "testing - Post #1") in ret
|
||||
assert _make_meta_tag("og:type", "article") in ret
|
||||
assert (
|
||||
bool(
|
||||
|
|
|
@ -14,21 +14,6 @@ def test_process_request_no_header(context_factory):
|
|||
assert ctx.user.name is None
|
||||
|
||||
|
||||
def test_process_request_non_rest(context_factory, user_factory):
|
||||
user = user_factory()
|
||||
ctx = context_factory(
|
||||
headers={"Authorization": "Basic dGVzdFVzZXI6dGVzdFBhc3N3b3Jk"},
|
||||
accept="text/html",
|
||||
)
|
||||
with patch("szurubooru.func.auth.is_valid_password"), patch(
|
||||
"szurubooru.func.users.get_user_by_name"
|
||||
):
|
||||
users.get_user_by_name.return_value = user
|
||||
auth.is_valid_password.return_value = True
|
||||
authenticator.process_request(ctx)
|
||||
assert ctx.user.name is None
|
||||
|
||||
|
||||
def test_process_request_bump_login(context_factory, user_factory):
|
||||
user = user_factory()
|
||||
db.session.add(user)
|
||||
|
|
Loading…
Reference in a new issue