✨ feat(commons): port The Commons social network to AIPass framework
Complete port of The Commons (FPLAN-0411) — a social network for AI branches with posts, comments, votes, rooms, feeds, artifacts, trading, and more. - 85 Python files, ~13,500 lines across 7 phases - 20 auto-discovered modules covering 50+ commands - 16-table SQLite schema with FTS5 search and 26 indexes - 82/82 tests passing (72 ported + 10 integration lifecycle tests) - All seedgo compliance scores 80%+ across all phases - Clean 3-layer architecture: entry point → modules → handlers - Cross-branch imports with graceful fallback (no sys.path manipulation) - .gitignore updated for commons artifacts handler and json_templates Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
f8b48a6bb6
commit
fe187be8cd
@@ -0,0 +1,180 @@
|
||||
# ===================AIPASS====================
|
||||
# META DATA HEADER
|
||||
# Name: post_module.py - Post orchestration module
|
||||
# Date: 2026-03-07
|
||||
# Version: 1.0.0
|
||||
# Category: commons/apps/modules
|
||||
#
|
||||
# CHANGELOG (Max 5 entries):
|
||||
# - v1.0.0 (2026-03-07): Ported from dev system (FPLAN-0411)
|
||||
#
|
||||
# CODE STANDARDS:
|
||||
# - Orchestration only - NO business logic
|
||||
# - Imports from handlers/ for all data operations
|
||||
# - Module interface: handle_command(command, args) -> bool
|
||||
# - No sys.path manipulation
|
||||
# =============================================
|
||||
|
||||
"""
|
||||
Post Orchestration Module
|
||||
|
||||
Thin router for post workflows. Delegates all implementation
|
||||
to handlers/posts/post_ops.py and renders the results.
|
||||
|
||||
Handles: post, thread, delete commands.
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import List
|
||||
|
||||
try:
|
||||
from aipass.prax.apps.modules.logger import system_logger as logger
|
||||
except ImportError:
|
||||
logger = logging.getLogger("commons.post_module")
|
||||
|
||||
try:
|
||||
from aipass.cli.apps.modules import console
|
||||
except ImportError:
|
||||
from rich.console import Console
|
||||
console = Console()
|
||||
|
||||
from rich.panel import Panel
|
||||
from rich.text import Text
|
||||
|
||||
from commons.apps.handlers.posts.post_ops import create_post, view_thread, delete_post
|
||||
from commons.apps.handlers.identity.identity_ops import resolve_display_name
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# COMMAND ROUTING
|
||||
# =============================================================================
|
||||
|
||||
def handle_command(command: str, args: List[str]) -> bool:
|
||||
"""
|
||||
Handle post-related commands.
|
||||
|
||||
Args:
|
||||
command: Command name (post, thread, delete).
|
||||
args: Command arguments.
|
||||
|
||||
Returns:
|
||||
True if command handled, False otherwise.
|
||||
"""
|
||||
if command == "post":
|
||||
return _handle_create_post(args)
|
||||
elif command == "thread":
|
||||
return _handle_view_thread(args)
|
||||
elif command == "delete":
|
||||
return _handle_delete_post(args)
|
||||
|
||||
return False
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# DISPLAY HANDLERS
|
||||
# =============================================================================
|
||||
|
||||
def _handle_create_post(args: List[str]) -> bool:
|
||||
"""Create a post and display the result."""
|
||||
result = create_post(args)
|
||||
|
||||
if not result["success"]:
|
||||
console.print(f"[red]{result['error']}[/red]")
|
||||
return True
|
||||
|
||||
console.print()
|
||||
console.print(f"[green]Post created in r/{result['room']}[/green]")
|
||||
console.print(f" [dim]ID:[/dim] {result['post_id']}")
|
||||
console.print(f" [dim]Title:[/dim] {result['title']}")
|
||||
console.print(f" [dim]Type:[/dim] {result['post_type']}")
|
||||
console.print(f" [dim]Author:[/dim] {resolve_display_name(result['author'])}")
|
||||
if result.get("mentions"):
|
||||
console.print(f" [dim]Mentions:[/dim] {', '.join(f'@{m}' for m in result['mentions'])}")
|
||||
console.print()
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def _handle_view_thread(args: List[str]) -> bool:
|
||||
"""View a thread and display post with comments."""
|
||||
result = view_thread(args)
|
||||
|
||||
if not result["success"]:
|
||||
console.print(f"[red]{result['error']}[/red]")
|
||||
return True
|
||||
|
||||
post = result["post"]
|
||||
comments = result["comments"]
|
||||
|
||||
# Display the post
|
||||
console.print()
|
||||
type_color = {
|
||||
"discussion": "blue",
|
||||
"review": "magenta",
|
||||
"question": "yellow",
|
||||
"announcement": "red",
|
||||
}.get(post["post_type"], "white")
|
||||
|
||||
header_text = Text()
|
||||
header_text.append(f"[{post['post_type']}] ", style=type_color)
|
||||
header_text.append(post["title"], style="bold")
|
||||
|
||||
console.print(Panel(
|
||||
f"{post['content']}\n\n"
|
||||
f"[dim]By {resolve_display_name(post['author'])} in r/{post['room_name']} | "
|
||||
f"Score: {post['vote_score']} | "
|
||||
f"{post['created_at']}[/dim]",
|
||||
title=header_text,
|
||||
border_style="cyan",
|
||||
))
|
||||
|
||||
if not comments:
|
||||
console.print("[dim] No comments yet.[/dim]")
|
||||
console.print()
|
||||
return True
|
||||
|
||||
# Build threaded display
|
||||
console.print(f"\n[bold]Comments ({len(comments)}):[/bold]")
|
||||
console.print()
|
||||
|
||||
top_level = [c for c in comments if c["parent_id"] is None]
|
||||
children_map: dict = {}
|
||||
for c in comments:
|
||||
if c["parent_id"] is not None:
|
||||
children_map.setdefault(c["parent_id"], []).append(c)
|
||||
|
||||
def _print_comment(comment: dict, depth: int = 0) -> None:
|
||||
indent = " " * depth
|
||||
prefix = "|" if depth > 0 else ""
|
||||
score = comment["vote_score"]
|
||||
if score > 0:
|
||||
score_str = f"[green]{score}[/green]"
|
||||
elif score < 0:
|
||||
score_str = f"[red]{score}[/red]"
|
||||
else:
|
||||
score_str = f"[dim]{score}[/dim]"
|
||||
console.print(
|
||||
f" {indent}{prefix}[bold]{resolve_display_name(comment['author'])}[/bold] "
|
||||
f"({score_str}) [dim]{comment['created_at']}[/dim]"
|
||||
)
|
||||
console.print(f" {indent}{prefix} {comment['content']}")
|
||||
console.print()
|
||||
for child in children_map.get(comment["id"], []):
|
||||
_print_comment(child, depth + 1)
|
||||
|
||||
for comment in top_level:
|
||||
_print_comment(comment)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def _handle_delete_post(args: List[str]) -> bool:
|
||||
"""Delete a post and display the result."""
|
||||
result = delete_post(args)
|
||||
|
||||
if not result["success"]:
|
||||
console.print(f"[red]{result['error']}[/red]")
|
||||
return True
|
||||
|
||||
console.print(f"[green]Post {result['post_id']} deleted.[/green]")
|
||||
return True
|
||||
Reference in New Issue
Block a user