Compare commits
2 Commits
f085d4a8d0
...
798087de9a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
798087de9a | ||
|
|
cc22b21b18 |
@@ -1,9 +1,9 @@
|
|||||||
# The monolith has been split into three apps (apps/coop, apps/market, apps/cart).
|
# The monolith has been split into three apps (apps/blog, apps/market, apps/cart).
|
||||||
# This package remains for shared infrastructure modules (middleware, redis_cacher,
|
# This package remains for shared infrastructure modules (middleware, redis_cacher,
|
||||||
# csrf, errors, authz, filters, utils, bp/*).
|
# csrf, errors, authz, filters, utils, bp/*).
|
||||||
#
|
#
|
||||||
# To run individual apps:
|
# To run individual apps:
|
||||||
# hypercorn apps.coop.app:app --bind 0.0.0.0:8000
|
# hypercorn apps.blog.app:app --bind 0.0.0.0:8000
|
||||||
# hypercorn apps.market.app:app --bind 0.0.0.0:8001
|
# hypercorn apps.market.app:app --bind 0.0.0.0:8001
|
||||||
# hypercorn apps.cart.app:app --bind 0.0.0.0:8002
|
# hypercorn apps.cart.app:app --bind 0.0.0.0:8002
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<form action="{{ coop_url('/auth/logout/') }}" method="post">
|
<form action="{{ blog_url('/auth/logout/') }}" method="post">
|
||||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{% import 'macros/links.html' as links %}
|
{% import 'macros/links.html' as links %}
|
||||||
{% call links.link(coop_url('/auth/newsletters/'), hx_select_search, select_colours, True, aclass=styles.nav_button) %}
|
{% call links.link(blog_url('/auth/newsletters/'), hx_select_search, select_colours, True, aclass=styles.nav_button) %}
|
||||||
newsletters
|
newsletters
|
||||||
{% endcall %}
|
{% endcall %}
|
||||||
{% for link in account_nav_links %}
|
{% for link in account_nav_links %}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<div id="nl-{{ un.newsletter_id }}" class="flex items-center">
|
<div id="nl-{{ un.newsletter_id }}" class="flex items-center">
|
||||||
<button
|
<button
|
||||||
hx-post="{{ coop_url('/auth/newsletter/' ~ un.newsletter_id ~ '/toggle/') }}"
|
hx-post="{{ blog_url('/auth/newsletter/' ~ un.newsletter_id ~ '/toggle/') }}"
|
||||||
hx-headers='{"X-CSRFToken": "{{ csrf_token() }}"}'
|
hx-headers='{"X-CSRFToken": "{{ csrf_token() }}"}'
|
||||||
hx-target="#nl-{{ un.newsletter_id }}"
|
hx-target="#nl-{{ un.newsletter_id }}"
|
||||||
hx-swap="outerHTML"
|
hx-swap="outerHTML"
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
{# No subscription row yet — show an off toggle that will create one #}
|
{# No subscription row yet — show an off toggle that will create one #}
|
||||||
<div id="nl-{{ item.newsletter.id }}" class="flex items-center">
|
<div id="nl-{{ item.newsletter.id }}" class="flex items-center">
|
||||||
<button
|
<button
|
||||||
hx-post="{{ coop_url('/auth/newsletter/' ~ item.newsletter.id ~ '/toggle/') }}"
|
hx-post="{{ blog_url('/auth/newsletter/' ~ item.newsletter.id ~ '/toggle/') }}"
|
||||||
hx-headers='{"X-CSRFToken": "{{ csrf_token() }}"}'
|
hx-headers='{"X-CSRFToken": "{{ csrf_token() }}"}'
|
||||||
hx-target="#nl-{{ item.newsletter.id }}"
|
hx-target="#nl-{{ item.newsletter.id }}"
|
||||||
hx-swap="outerHTML"
|
hx-swap="outerHTML"
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
<p class="mt-6 text-sm">
|
<p class="mt-6 text-sm">
|
||||||
<a
|
<a
|
||||||
href="{{ coop_url('/auth/login/') }}"
|
href="{{ blog_url('/auth/login/') }}"
|
||||||
class="text-stone-600 dark:text-stone-300 hover:underline"
|
class="text-stone-600 dark:text-stone-300 hover:underline"
|
||||||
>
|
>
|
||||||
← Back
|
← Back
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{% import 'macros/links.html' as links %}
|
{% import 'macros/links.html' as links %}
|
||||||
{% macro header_row(oob=False) %}
|
{% macro header_row(oob=False) %}
|
||||||
{% call links.menu_row(id='auth-row', oob=oob) %}
|
{% call links.menu_row(id='auth-row', oob=oob) %}
|
||||||
{% call links.link(coop_url('/auth/account/'), hx_select_search ) %}
|
{% call links.link(blog_url('/auth/account/'), hx_select_search ) %}
|
||||||
<i class="fa-solid fa-user"></i>
|
<i class="fa-solid fa-user"></i>
|
||||||
<div>account</div>
|
<div>account</div>
|
||||||
{% endcall %}
|
{% endcall %}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<form
|
<form
|
||||||
method="post" action="{{ coop_url('/auth/start/') }}"
|
method="post" action="{{ blog_url('/auth/start/') }}"
|
||||||
class="mt-6 space-y-5"
|
class="mt-6 space-y-5"
|
||||||
>
|
>
|
||||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
{% if _count == 0 %}
|
{% if _count == 0 %}
|
||||||
<div class="h-12 w-12 rounded-full overflow-hidden border border-stone-300 flex-shrink-0">
|
<div class="h-12 w-12 rounded-full overflow-hidden border border-stone-300 flex-shrink-0">
|
||||||
<a
|
<a
|
||||||
href="{{ coop_url('/') }}"
|
href="{{ blog_url('/') }}"
|
||||||
class="h-full w-full font-bold text-5xl flex-shrink-0 flex flex-row items-center gap-1"
|
class="h-full w-full font-bold text-5xl flex-shrink-0 flex flex-row items-center gap-1"
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
{% from 'macros/scrolling_menu.html' import scrolling_menu with context %}
|
{% from 'macros/scrolling_menu.html' import scrolling_menu with context %}
|
||||||
{% call(entry_post) scrolling_menu('entry-posts-container', entry_posts) %}
|
{% call(entry_post) scrolling_menu('entry-posts-container', entry_posts) %}
|
||||||
<a
|
<a
|
||||||
href="{{ coop_url('/' + entry_post.slug + '/') }}"
|
href="{{ blog_url('/' + entry_post.slug + '/') }}"
|
||||||
class="flex items-center gap-2 px-3 py-2 hover:bg-stone-100 rounded transition text-sm border sm:whitespace-nowrap sm:flex-shrink-0">
|
class="flex items-center gap-2 px-3 py-2 hover:bg-stone-100 rounded transition text-sm border sm:whitespace-nowrap sm:flex-shrink-0">
|
||||||
{% if entry_post.feature_image %}
|
{% if entry_post.feature_image %}
|
||||||
<img src="{{ entry_post.feature_image }}"
|
<img src="{{ entry_post.feature_image }}"
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
{% from 'macros/scrolling_menu.html' import scrolling_menu with context %}
|
{% from 'macros/scrolling_menu.html' import scrolling_menu with context %}
|
||||||
{% call(entry_post) scrolling_menu('entry-posts-container', entry_posts) %}
|
{% call(entry_post) scrolling_menu('entry-posts-container', entry_posts) %}
|
||||||
<a
|
<a
|
||||||
href="{{ coop_url('/' + entry_post.slug + '/') }}"
|
href="{{ blog_url('/' + entry_post.slug + '/') }}"
|
||||||
class="{{styles.nav_button}}"
|
class="{{styles.nav_button}}"
|
||||||
>
|
>
|
||||||
{% if entry_post.feature_image %}
|
{% if entry_post.feature_image %}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
class="font-bold text-xl flex-shrink-0 flex gap-2 items-center">
|
class="font-bold text-xl flex-shrink-0 flex gap-2 items-center">
|
||||||
<div>
|
<div>
|
||||||
<i class="fa fa-shop"></i>
|
<i class="fa fa-shop"></i>
|
||||||
{{ coop_title }}
|
{{ market_title }}
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col md:flex-row md:gap-2 text-xs">
|
<div class="flex flex-col md:flex-row md:gap-2 text-xs">
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
hx-swap-oob="outerHTML">
|
hx-swap-oob="outerHTML">
|
||||||
{% from 'macros/scrolling_menu.html' import scrolling_menu with context %}
|
{% from 'macros/scrolling_menu.html' import scrolling_menu with context %}
|
||||||
{% call(item) scrolling_menu('menu-items-container', menu_items) %}
|
{% call(item) scrolling_menu('menu-items-container', menu_items) %}
|
||||||
{% set _href = _app_slugs.get(item.slug, coop_url('/' + item.slug + '/')) %}
|
{% set _href = _app_slugs.get(item.slug, blog_url('/' + item.slug + '/')) %}
|
||||||
<a
|
<a
|
||||||
href="{{ _href }}"
|
href="{{ _href }}"
|
||||||
{% if item.slug not in _app_slugs %}
|
{% if item.slug not in _app_slugs %}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{% import 'macros/links.html' as links %}
|
{% import 'macros/links.html' as links %}
|
||||||
{% macro header_row(oob=False) %}
|
{% macro header_row(oob=False) %}
|
||||||
{% call links.menu_row(id='post-row', oob=oob) %}
|
{% call links.menu_row(id='post-row', oob=oob) %}
|
||||||
<a href="{{ coop_url('/' + post.slug + '/') }}" class="flex items-center gap-2 px-3 py-2 rounded whitespace-normal text-center break-words leading-snug">
|
<a href="{{ blog_url('/' + post.slug + '/') }}" class="flex items-center gap-2 px-3 py-2 rounded whitespace-normal text-center break-words leading-snug">
|
||||||
{% if post.feature_image %}
|
{% if post.feature_image %}
|
||||||
<img
|
<img
|
||||||
src="{{ post.feature_image }}"
|
src="{{ post.feature_image }}"
|
||||||
|
|||||||
@@ -30,7 +30,7 @@
|
|||||||
|
|
||||||
{% block filter %}
|
{% block filter %}
|
||||||
{% call layout.details() %}
|
{% call layout.details() %}
|
||||||
{% call layout.summary('coop-child-header') %}
|
{% call layout.summary('blog-child-header') %}
|
||||||
{% endcall %}
|
{% endcall %}
|
||||||
{% call layout.menu('blog-child-menu') %}
|
{% call layout.menu('blog-child-menu') %}
|
||||||
{% endcall %}
|
{% endcall %}
|
||||||
|
|||||||
@@ -30,8 +30,8 @@
|
|||||||
{% block filter %}
|
{% block filter %}
|
||||||
|
|
||||||
{% call layout.details() %}
|
{% call layout.details() %}
|
||||||
{% call layout.summary('coop-child-header') %}
|
{% call layout.summary('blog-child-header') %}
|
||||||
{% block coop_child_summary %}
|
{% block blog_child_summary %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% endcall %}
|
{% endcall %}
|
||||||
{% call layout.menu('blog-child-menu') %}
|
{% call layout.menu('blog-child-menu') %}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
{% set href=coop_url('/auth/account/') %}
|
{% set href=blog_url('/auth/account/') %}
|
||||||
<a
|
<a
|
||||||
href="{{ href }}"
|
href="{{ href }}"
|
||||||
class="justify-center cursor-pointer flex flex-row items-center p-3 gap-2 rounded bg-stone-200 text-black {{select_colours}}"
|
class="justify-center cursor-pointer flex flex-row items-center p-3 gap-2 rounded bg-stone-200 text-black {{select_colours}}"
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
id="menu-items-nav-wrapper">
|
id="menu-items-nav-wrapper">
|
||||||
{% from 'macros/scrolling_menu.html' import scrolling_menu with context %}
|
{% from 'macros/scrolling_menu.html' import scrolling_menu with context %}
|
||||||
{% call(item) scrolling_menu('menu-items-container', menu_items) %}
|
{% call(item) scrolling_menu('menu-items-container', menu_items) %}
|
||||||
{% set _href = _app_slugs.get(item.slug, coop_url('/' + item.slug + '/')) %}
|
{% set _href = _app_slugs.get(item.slug, blog_url('/' + item.slug + '/')) %}
|
||||||
<a
|
<a
|
||||||
href="{{ _href }}"
|
href="{{ _href }}"
|
||||||
aria-selected="{{ 'true' if (item.slug == _first_seg or item.slug == app_name) else 'false' }}"
|
aria-selected="{{ 'true' if (item.slug == _first_seg or item.slug == app_name) else 'false' }}"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{% import 'macros/links.html' as links %}
|
{% import 'macros/links.html' as links %}
|
||||||
{% if g.rights.admin %}
|
{% if g.rights.admin %}
|
||||||
<a href="{{ coop_url('/settings/') }}" class="{{styles.nav_button}}">
|
<a href="{{ blog_url('/settings/') }}" class="{{styles.nav_button}}">
|
||||||
<i class="fa fa-cog" aria-hidden="true"></i>
|
<i class="fa fa-cog" aria-hidden="true"></i>
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
← Go Back
|
← Go Back
|
||||||
</button>
|
</button>
|
||||||
<a
|
<a
|
||||||
href="{{ coop_url('/') }}"
|
href="{{ blog_url('/') }}"
|
||||||
class="px-4 py-2 bg-stone-800 text-white rounded hover:bg-stone-700 transition-colors text-center"
|
class="px-4 py-2 bg-stone-800 text-white rounded hover:bg-stone-700 transition-colors text-center"
|
||||||
>
|
>
|
||||||
Home
|
Home
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
{% set href=coop_url('/auth/account/') %}
|
{% set href=blog_url('/auth/account/') %}
|
||||||
<a
|
<a
|
||||||
href="{{ href }}"
|
href="{{ href }}"
|
||||||
data-close-details
|
data-close-details
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{% macro title(_class='') %}
|
{% macro title(_class='') %}
|
||||||
<a
|
<a
|
||||||
href="{{ coop_url('/') }}"
|
href="{{ blog_url('/') }}"
|
||||||
class="{{_class}}"
|
class="{{_class}}"
|
||||||
>
|
>
|
||||||
<h1>
|
<h1>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ from quart import Quart, g
|
|||||||
DATABASE_URL = (
|
DATABASE_URL = (
|
||||||
os.getenv("DATABASE_URL_ASYNC")
|
os.getenv("DATABASE_URL_ASYNC")
|
||||||
or os.getenv("DATABASE_URL")
|
or os.getenv("DATABASE_URL")
|
||||||
or "postgresql+asyncpg://localhost/coop"
|
or "postgresql+asyncpg://localhost/blog"
|
||||||
)
|
)
|
||||||
|
|
||||||
_engine = create_async_engine(
|
_engine = create_async_engine(
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ def _build_activity_json(activity: APActivity, actor: ActorProfile, domain: str)
|
|||||||
obj = dict(activity.object_data or {})
|
obj = dict(activity.object_data or {})
|
||||||
|
|
||||||
# Object id MUST be on the actor's domain (Mastodon origin check).
|
# Object id MUST be on the actor's domain (Mastodon origin check).
|
||||||
# The post URL (e.g. coop.rose-ash.com/slug/) goes in "url" only.
|
# The post URL (e.g. blog.rose-ash.com/slug/) goes in "url" only.
|
||||||
object_id = activity.activity_id + "/object"
|
object_id = activity.activity_id + "/object"
|
||||||
|
|
||||||
if activity.activity_type == "Delete":
|
if activity.activity_type == "Delete":
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ def create_base_app(
|
|||||||
context_fn:
|
context_fn:
|
||||||
Async function returning a dict for template context.
|
Async function returning a dict for template context.
|
||||||
Each app provides its own — the cart app queries locally,
|
Each app provides its own — the cart app queries locally,
|
||||||
while coop/market apps fetch via internal API.
|
while blog/market apps fetch via internal API.
|
||||||
If not provided, a minimal default context is used.
|
If not provided, a minimal default context is used.
|
||||||
before_request_fns:
|
before_request_fns:
|
||||||
Extra before-request hooks (e.g. cart_loader for the cart app).
|
Extra before-request hooks (e.g. cart_loader for the cart app).
|
||||||
@@ -84,7 +84,7 @@ def create_base_app(
|
|||||||
cookie_domain = os.getenv("SESSION_COOKIE_DOMAIN") # e.g. ".rose-ash.com"
|
cookie_domain = os.getenv("SESSION_COOKIE_DOMAIN") # e.g. ".rose-ash.com"
|
||||||
if cookie_domain:
|
if cookie_domain:
|
||||||
app.config["SESSION_COOKIE_DOMAIN"] = cookie_domain
|
app.config["SESSION_COOKIE_DOMAIN"] = cookie_domain
|
||||||
app.config["SESSION_COOKIE_NAME"] = "coop_session"
|
app.config["SESSION_COOKIE_NAME"] = "blog_session"
|
||||||
|
|
||||||
# Ghost / Redis config
|
# Ghost / Redis config
|
||||||
app.config["GHOST_API_URL"] = os.getenv("GHOST_API_URL")
|
app.config["GHOST_API_URL"] = os.getenv("GHOST_API_URL")
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ from shared.browser.app.csrf import generate_csrf_token
|
|||||||
from shared.browser.app.authz import has_access
|
from shared.browser.app.authz import has_access
|
||||||
from shared.browser.app.filters import register as register_filters
|
from shared.browser.app.filters import register as register_filters
|
||||||
|
|
||||||
from .urls import coop_url, market_url, cart_url, events_url, login_url, page_cart_url, market_product_url
|
from .urls import blog_url, market_url, cart_url, events_url, login_url, page_cart_url, market_product_url
|
||||||
|
|
||||||
|
|
||||||
def setup_jinja(app: Quart) -> None:
|
def setup_jinja(app: Quart) -> None:
|
||||||
@@ -93,7 +93,7 @@ def setup_jinja(app: Quart) -> None:
|
|||||||
app.jinja_env.globals["site"] = site
|
app.jinja_env.globals["site"] = site
|
||||||
|
|
||||||
# cross-app URL helpers available in all templates
|
# cross-app URL helpers available in all templates
|
||||||
app.jinja_env.globals["coop_url"] = coop_url
|
app.jinja_env.globals["blog_url"] = blog_url
|
||||||
app.jinja_env.globals["market_url"] = market_url
|
app.jinja_env.globals["market_url"] = market_url
|
||||||
app.jinja_env.globals["cart_url"] = cart_url
|
app.jinja_env.globals["cart_url"] = cart_url
|
||||||
app.jinja_env.globals["events_url"] = events_url
|
app.jinja_env.globals["events_url"] = events_url
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ def app_url(app_name: str, path: str = "/") -> str:
|
|||||||
return base + path
|
return base + path
|
||||||
|
|
||||||
|
|
||||||
def coop_url(path: str = "/") -> str:
|
def blog_url(path: str = "/") -> str:
|
||||||
return app_url("coop", path)
|
return app_url("blog", path)
|
||||||
|
|
||||||
|
|
||||||
def market_url(path: str = "/") -> str:
|
def market_url(path: str = "/") -> str:
|
||||||
@@ -66,9 +66,9 @@ def market_product_url(product_slug: str, suffix: str = "", market_place=None) -
|
|||||||
|
|
||||||
|
|
||||||
def login_url(next_url: str = "") -> str:
|
def login_url(next_url: str = "") -> str:
|
||||||
# Auth lives in blog (coop) for now. Set AUTH_APP=federation to switch.
|
# Auth lives in blog for now. Set AUTH_APP=federation to switch.
|
||||||
from quart import session as qsession
|
from quart import session as qsession
|
||||||
auth_app = os.getenv("AUTH_APP", "coop")
|
auth_app = os.getenv("AUTH_APP", "blog")
|
||||||
base = app_url(auth_app, "/auth/login/")
|
base = app_url(auth_app, "/auth/login/")
|
||||||
params: list[str] = []
|
params: list[str] = []
|
||||||
if next_url:
|
if next_url:
|
||||||
|
|||||||
@@ -48,8 +48,8 @@ class _WidgetRegistry:
|
|||||||
slug = w.slug
|
slug = w.slug
|
||||||
|
|
||||||
def _href(s=slug):
|
def _href(s=slug):
|
||||||
from shared.infrastructure.urls import coop_url
|
from shared.infrastructure.urls import blog_url
|
||||||
return coop_url(f"/auth/{s}/")
|
return blog_url(f"/auth/{s}/")
|
||||||
|
|
||||||
self._account_nav.append(AccountNavLink(
|
self._account_nav.append(AccountNavLink(
|
||||||
label=w.label,
|
label=w.label,
|
||||||
|
|||||||
Reference in New Issue
Block a user