1010from app .schemas import PageCreate , PageUpdate , PageResponse , PageListResponse , PageMoveRequest
1111from app .auth import get_current_user
1212from app .database import get_db , write_transaction
13- from app .services .acl import invalidate_readable_cache , list_readable_page_ids , resolve_page_permission
13+ from app .services .acl import build_id_clause , invalidate_readable_cache , list_readable_page_ids , resolve_page_permission
1414from app .services .search import rebuild_search_index , remove_from_search_index
1515from app .services .wikilink import parse_and_update_backlinks
1616from app .services .media_ref import parse_and_update_media_refs
1717from app .routers .activity import log_activity
1818from app .routers .versions import save_version
19+ from app .services .notifications import (
20+ notify_page_created ,
21+ notify_page_deleted ,
22+ notify_page_updated ,
23+ )
1924
2025router = APIRouter (prefix = "/api/pages" , tags = ["pages" ])
2126
@@ -60,20 +65,6 @@ async def _should_count_view(db, user_id: int, page_id: int) -> bool:
6065 return True
6166
6267
63- def _build_id_clause (ids : set [int ], column : str = "id" ) -> tuple [str , list ]:
64- """Produce a parameterized ``column IN (SELECT value FROM json_each(?))``
65- clause plus params.
66-
67- Uses ``json_each`` instead of ``IN (?,?,...)`` to avoid hitting
68- SQLite's ``SQLITE_MAX_VARIABLE_NUMBER`` limit on large page sets.
69- For the empty set, returns a clause that never matches so downstream
70- SQL can be composed without branching.
71- """
72- if not ids :
73- return "0 = 1" , []
74- return f"{ column } IN (SELECT value FROM json_each(?))" , [json .dumps (list (ids ))]
75-
76-
7768def slugify (title : str , existing_slug : str | None = None ) -> str :
7869 """Generate a URL-friendly slug from title. Preserves CJK characters so
7970 Chinese/Japanese/Korean titles show up in the URL as-is rather than pinyin."""
@@ -139,7 +130,7 @@ async def list_pages(
139130 offset = (page - 1 ) * per_page
140131
141132 readable = await list_readable_page_ids (db , user )
142- id_clause , id_params = _build_id_clause (readable )
133+ id_clause , id_params = build_id_clause (readable )
143134
144135 where = f"WHERE deleted_at IS NULL AND { id_clause } "
145136 params : list = list (id_params )
@@ -164,7 +155,7 @@ async def list_pages(
164155async def page_tree (user = Depends (get_current_user )):
165156 db = await get_db ()
166157 readable = await list_readable_page_ids (db , user )
167- id_clause , id_params = _build_id_clause (readable )
158+ id_clause , id_params = build_id_clause (readable )
168159 rows = await db .execute_fetchall (
169160 f"SELECT id, slug, title, parent_id, sort_order FROM pages "
170161 f"WHERE deleted_at IS NULL AND { id_clause } "
@@ -205,7 +196,7 @@ def build_tree(parent_id):
205196async def page_graph (user = Depends (get_current_user )):
206197 db = await get_db ()
207198 readable = await list_readable_page_ids (db , user )
208- id_clause , id_params = _build_id_clause (readable )
199+ id_clause , id_params = build_id_clause (readable )
209200 pages = await db .execute_fetchall (
210201 f"SELECT id, slug, title, parent_id FROM pages WHERE deleted_at IS NULL AND { id_clause } " ,
211202 id_params ,
@@ -312,7 +303,6 @@ async def create_page(body: PageCreate, user=Depends(get_current_user)):
312303 new_page = dict (rows [0 ])
313304
314305 # Fire notification
315- from app .services .notifications import notify_page_created
316306 await notify_page_created (db , new_page , user )
317307
318308 return new_page
@@ -468,7 +458,6 @@ async def update_page(slug: str, body: PageUpdate, user=Depends(get_current_user
468458
469459 # Fire notifications if content/title actually changed
470460 if content_changed or title_changed :
471- from app .services .notifications import notify_page_updated
472461 await notify_page_updated (db , updated , user , {"title_changed" : title_changed , "content_changed" : content_changed })
473462
474463 return updated
@@ -487,7 +476,7 @@ async def get_children(slug: str, user=Depends(get_current_user)):
487476 raise HTTPException (status_code = 404 , detail = "Page not found" )
488477
489478 readable = await list_readable_page_ids (db , user )
490- id_clause , id_params = _build_id_clause (readable )
479+ id_clause , id_params = build_id_clause (readable )
491480 children = await db .execute_fetchall (
492481 f"SELECT * FROM pages WHERE parent_id = ? AND deleted_at IS NULL AND { id_clause } "
493482 f"ORDER BY sort_order, title" ,
@@ -509,7 +498,7 @@ async def get_backlinks(slug: str, user=Depends(get_current_user)):
509498 raise HTTPException (status_code = 404 , detail = "Page not found" )
510499
511500 readable = await list_readable_page_ids (db , user )
512- id_clause , id_params = _build_id_clause (readable , column = "p.id" )
501+ id_clause , id_params = build_id_clause (readable , column = "p.id" )
513502 backlinks = await db .execute_fetchall (
514503 f"""SELECT p.id, p.slug, p.title
515504 FROM backlinks b
@@ -622,7 +611,6 @@ async def delete_page(slug: str, user=Depends(get_current_user)):
622611 invalidate_readable_cache ()
623612
624613 # Fire notification
625- from app .services .notifications import notify_page_deleted
626614 await notify_page_deleted (db , {"id" : page_id , "title" : page_title , "slug" : slug }, user )
627615
628616 return {"ok" : True }
0 commit comments