server/posts: generate appropriate URIs using config parameters only
This commit is contained in:
parent
299ebfc4c8
commit
36a614d954
22 changed files with 314 additions and 187 deletions
|
@ -20,7 +20,11 @@ http {
|
|||
keepalive_timeout 65;
|
||||
|
||||
proxy_cache_path /tmp/nginx-cache
|
||||
levels=1:2 keys_zone=spa_cache:1m max_size=50m inactive=60m use_temp_path=off;
|
||||
levels=1:2
|
||||
keys_zone=spa_cache:4m
|
||||
max_size=50m
|
||||
inactive=60m
|
||||
use_temp_path=off;
|
||||
|
||||
upstream backend {
|
||||
server __BACKEND__:6666;
|
||||
|
@ -88,6 +92,9 @@ http {
|
|||
location / {
|
||||
tcp_nodelay on;
|
||||
|
||||
# remove unneeded auth headers to improve caching
|
||||
proxy_set_header Authorization "";
|
||||
|
||||
proxy_cache spa_cache;
|
||||
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
|
||||
proxy_cache_background_update on;
|
||||
|
|
|
@ -80,8 +80,8 @@ user@host:szuru$ docker-compose down
|
|||
|
||||
If you want to host your website on, (`http://example.com/`) but want
|
||||
to serve the images on a different domain, (`http://static.example.com/`)
|
||||
then you can run the backend container with an additional environment
|
||||
variable `DATA_URL=http://static.example.com/`. Make sure that this
|
||||
then you can configure the `data_url` variable in your `config.yaml`
|
||||
(ex: `data_url: http://static.example.com/`). Make sure that this
|
||||
additional host has access contents to the `/data` volume mounted in the
|
||||
backend.
|
||||
|
||||
|
@ -89,12 +89,9 @@ user@host:szuru$ docker-compose down
|
|||
|
||||
Some users may wish to access the service at a different base URI, such
|
||||
as `http://example.com/szuru/`, commonly when sharing multiple HTTP
|
||||
services on one domain using a reverse proxy. This can be configured in
|
||||
either of the following ways:
|
||||
|
||||
- Set the 'domain' value in `config.yaml` to include the prefix, i.e.:
|
||||
`domain: "http://example.com/szuru" # omit trailing slash`
|
||||
- Configure the reverse proxy to pass the `X-Forwarded-Prefix` header.
|
||||
services on one domain using a reverse proxy. For szurubooru to handle
|
||||
links properly, you must configure the reverse proxy to pass the new
|
||||
URL prefix (in this case `/szuru`) in the `X-Forwarded-Prefix` header.
|
||||
|
||||
Note that this will require a reverse proxy to function. You should set
|
||||
your reverse proxy to proxy `http(s)://example.com/szuru` to
|
||||
|
@ -111,7 +108,7 @@ user@host:szuru$ docker-compose down
|
|||
proxy_set_header Connection "upgrade";
|
||||
proxy_set_header X-Forwarded-Prefix /szuru;
|
||||
|
||||
// optional...
|
||||
# optional...
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Scheme $scheme;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
|
|
|
@ -3,11 +3,28 @@
|
|||
|
||||
# shown in the website title and on the front page
|
||||
name: szurubooru
|
||||
# full url to the homepage of this szurubooru site, with no trailing slash
|
||||
domain: # example: http://example.com
|
||||
# used to salt the users' password hashes and generate filenames for static content
|
||||
secret: change
|
||||
|
||||
# set to the root web address for your instance
|
||||
# example values:
|
||||
# - `/` (default) is used when the domain is unknown
|
||||
# - `https://szuru.example.com/` if you know the specific domain
|
||||
# and is required if you want email-based password reset
|
||||
# - `/baseprefix` if you want to host szurubooru on a specific
|
||||
# prefix and share the domain with other applications
|
||||
# - `https://www.example.com/szuru` combines both of the above
|
||||
# also see: "Setting a specific base URI for proxying" in INSTALL.md
|
||||
base_url: /
|
||||
|
||||
# !!should not be changed for the normal docker installation!!
|
||||
# set to the root web address for static image content
|
||||
# if it is a relative path with no leading `/`, then this will be
|
||||
# appended to the base url.
|
||||
# see: "Using a seperate domain to host static files" in INSTALL.md
|
||||
# for more info on when to modify
|
||||
data_url: data/
|
||||
|
||||
# Delete thumbnails and source files on post delete
|
||||
# Original functionality is no, to mitigate the impacts of admins going
|
||||
# on unchecked post purges.
|
||||
|
@ -171,7 +188,6 @@ privileges:
|
|||
## ONLY SET THESE IF DEPLOYING OUTSIDE OF DOCKER
|
||||
#debug: 0 # generate server logs?
|
||||
#show_sql: 0 # show sql in server logs?
|
||||
#data_url: /data/
|
||||
#data_dir: /var/www/data
|
||||
## usage: schema://user:password@host:port/database_name
|
||||
## example: postgres://szuru:dog@localhost:5432/szuru_test
|
||||
|
|
|
@ -45,7 +45,7 @@ def get_info(ctx: rest.Context, _params: Dict[str, str] = {}) -> rest.Response:
|
|||
"defaultUserRank": config.config["default_rank"],
|
||||
"enableSafety": config.config["enable_safety"],
|
||||
"contactEmail": config.config["contact_email"],
|
||||
"canSendMails": bool(config.config["smtp"]["host"]),
|
||||
"canSendMails": util.can_send_mail(),
|
||||
"privileges": util.snake_case_to_lower_camel_case_keys(
|
||||
config.config["privileges"]
|
||||
),
|
||||
|
@ -74,17 +74,17 @@ def generate_manifest(
|
|||
"name": config.config["name"],
|
||||
"icons": [
|
||||
{
|
||||
"src": f"{ctx.url_prefix}/img/android-chrome-192x192.png",
|
||||
"src": util.add_url_prefix("/img/android-chrome-192x192.png"),
|
||||
"type": "image/png",
|
||||
"sizes": "192x192",
|
||||
},
|
||||
{
|
||||
"src": f"{ctx.url_prefix}/img/android-chrome-512x512.png",
|
||||
"src": util.add_url_prefix("/img/android-chrome-512x512.png"),
|
||||
"type": "image/png",
|
||||
"sizes": "512x512",
|
||||
},
|
||||
],
|
||||
"start_url": f"{ctx.url_prefix}/",
|
||||
"start_url": util.add_url_prefix(),
|
||||
"theme_color": "#24aadd",
|
||||
"background_color": "#ffffff",
|
||||
"display": "standalone",
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
from typing import Dict
|
||||
from typing import Callable, Dict
|
||||
|
||||
from yattag import Doc
|
||||
|
||||
from szurubooru import config, model, rest
|
||||
from szurubooru.func import auth, posts
|
||||
from szurubooru.func import auth, posts, util
|
||||
|
||||
_default_meta_tags = {
|
||||
"viewport": "width=device-width, initial-scale=1, maximum-scale=1",
|
||||
|
@ -62,7 +62,8 @@ _apple_touch_startup_images = {
|
|||
|
||||
|
||||
def _get_html_template(
|
||||
meta_tags: Dict = {}, title: str = config.config["name"], prefix: str = ""
|
||||
title: str,
|
||||
meta_tags: Dict = {},
|
||||
) -> Doc:
|
||||
doc = Doc()
|
||||
doc.asis("<!DOCTYPE html>")
|
||||
|
@ -73,19 +74,21 @@ def _get_html_template(
|
|||
doc.stag("meta", name=name, content=content)
|
||||
with doc.tag("title"):
|
||||
doc.text(title)
|
||||
doc.stag("base", href=f"{prefix}/")
|
||||
doc.stag("base", href=util.add_url_prefix())
|
||||
doc.stag(
|
||||
"link", rel="manifest", href=f"{prefix}/api/manifest.json"
|
||||
"link",
|
||||
rel="manifest",
|
||||
href=util.add_url_prefix("/api/manifest.json"),
|
||||
)
|
||||
doc.stag(
|
||||
"link",
|
||||
href=f"{prefix}/css/app.min.css",
|
||||
href=util.add_url_prefix("/css/app.min.css"),
|
||||
rel="stylesheet",
|
||||
type="text/css",
|
||||
)
|
||||
doc.stag(
|
||||
"link",
|
||||
href=f"{prefix}/css/vendor.min.css",
|
||||
href=util.add_url_prefix("/css/vendor.min.css"),
|
||||
rel="stylesheet",
|
||||
type="text/css",
|
||||
)
|
||||
|
@ -93,19 +96,21 @@ def _get_html_template(
|
|||
"link",
|
||||
rel="shortcut icon",
|
||||
type="image/png",
|
||||
href=f"{prefix}/img/favicon.png",
|
||||
href=util.add_url_prefix("/img/favicon.png"),
|
||||
)
|
||||
doc.stag(
|
||||
"link",
|
||||
rel="apple-touch-icon",
|
||||
sizes="180x180",
|
||||
href=f"{prefix}/img/apple-touch-icon.png",
|
||||
href=util.add_url_prefix("/img/apple-touch-icon.png"),
|
||||
)
|
||||
for res, media in _apple_touch_startup_images.items():
|
||||
doc.stag(
|
||||
"link",
|
||||
rel="apple-touch-startup-image",
|
||||
href=f"{prefix}/img/apple-touch-startup-image-{res}.png",
|
||||
href=util.add_url_prefix(
|
||||
f"/img/apple-touch-startup-image-{res}.png"
|
||||
),
|
||||
media=" and ".join(
|
||||
f"({k}: {v})" for k, v in media.items()
|
||||
),
|
||||
|
@ -116,11 +121,15 @@ def _get_html_template(
|
|||
with doc.tag("div", id="content-holder"):
|
||||
pass
|
||||
with doc.tag(
|
||||
"script", type="text/javascript", src="js/vendor.min.js"
|
||||
"script",
|
||||
type="text/javascript",
|
||||
src=util.add_url_prefix("js/vendor.min.js"),
|
||||
):
|
||||
pass
|
||||
with doc.tag(
|
||||
"script", type="text/javascript", src="js/app.min.js"
|
||||
"script",
|
||||
type="text/javascript",
|
||||
src=util.add_url_prefix("js/app.min.js"),
|
||||
):
|
||||
pass
|
||||
return doc.getvalue()
|
||||
|
@ -152,13 +161,17 @@ def get_post_html(
|
|||
|
||||
metadata = {
|
||||
"og:site_name": config.config["name"],
|
||||
"og:url": f"{ctx.url_prefix}/post/{params['post_id']}",
|
||||
"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)
|
||||
)
|
||||
metadata["og:article:published_time"] = post.creation_time.isoformat()
|
||||
if post.last_edit_time:
|
||||
metadata[
|
||||
|
@ -169,11 +182,9 @@ def get_post_html(
|
|||
)
|
||||
if post.type in (model.Post.TYPE_VIDEO):
|
||||
metadata["twitter:card"] = "player"
|
||||
metadata["og:video:url"] = posts.get_post_content_url(post)
|
||||
metadata["twitter:player:stream"] = posts.get_post_content_url(
|
||||
post
|
||||
)
|
||||
metadata["og:image:url"] = posts.get_post_thumbnail_url(post)
|
||||
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)
|
||||
|
@ -181,15 +192,13 @@ def get_post_html(
|
|||
metadata["twitter:player:height"] = str(post.canvas_height)
|
||||
else:
|
||||
metadata["twitter:card"] = "summary_large_image"
|
||||
metadata["og:image:url"] = posts.get_post_content_url(post)
|
||||
metadata["twitter:image"] = posts.get_post_content_url(post)
|
||||
return _get_html_template(
|
||||
meta_tags=metadata, title=title, prefix=ctx.url_prefix
|
||||
)
|
||||
metadata["og:image:url"] = content_url
|
||||
metadata["twitter:image"] = content_url
|
||||
return _get_html_template(title=title, meta_tags=metadata)
|
||||
|
||||
|
||||
@rest.routes.get("/html/.*", accept="text/html")
|
||||
def default_route(
|
||||
ctx: rest.Context, _params: Dict[str, str] = {}
|
||||
) -> rest.Response:
|
||||
return _get_html_template(prefix=ctx.url_prefix)
|
||||
return _get_html_template(title=config.config["name"])
|
||||
|
|
|
@ -2,7 +2,7 @@ from hashlib import md5
|
|||
from typing import Dict
|
||||
|
||||
from szurubooru import config, errors, rest
|
||||
from szurubooru.func import auth, mailer, users, versions
|
||||
from szurubooru.func import auth, mailer, users, util, versions
|
||||
|
||||
MAIL_SUBJECT = "Password reset for {name}"
|
||||
MAIL_BODY = (
|
||||
|
@ -24,8 +24,7 @@ def start_password_reset(
|
|||
% (user_name)
|
||||
)
|
||||
token = auth.generate_authentication_token(user)
|
||||
|
||||
url = f"{ctx.url_prefix}/password-reset/{user.name}:{token}"
|
||||
url = util.add_url_prefix(f"password-reset/{user.name}:{token}")
|
||||
|
||||
mailer.send_mail(
|
||||
config.config["smtp"]["from"],
|
||||
|
|
|
@ -9,7 +9,8 @@ _search_executor = search.Executor(search.configs.PoolSearchConfig())
|
|||
|
||||
def _serialize(ctx: rest.Context, pool: model.Pool) -> rest.Response:
|
||||
return pools.serialize_pool(
|
||||
pool, options=serialization.get_serialization_options(ctx)
|
||||
pool,
|
||||
options=serialization.get_serialization_options(ctx),
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -35,7 +35,9 @@ def _serialize_post(
|
|||
ctx: rest.Context, post: Optional[model.Post]
|
||||
) -> rest.Response:
|
||||
return posts.serialize_post(
|
||||
post, ctx.user, options=serialization.get_serialization_options(ctx)
|
||||
post,
|
||||
ctx.user,
|
||||
options=serialization.get_serialization_options(ctx),
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -31,7 +31,6 @@ def _docker_config() -> Dict:
|
|||
return {
|
||||
"debug": True,
|
||||
"show_sql": int(os.getenv("LOG_SQL", 0)),
|
||||
"data_url": os.getenv("DATA_URL", "data/"),
|
||||
"data_dir": "/data/",
|
||||
"database": "postgres://%(user)s:%(pass)s@%(host)s:%(port)d/%(db)s"
|
||||
% {
|
||||
|
|
|
@ -85,13 +85,7 @@ def validate_config() -> None:
|
|||
% (config.config["default_rank"])
|
||||
)
|
||||
|
||||
for key in ["data_url", "data_dir"]:
|
||||
if not config.config[key]:
|
||||
raise errors.ConfigError(
|
||||
"Service is not configured: %r is missing" % key
|
||||
)
|
||||
|
||||
if not os.path.isabs(config.config["data_dir"]):
|
||||
if not os.path.isabs(config.config["data_dir"] or ""):
|
||||
raise errors.ConfigError("data_dir must be an absolute path")
|
||||
|
||||
if not config.config["database"]:
|
||||
|
|
|
@ -145,7 +145,8 @@ class PoolSerializer(serialization.BaseSerializer):
|
|||
|
||||
|
||||
def serialize_pool(
|
||||
pool: model.Pool, options: List[str] = []
|
||||
pool: model.Pool,
|
||||
options: List[str] = [],
|
||||
) -> Optional[rest.Response]:
|
||||
if not pool:
|
||||
return None
|
||||
|
@ -154,7 +155,8 @@ def serialize_pool(
|
|||
|
||||
def serialize_micro_pool(pool: model.Pool) -> Optional[rest.Response]:
|
||||
return serialize_pool(
|
||||
pool, options=["id", "names", "category", "description", "postCount"]
|
||||
pool,
|
||||
options=["id", "names", "category", "description", "postCount"],
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -44,7 +44,9 @@ class PostAlreadyUploadedError(errors.ValidationError):
|
|||
super().__init__(
|
||||
"Post already uploaded (%d)" % other_post.post_id,
|
||||
{
|
||||
"otherPostUrl": get_post_content_url(other_post),
|
||||
"otherPostUrl": util.add_data_prefix(
|
||||
get_post_content_path(other_post)
|
||||
),
|
||||
"otherPostId": other_post.post_id,
|
||||
},
|
||||
)
|
||||
|
@ -105,25 +107,6 @@ def get_post_security_hash(id: int) -> str:
|
|||
).hexdigest()[0:16]
|
||||
|
||||
|
||||
def get_post_content_url(post: model.Post) -> str:
|
||||
assert post
|
||||
return "%s/posts/%d_%s.%s" % (
|
||||
config.config["data_url"].rstrip("/"),
|
||||
post.post_id,
|
||||
get_post_security_hash(post.post_id),
|
||||
mime.get_extension(post.mime_type) or "dat",
|
||||
)
|
||||
|
||||
|
||||
def get_post_thumbnail_url(post: model.Post) -> str:
|
||||
assert post
|
||||
return "%s/generated-thumbnails/%d_%s.jpg" % (
|
||||
config.config["data_url"].rstrip("/"),
|
||||
post.post_id,
|
||||
get_post_security_hash(post.post_id),
|
||||
)
|
||||
|
||||
|
||||
def get_post_content_path(post: model.Post) -> str:
|
||||
assert post
|
||||
assert post.post_id
|
||||
|
@ -159,7 +142,11 @@ def serialize_note(note: model.PostNote) -> rest.Response:
|
|||
|
||||
|
||||
class PostSerializer(serialization.BaseSerializer):
|
||||
def __init__(self, post: model.Post, auth_user: model.User) -> None:
|
||||
def __init__(
|
||||
self,
|
||||
post: model.Post,
|
||||
auth_user: model.User,
|
||||
) -> None:
|
||||
self.post = post
|
||||
self.auth_user = auth_user
|
||||
|
||||
|
@ -241,10 +228,10 @@ class PostSerializer(serialization.BaseSerializer):
|
|||
return self.post.canvas_height
|
||||
|
||||
def serialize_content_url(self) -> Any:
|
||||
return get_post_content_url(self.post)
|
||||
return util.add_data_prefix(get_post_content_path(self.post))
|
||||
|
||||
def serialize_thumbnail_url(self) -> Any:
|
||||
return get_post_thumbnail_url(self.post)
|
||||
return util.add_data_prefix(get_post_thumbnail_path(self.post))
|
||||
|
||||
def serialize_flags(self) -> Any:
|
||||
return self.post.flags
|
||||
|
@ -264,7 +251,7 @@ class PostSerializer(serialization.BaseSerializer):
|
|||
{
|
||||
post["id"]: post
|
||||
for post in [
|
||||
serialize_micro_post(rel, self.auth_user)
|
||||
serialize_micro_post(rel, self.auth_user, self.url_prefix)
|
||||
for rel in self.post.relations
|
||||
]
|
||||
}.values(),
|
||||
|
@ -346,7 +333,9 @@ class PostSerializer(serialization.BaseSerializer):
|
|||
|
||||
|
||||
def serialize_post(
|
||||
post: Optional[model.Post], auth_user: model.User, options: List[str] = []
|
||||
post: Optional[model.Post],
|
||||
auth_user: model.User,
|
||||
options: List[str] = [],
|
||||
) -> Optional[rest.Response]:
|
||||
if not post:
|
||||
return None
|
||||
|
@ -354,7 +343,8 @@ def serialize_post(
|
|||
|
||||
|
||||
def serialize_micro_post(
|
||||
post: model.Post, auth_user: model.User
|
||||
post: model.Post,
|
||||
auth_user: model.User,
|
||||
) -> Optional[rest.Response]:
|
||||
return serialize_post(
|
||||
post, auth_user=auth_user, options=["id", "thumbnailUrl"]
|
||||
|
|
|
@ -5,8 +5,9 @@ import tempfile
|
|||
from contextlib import contextmanager
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Any, Dict, Generator, List, Optional, Tuple, TypeVar, Union
|
||||
from urllib.parse import urlparse, urlunparse
|
||||
|
||||
from szurubooru import errors
|
||||
from szurubooru import config, errors
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
|
@ -176,3 +177,34 @@ def get_column_size(column: Any) -> Optional[int]:
|
|||
def chunks(source_list: List[Any], part_size: int) -> Generator:
|
||||
for i in range(0, len(source_list), part_size):
|
||||
yield source_list[i : i + part_size]
|
||||
|
||||
|
||||
def _get_url_prefix_parts() -> str:
|
||||
parsed_base_url = list(urlparse(config.config["base_url"]))
|
||||
if not all(parsed_base_url[0:2]):
|
||||
parsed_base_url[0:2] = ["", ""]
|
||||
parsed_base_url[2] = parsed_base_url[2].rstrip("/")
|
||||
return parsed_base_url[0:3] + ["", "", ""]
|
||||
|
||||
|
||||
def _get_data_prefix_parts() -> str:
|
||||
parsed_base_url = _get_url_prefix_parts()
|
||||
parsed_data_url = list(urlparse(config.config["data_url"]))
|
||||
if not all(parsed_data_url[0:2]):
|
||||
parsed_data_url[0:2] = parsed_base_url[0:2]
|
||||
if not parsed_data_url[2].startswith("/"):
|
||||
parsed_data_url[2] = parsed_base_url[2] + "/" + parsed_data_url[2]
|
||||
parsed_data_url[2] = parsed_data_url[2].rstrip("/")
|
||||
return parsed_data_url[0:3] + ["", "", ""]
|
||||
|
||||
|
||||
def add_url_prefix(url: str = "") -> str:
|
||||
return urlunparse(_get_url_prefix_parts()) + "/" + url.lstrip("/")
|
||||
|
||||
|
||||
def add_data_prefix(url: str = "") -> str:
|
||||
return urlunparse(_get_data_prefix_parts()) + "/" + url.lstrip("/")
|
||||
|
||||
|
||||
def can_send_mail() -> bool:
|
||||
return bool(config.config["smtp"]["host"] and _get_url_prefix_parts()[1])
|
||||
|
|
|
@ -41,11 +41,6 @@ def _create_context(env: Dict[str, Any]) -> context.Context:
|
|||
path = path.encode("latin-1").decode("utf-8") # PEP-3333
|
||||
headers = _get_headers(env)
|
||||
|
||||
if config.config["domain"]:
|
||||
url_prefix = config.config["domain"].rstrip("/")
|
||||
else:
|
||||
url_prefix = headers.get("X-Forwarded-Prefix", "")
|
||||
|
||||
files = {}
|
||||
params = dict(urllib.parse.parse_qsl(env.get("QUERY_STRING", "")))
|
||||
|
||||
|
@ -80,7 +75,6 @@ def _create_context(env: Dict[str, Any]) -> context.Context:
|
|||
method=method,
|
||||
url=path,
|
||||
headers=headers,
|
||||
url_prefix=url_prefix,
|
||||
params=params,
|
||||
files=files,
|
||||
)
|
||||
|
|
|
@ -16,7 +16,6 @@ class Context:
|
|||
url: str,
|
||||
headers: Dict[str, str] = None,
|
||||
accept: str = None,
|
||||
url_prefix: str = None,
|
||||
params: Request = None,
|
||||
files: Dict[str, bytes] = None,
|
||||
) -> None:
|
||||
|
@ -24,7 +23,6 @@ class Context:
|
|||
self.method = method
|
||||
self.url = url
|
||||
self.accept = accept
|
||||
self.url_prefix = url_prefix
|
||||
self._headers = headers or {}
|
||||
self._params = params or {}
|
||||
self._files = files or {}
|
||||
|
|
|
@ -18,6 +18,7 @@ def test_info_api(
|
|||
config_injector(
|
||||
{
|
||||
"name": "test installation",
|
||||
"base_url": "https://www.example.com",
|
||||
"contact_email": "test@example.com",
|
||||
"enable_safety": True,
|
||||
"data_dir": str(directory),
|
||||
|
@ -97,9 +98,13 @@ def test_info_api(
|
|||
|
||||
|
||||
def test_manifest(config_injector, context_factory):
|
||||
config_injector({"name": "test installation"})
|
||||
config_injector(
|
||||
{
|
||||
"name": "test installation",
|
||||
"base_url": "/someprefix",
|
||||
}
|
||||
)
|
||||
ctx = context_factory()
|
||||
ctx.url_prefix = "/someprefix"
|
||||
expected_manifest = {
|
||||
"name": "test installation",
|
||||
"icons": [
|
||||
|
|
|
@ -23,23 +23,24 @@ def test_get_post_html(
|
|||
config_injector(
|
||||
{
|
||||
"name": "test installation",
|
||||
"data_url": "data/",
|
||||
"base_url": "/someprefix",
|
||||
"data_url": "data",
|
||||
}
|
||||
)
|
||||
ctx = context_factory()
|
||||
ctx.url_prefix = "/someprefix"
|
||||
post = post_factory(id=1, type=post_type)
|
||||
post.canvas_width = 1920
|
||||
post.canvas_height = 1080
|
||||
db.session.add(post)
|
||||
db.session.flush()
|
||||
with patch("szurubooru.func.auth.has_privilege"), patch(
|
||||
"szurubooru.func.posts.get_post_content_url"
|
||||
), patch("szurubooru.func.posts.get_post_thumbnail_url"):
|
||||
"szurubooru.func.posts.get_post_content_path"
|
||||
), patch("szurubooru.func.posts.get_post_thumbnail_path"):
|
||||
auth.has_privilege.return_value = view_priv
|
||||
posts.get_post_content_url.return_value = "/content-url"
|
||||
posts.get_post_thumbnail_url.return_value = "/thumbnail-url"
|
||||
ret = api.opengraph_api.get_post_html(ctx, {"post_id": 1})
|
||||
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:url", "/someprefix/post/1") in ret
|
||||
|
@ -59,16 +60,27 @@ def test_get_post_html(
|
|||
)
|
||||
assert (
|
||||
bool(
|
||||
_make_meta_tag("twitter:player:stream", "/content-url") in ret
|
||||
_make_meta_tag(
|
||||
"twitter:player:stream", "/someprefix/data/content-url"
|
||||
)
|
||||
in ret
|
||||
)
|
||||
== view_priv
|
||||
)
|
||||
assert (
|
||||
bool(_make_meta_tag("og:video:url", "/content-url") in ret)
|
||||
bool(
|
||||
_make_meta_tag("og:video:url", "/someprefix/data/content-url")
|
||||
in ret
|
||||
)
|
||||
== view_priv
|
||||
)
|
||||
assert (
|
||||
bool(_make_meta_tag("og:image:url", "/thumbnail-url") in ret)
|
||||
bool(
|
||||
_make_meta_tag(
|
||||
"og:image:url", "/someprefix/data/thumbnail-url"
|
||||
)
|
||||
in ret
|
||||
)
|
||||
== view_priv
|
||||
)
|
||||
assert (
|
||||
|
@ -83,6 +95,9 @@ def test_get_post_html(
|
|||
== view_priv
|
||||
)
|
||||
assert (
|
||||
bool(_make_meta_tag("twitter:image", "/content-url") in ret)
|
||||
bool(
|
||||
_make_meta_tag("twitter:image", "/someprefix/data/content-url")
|
||||
in ret
|
||||
)
|
||||
== view_priv
|
||||
)
|
||||
|
|
|
@ -11,7 +11,7 @@ def inject_config(config_injector):
|
|||
config_injector(
|
||||
{
|
||||
"secret": "x",
|
||||
"domain": "http://example.com",
|
||||
"base_url": "http://example.com",
|
||||
"name": "Test instance",
|
||||
"smtp": {
|
||||
"from": "noreply@example.com",
|
||||
|
@ -27,13 +27,11 @@ def test_reset_sending_email(context_factory, user_factory):
|
|||
)
|
||||
)
|
||||
db.session.flush()
|
||||
ctx = context_factory()
|
||||
ctx.url_prefix = "http://example.com"
|
||||
for initiating_user in ["u1", "user@example.com"]:
|
||||
with patch("szurubooru.func.mailer.send_mail"):
|
||||
assert (
|
||||
api.password_reset_api.start_password_reset(
|
||||
ctx, {"user_name": initiating_user}
|
||||
context_factory(), {"user_name": initiating_user}
|
||||
)
|
||||
== {}
|
||||
)
|
||||
|
|
|
@ -41,19 +41,17 @@ def test_simple_updating(user_factory, pool_factory, context_factory):
|
|||
):
|
||||
posts.get_posts_by_ids.return_value = ([], [])
|
||||
pools.serialize_pool.return_value = "serialized pool"
|
||||
result = api.pool_api.update_pool(
|
||||
context_factory(
|
||||
params={
|
||||
"version": 1,
|
||||
"names": ["pool3"],
|
||||
"category": "series",
|
||||
"description": "desc",
|
||||
"posts": [1, 2],
|
||||
},
|
||||
user=auth_user,
|
||||
),
|
||||
{"pool_id": 1},
|
||||
ctx = context_factory(
|
||||
params={
|
||||
"version": 1,
|
||||
"names": ["pool3"],
|
||||
"category": "series",
|
||||
"description": "desc",
|
||||
"posts": [1, 2],
|
||||
},
|
||||
user=auth_user,
|
||||
)
|
||||
result = api.pool_api.update_pool(ctx, {"pool_id": 1})
|
||||
assert result == "serialized pool"
|
||||
pools.create_pool.assert_not_called()
|
||||
pools.update_pool_names.assert_called_once_with(pool, ["pool3"])
|
||||
|
|
|
@ -45,19 +45,18 @@ def test_creating_minimal_posts(context_factory, post_factory, user_factory):
|
|||
posts.create_post.return_value = (post, [])
|
||||
posts.serialize_post.return_value = "serialized post"
|
||||
|
||||
result = api.post_api.create_post(
|
||||
context_factory(
|
||||
params={
|
||||
"safety": "safe",
|
||||
"tags": ["tag1", "tag2"],
|
||||
},
|
||||
files={
|
||||
"content": "post-content",
|
||||
"thumbnail": "post-thumbnail",
|
||||
},
|
||||
user=auth_user,
|
||||
)
|
||||
ctx = context_factory(
|
||||
params={
|
||||
"safety": "safe",
|
||||
"tags": ["tag1", "tag2"],
|
||||
},
|
||||
files={
|
||||
"content": "post-content",
|
||||
"thumbnail": "post-thumbnail",
|
||||
},
|
||||
user=auth_user,
|
||||
)
|
||||
result = api.post_api.create_post(ctx)
|
||||
|
||||
assert result == "serialized post"
|
||||
posts.create_post.assert_called_once_with(
|
||||
|
@ -102,22 +101,21 @@ def test_creating_full_posts(context_factory, post_factory, user_factory):
|
|||
posts.create_post.return_value = (post, [])
|
||||
posts.serialize_post.return_value = "serialized post"
|
||||
|
||||
result = api.post_api.create_post(
|
||||
context_factory(
|
||||
params={
|
||||
"safety": "safe",
|
||||
"tags": ["tag1", "tag2"],
|
||||
"relations": [1, 2],
|
||||
"source": "source",
|
||||
"notes": ["note1", "note2"],
|
||||
"flags": ["flag1", "flag2"],
|
||||
},
|
||||
files={
|
||||
"content": "post-content",
|
||||
},
|
||||
user=auth_user,
|
||||
)
|
||||
ctx = context_factory(
|
||||
params={
|
||||
"safety": "safe",
|
||||
"tags": ["tag1", "tag2"],
|
||||
"relations": [1, 2],
|
||||
"source": "source",
|
||||
"notes": ["note1", "note2"],
|
||||
"flags": ["flag1", "flag2"],
|
||||
},
|
||||
files={
|
||||
"content": "post-content",
|
||||
},
|
||||
user=auth_user,
|
||||
)
|
||||
result = api.post_api.create_post(ctx)
|
||||
|
||||
assert result == "serialized post"
|
||||
posts.create_post.assert_called_once_with(
|
||||
|
@ -333,7 +331,8 @@ def test_errors_not_spending_ids(
|
|||
config_injector(
|
||||
{
|
||||
"data_dir": str(tmpdir.mkdir("data")),
|
||||
"data_url": "example.com",
|
||||
"base_url": "https://example.com/",
|
||||
"data_url": "https://example.com/data",
|
||||
"thumbnails": {
|
||||
"post_width": 300,
|
||||
"post_height": 300,
|
||||
|
|
|
@ -17,34 +17,6 @@ from szurubooru.func import (
|
|||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"input_mime_type,expected_url",
|
||||
[
|
||||
("image/jpeg", "http://example.com/posts/1_244c8840887984c4.jpg"),
|
||||
("image/gif", "http://example.com/posts/1_244c8840887984c4.gif"),
|
||||
("totally/unknown", "http://example.com/posts/1_244c8840887984c4.dat"),
|
||||
],
|
||||
)
|
||||
def test_get_post_url(input_mime_type, expected_url, config_injector):
|
||||
config_injector({"data_url": "http://example.com/", "secret": "test"})
|
||||
post = model.Post()
|
||||
post.post_id = 1
|
||||
post.mime_type = input_mime_type
|
||||
assert posts.get_post_content_url(post) == expected_url
|
||||
|
||||
|
||||
@pytest.mark.parametrize("input_mime_type", ["image/jpeg", "image/gif"])
|
||||
def test_get_post_thumbnail_url(input_mime_type, config_injector):
|
||||
config_injector({"data_url": "http://example.com/", "secret": "test"})
|
||||
post = model.Post()
|
||||
post.post_id = 1
|
||||
post.mime_type = input_mime_type
|
||||
assert (
|
||||
posts.get_post_thumbnail_url(post)
|
||||
== "http://example.com/generated-thumbnails/1_244c8840887984c4.jpg"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"input_mime_type,expected_path",
|
||||
[
|
||||
|
@ -53,7 +25,10 @@ def test_get_post_thumbnail_url(input_mime_type, config_injector):
|
|||
("totally/unknown", "posts/1_244c8840887984c4.dat"),
|
||||
],
|
||||
)
|
||||
def test_get_post_content_path(input_mime_type, expected_path):
|
||||
def test_get_post_content_path(
|
||||
input_mime_type, expected_path, config_injector
|
||||
):
|
||||
config_injector({"secret": "test"})
|
||||
post = model.Post()
|
||||
post.post_id = 1
|
||||
post.mime_type = input_mime_type
|
||||
|
@ -61,7 +36,8 @@ def test_get_post_content_path(input_mime_type, expected_path):
|
|||
|
||||
|
||||
@pytest.mark.parametrize("input_mime_type", ["image/jpeg", "image/gif"])
|
||||
def test_get_post_thumbnail_path(input_mime_type):
|
||||
def test_get_post_thumbnail_path(input_mime_type, config_injector):
|
||||
config_injector({"secret": "test"})
|
||||
post = model.Post()
|
||||
post.post_id = 1
|
||||
post.mime_type = input_mime_type
|
||||
|
@ -72,7 +48,8 @@ def test_get_post_thumbnail_path(input_mime_type):
|
|||
|
||||
|
||||
@pytest.mark.parametrize("input_mime_type", ["image/jpeg", "image/gif"])
|
||||
def test_get_post_thumbnail_backup_path(input_mime_type):
|
||||
def test_get_post_thumbnail_backup_path(input_mime_type, config_injector):
|
||||
config_injector({"secret": "test"})
|
||||
post = model.Post()
|
||||
post.post_id = 1
|
||||
post.mime_type = input_mime_type
|
||||
|
@ -105,7 +82,13 @@ def test_serialize_post(
|
|||
pool_category_factory,
|
||||
config_injector,
|
||||
):
|
||||
config_injector({"data_url": "http://example.com/", "secret": "test"})
|
||||
config_injector(
|
||||
{
|
||||
"secret": "test",
|
||||
"base_url": "http://example.com/",
|
||||
"data_url": "http://example.com/",
|
||||
}
|
||||
)
|
||||
with patch("szurubooru.func.comments.serialize_comment"), patch(
|
||||
"szurubooru.func.users.serialize_micro_user"
|
||||
), patch("szurubooru.func.posts.files.has"):
|
||||
|
@ -277,17 +260,15 @@ def test_serialize_post(
|
|||
|
||||
|
||||
def test_serialize_micro_post(post_factory, user_factory):
|
||||
with patch("szurubooru.func.posts.get_post_thumbnail_url"):
|
||||
posts.get_post_thumbnail_url.return_value = (
|
||||
"https://example.com/thumb.png"
|
||||
)
|
||||
with patch("szurubooru.func.posts.get_post_thumbnail_path"):
|
||||
posts.get_post_thumbnail_path.return_value = "thumb.png"
|
||||
auth_user = user_factory()
|
||||
post = post_factory()
|
||||
db.session.add(post)
|
||||
db.session.flush()
|
||||
assert posts.serialize_micro_post(post, auth_user) == {
|
||||
"id": post.post_id,
|
||||
"thumbnailUrl": "https://example.com/thumb.png",
|
||||
"thumbnailUrl": "http://example.com/thumb.png",
|
||||
}
|
||||
|
||||
|
||||
|
@ -519,7 +500,8 @@ def test_update_post_content_to_existing_content(
|
|||
config_injector(
|
||||
{
|
||||
"data_dir": str(tmpdir.mkdir("data")),
|
||||
"data_url": "example.com",
|
||||
"base_url": "https://example.com/",
|
||||
"data_url": "https://example.com/data",
|
||||
"thumbnails": {
|
||||
"post_width": 300,
|
||||
"post_height": 300,
|
||||
|
|
|
@ -45,3 +45,93 @@ def test_parsing_date_time(fake_datetime, input, output):
|
|||
)
|
||||
def test_icase_unique(input, output):
|
||||
assert util.icase_unique(input) == output
|
||||
|
||||
|
||||
def test_url_generation(config_injector):
|
||||
config_injector(
|
||||
{
|
||||
"base_url": "https://www.example.com/",
|
||||
"data_url": "data/",
|
||||
}
|
||||
)
|
||||
assert util.add_url_prefix() == "https://www.example.com/"
|
||||
assert util.add_url_prefix("/post/1") == "https://www.example.com/post/1"
|
||||
assert util.add_url_prefix("post/1") == "https://www.example.com/post/1"
|
||||
assert util.add_data_prefix() == "https://www.example.com/data/"
|
||||
assert (
|
||||
util.add_data_prefix("posts/1.jpg")
|
||||
== "https://www.example.com/data/posts/1.jpg"
|
||||
)
|
||||
assert (
|
||||
util.add_data_prefix("/posts/1.jpg")
|
||||
== "https://www.example.com/data/posts/1.jpg"
|
||||
)
|
||||
config_injector(
|
||||
{
|
||||
"base_url": "https://www.example.com/szuru/",
|
||||
"data_url": "data/",
|
||||
}
|
||||
)
|
||||
assert util.add_url_prefix() == "https://www.example.com/szuru/"
|
||||
assert (
|
||||
util.add_url_prefix("/post/1")
|
||||
== "https://www.example.com/szuru/post/1"
|
||||
)
|
||||
assert (
|
||||
util.add_url_prefix("post/1") == "https://www.example.com/szuru/post/1"
|
||||
)
|
||||
assert util.add_data_prefix() == "https://www.example.com/szuru/data/"
|
||||
assert (
|
||||
util.add_data_prefix("posts/1.jpg")
|
||||
== "https://www.example.com/szuru/data/posts/1.jpg"
|
||||
)
|
||||
assert (
|
||||
util.add_data_prefix("/posts/1.jpg")
|
||||
== "https://www.example.com/szuru/data/posts/1.jpg"
|
||||
)
|
||||
config_injector(
|
||||
{
|
||||
"base_url": "https://www.example.com/szuru/",
|
||||
"data_url": "/data/",
|
||||
}
|
||||
)
|
||||
assert util.add_url_prefix() == "https://www.example.com/szuru/"
|
||||
assert (
|
||||
util.add_url_prefix("/post/1")
|
||||
== "https://www.example.com/szuru/post/1"
|
||||
)
|
||||
assert (
|
||||
util.add_url_prefix("post/1") == "https://www.example.com/szuru/post/1"
|
||||
)
|
||||
assert util.add_data_prefix() == "https://www.example.com/data/"
|
||||
assert (
|
||||
util.add_data_prefix("posts/1.jpg")
|
||||
== "https://www.example.com/data/posts/1.jpg"
|
||||
)
|
||||
assert (
|
||||
util.add_data_prefix("/posts/1.jpg")
|
||||
== "https://www.example.com/data/posts/1.jpg"
|
||||
)
|
||||
config_injector(
|
||||
{
|
||||
"base_url": "https://www.example.com/szuru",
|
||||
"data_url": "https://static.example.com/",
|
||||
}
|
||||
)
|
||||
assert util.add_url_prefix() == "https://www.example.com/szuru/"
|
||||
assert (
|
||||
util.add_url_prefix("/post/1")
|
||||
== "https://www.example.com/szuru/post/1"
|
||||
)
|
||||
assert (
|
||||
util.add_url_prefix("post/1") == "https://www.example.com/szuru/post/1"
|
||||
)
|
||||
assert util.add_data_prefix() == "https://static.example.com/"
|
||||
assert (
|
||||
util.add_data_prefix("posts/1.jpg")
|
||||
== "https://static.example.com/posts/1.jpg"
|
||||
)
|
||||
assert (
|
||||
util.add_data_prefix("/posts/1.jpg")
|
||||
== "https://static.example.com/posts/1.jpg"
|
||||
)
|
||||
|
|
Loading…
Reference in a new issue