Monorepo: consolidate 7 repos into one
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 1m5s

Combines shared, blog, market, cart, events, federation, and account
into a single repository. Eliminates submodule sync, sibling model
copying at build time, and per-app CI orchestration.

Changes:
- Remove per-app .git, .gitmodules, .gitea, submodule shared/ dirs
- Remove stale sibling model copies from each app
- Update all 6 Dockerfiles for monorepo build context (root = .)
- Add build directives to docker-compose.yml
- Add single .gitea/workflows/ci.yml with change detection
- Add .dockerignore for monorepo build context
- Create __init__.py for federation and account (cross-app imports)
This commit is contained in:
giles
2026-02-24 19:44:17 +00:00
commit f42042ccb7
895 changed files with 61147 additions and 0 deletions

View File

@@ -0,0 +1,18 @@
from ..ghost_db import DBClient
async def pages_data(session, page, search):
client = DBClient(session)
pages, pagination = await client.list_pages(
limit=10,
page=page,
search=search,
)
return {
"pages": pages,
"page": pagination.get("page", page),
"total_pages": pagination.get("pages", 1),
"search": search,
}

View File

@@ -0,0 +1,142 @@
import re
from ..ghost_db import DBClient # adjust import path
from sqlalchemy import select
from models.ghost_content import PostLike
from shared.infrastructure.fragments import fetch_fragment
from quart import g
async def posts_data(
session,
page, search, sort, selected_tags, selected_authors, liked,
drafts=False, drafts_user_id=None, count_drafts_for_user_id=None,
selected_groups=(),
):
client = DBClient(session)
# --- Tag-group resolution ---
tag_groups = await client.list_tag_groups_with_counts()
# Collect all assigned tag IDs across groups
all_assigned_tag_ids = []
for grp in tag_groups:
all_assigned_tag_ids.extend(grp["tag_ids"])
# Build slug-lookup for groups
group_by_slug = {grp["slug"]: grp for grp in tag_groups}
# Resolve selected group → post filtering
# Groups and tags are mutually exclusive — groups override tags when set
effective_tags = selected_tags
etc_mode_tag_ids = None # set when "etc" is selected
if selected_groups:
group_slug = selected_groups[0]
if group_slug == "etc":
# etc = posts NOT covered by any group (includes untagged)
etc_mode_tag_ids = all_assigned_tag_ids
effective_tags = ()
elif group_slug in group_by_slug:
effective_tags = tuple(group_by_slug[group_slug]["tag_slugs"])
# Compute "etc" virtual group
etc_count = await client.count_etc_posts(all_assigned_tag_ids)
if etc_count > 0 or (selected_groups and selected_groups[0] == "etc"):
tag_groups.append({
"id": None,
"name": "etc",
"slug": "etc",
"feature_image": None,
"colour": None,
"sort_order": 999999,
"post_count": etc_count,
"tag_slugs": [],
"tag_ids": [],
})
posts, pagination = await client.list_posts(
limit=10,
page=page,
selected_tags=effective_tags,
selected_authors=selected_authors,
search=search,
drafts=drafts,
drafts_user_id=drafts_user_id,
exclude_covered_tag_ids=etc_mode_tag_ids,
)
# Get all post IDs in this batch
post_ids = [p["id"] for p in posts]
# Add is_liked field to each post for current user
if g.user:
# Fetch all likes for this user and these posts in one query
liked_posts = await session.execute(
select(PostLike.post_id).where(
PostLike.user_id == g.user.id,
PostLike.post_id.in_(post_ids),
PostLike.deleted_at.is_(None),
)
)
liked_post_ids = {row[0] for row in liked_posts}
# Add is_liked to each post
for post in posts:
post["is_liked"] = post["id"] in liked_post_ids
else:
# Not logged in - no posts are liked
for post in posts:
post["is_liked"] = False
# Fetch card decoration fragments from events
card_widgets_html = {}
if post_ids:
post_slugs = [p.get("slug", "") for p in posts]
cards_html = await fetch_fragment("events", "container-cards", params={
"post_ids": ",".join(str(pid) for pid in post_ids),
"post_slugs": ",".join(post_slugs),
})
if cards_html:
card_widgets_html = _parse_card_fragments(cards_html)
tags=await client.list_tags(
limit=50000
)
authors=await client.list_authors(
limit=50000
)
# Draft count for the logged-in user (None → admin sees all)
draft_count = 0
if count_drafts_for_user_id is not False:
draft_count = await client.count_drafts(user_id=count_drafts_for_user_id)
return {
"posts": posts,
"page": pagination.get("page", page),
"total_pages": pagination.get("pages", 1),
"search_count": pagination.get("search_count"),
"tags": tags,
"authors": authors,
"draft_count": draft_count,
"tag_groups": tag_groups,
"selected_groups": selected_groups,
"card_widgets_html": card_widgets_html,
}
# Regex to extract per-post blocks delimited by comment markers
_CARD_MARKER_RE = re.compile(
r'<!-- card-widget:(\d+) -->(.*?)<!-- /card-widget:\1 -->',
re.DOTALL,
)
def _parse_card_fragments(html: str) -> dict[str, str]:
"""Parse the container-cards fragment into {post_id_str: html} dict."""
result = {}
for m in _CARD_MARKER_RE.finditer(html):
post_id_str = m.group(1)
inner = m.group(2).strip()
if inner:
result[post_id_str] = inner
return result