#!/usr/bin/env python3 """ InsightFlow Developer Ecosystem Manager - Phase 8 Task 6 开发者生态系统模块 - SDK 发布与管理(Python/JavaScript/Go) - 模板市场(行业模板、预训练模型) - 插件市场(第三方插件审核与分发) - 开发者文档与示例代码 作者: InsightFlow Team """ import json import os import sqlite3 import uuid from dataclasses import dataclass from datetime import datetime from enum import StrEnum # Database path DB_PATH = os.path.join(os.path.dirname(__file__), "insightflow.db") class SDKLanguage(StrEnum): """SDK 语言类型""" PYTHON = "python" JAVASCRIPT = "javascript" TYPESCRIPT = "typescript" GO = "go" JAVA = "java" RUST = "rust" class SDKStatus(StrEnum): """SDK 状态""" DRAFT = "draft" # 草稿 BETA = "beta" # 测试版 STABLE = "stable" # 稳定版 DEPRECATED = "deprecated" # 已弃用 ARCHIVED = "archived" # 已归档 class TemplateCategory(StrEnum): """模板分类""" MEDICAL = "medical" # 医疗 LEGAL = "legal" # 法律 FINANCE = "finance" # 金融 EDUCATION = "education" # 教育 TECH = "tech" # 科技 GENERAL = "general" # 通用 class TemplateStatus(StrEnum): """模板状态""" PENDING = "pending" # 待审核 APPROVED = "approved" # 已通过 REJECTED = "rejected" # 已拒绝 PUBLISHED = "published" # 已发布 UNLISTED = "unlisted" # 未列出 class PluginStatus(StrEnum): """插件状态""" PENDING = "pending" # 待审核 REVIEWING = "reviewing" # 审核中 APPROVED = "approved" # 已通过 REJECTED = "rejected" # 已拒绝 PUBLISHED = "published" # 已发布 SUSPENDED = "suspended" # 已暂停 class PluginCategory(StrEnum): """插件分类""" INTEGRATION = "integration" # 集成 ANALYSIS = "analysis" # 分析 VISUALIZATION = "visualization" # 可视化 AUTOMATION = "automation" # 自动化 SECURITY = "security" # 安全 CUSTOM = "custom" # 自定义 class DeveloperStatus(StrEnum): """开发者认证状态""" UNVERIFIED = "unverified" # 未认证 PENDING = "pending" # 审核中 VERIFIED = "verified" # 已认证 CERTIFIED = "certified" # 已认证(高级) SUSPENDED = "suspended" # 已暂停 @dataclass class SDKRelease: """SDK 发布""" id: str name: str language: SDKLanguage version: str description: str changelog: str download_url: str documentation_url: str repository_url: str package_name: str # pip/npm/go module name status: SDKStatus min_platform_version: str dependencies: list[dict] # [{"name": "requests", "version": ">= 2.0"}] file_size: int checksum: str download_count: int created_at: str updated_at: str published_at: str | None created_by: str @dataclass class SDKVersion: """SDK 版本历史""" id: str sdk_id: str version: str is_latest: bool is_lts: bool # 长期支持版本 release_notes: str download_url: str checksum: str file_size: int download_count: int created_at: str @dataclass class TemplateMarketItem: """模板市场项目""" id: str name: str description: str category: TemplateCategory subcategory: str | None tags: list[str] author_id: str author_name: str status: TemplateStatus price: float # 0 = 免费 currency: str preview_image_url: str | None demo_url: str | None documentation_url: str | None download_url: str | None install_count: int rating: float rating_count: int review_count: int version: str min_platform_version: str file_size: int checksum: str created_at: str updated_at: str published_at: str | None @dataclass class TemplateReview: """模板评价""" id: str template_id: str user_id: str user_name: str rating: int # 1-5 comment: str is_verified_purchase: bool helpful_count: int created_at: str updated_at: str @dataclass class PluginMarketItem: """插件市场项目""" id: str name: str description: str category: PluginCategory tags: list[str] author_id: str author_name: str status: PluginStatus price: float currency: str pricing_model: str # free, paid, freemium, subscription preview_image_url: str | None demo_url: str | None documentation_url: str | None repository_url: str | None download_url: str | None webhook_url: str | None # 用于插件回调 permissions: list[str] # 需要的权限列表 install_count: int active_install_count: int rating: float rating_count: int review_count: int version: str min_platform_version: str file_size: int checksum: str created_at: str updated_at: str published_at: str | None reviewed_by: str | None reviewed_at: str | None review_notes: str | None @dataclass class PluginReview: """插件评价""" id: str plugin_id: str user_id: str user_name: str rating: int comment: str is_verified_purchase: bool helpful_count: int created_at: str updated_at: str @dataclass class DeveloperProfile: """开发者档案""" id: str user_id: str display_name: str email: str bio: str | None website: str | None github_url: str | None avatar_url: str | None status: DeveloperStatus verification_documents: dict # 认证文档 total_sales: float total_downloads: int plugin_count: int template_count: int rating_average: float created_at: str updated_at: str verified_at: str | None @dataclass class DeveloperRevenue: """开发者收益""" id: str developer_id: str item_type: str # plugin, template item_id: str item_name: str sale_amount: float platform_fee: float developer_earnings: float currency: str buyer_id: str transaction_id: str created_at: str @dataclass class CodeExample: """代码示例""" id: str title: str description: str language: str category: str code: str explanation: str tags: list[str] author_id: str author_name: str sdk_id: str | None # 关联的 SDK api_endpoints: list[str] # 涉及的 API 端点 view_count: int copy_count: int rating: float created_at: str updated_at: str @dataclass class APIDocumentation: """API 文档生成记录""" id: str version: str openapi_spec: str # OpenAPI JSON markdown_content: str html_content: str changelog: str generated_at: str generated_by: str @dataclass class DeveloperPortalConfig: """开发者门户配置""" id: str name: str description: str theme: str custom_css: str | None custom_js: str | None logo_url: str | None favicon_url: str | None primary_color: str secondary_color: str support_email: str support_url: str | None github_url: str | None discord_url: str | None api_base_url: str is_active: bool created_at: str updated_at: str class DeveloperEcosystemManager: """开发者生态系统管理主类""" def __init__(self, db_path: str = DB_PATH) -> None: self.db_path = db_path self.platform_fee_rate = 0.30 # 平台抽成比例 30% def _get_db(self) -> None: """获取数据库连接""" conn = sqlite3.connect(self.db_path) conn.row_factory = sqlite3.Row return conn # ==================== SDK 发布与管理 ==================== def create_sdk_release( self, name: str, language: SDKLanguage, version: str, description: str, changelog: str, download_url: str, documentation_url: str, repository_url: str, package_name: str, min_platform_version: str, dependencies: list[dict], file_size: int, checksum: str, created_by: str, ) -> SDKRelease: """创建 SDK 发布""" sdk_id = f"sdk_{uuid.uuid4().hex[:16]}" now = datetime.now().isoformat() sdk = SDKRelease( id=sdk_id, name=name, language=language, version=version, description=description, changelog=changelog, download_url=download_url, documentation_url=documentation_url, repository_url=repository_url, package_name=package_name, status=SDKStatus.DRAFT, min_platform_version=min_platform_version, dependencies=dependencies, file_size=file_size, checksum=checksum, download_count=0, created_at=now, updated_at=now, published_at=None, created_by=created_by, ) with self._get_db() as conn: conn.execute( """ INSERT INTO sdk_releases (id, name, language, version, description, changelog, download_url, documentation_url, repository_url, package_name, status, min_platform_version, dependencies, file_size, checksum, download_count, created_at, updated_at, published_at, created_by) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) """, ( sdk.id, sdk.name, sdk.language.value, sdk.version, sdk.description, sdk.changelog, sdk.download_url, sdk.documentation_url, sdk.repository_url, sdk.package_name, sdk.status.value, sdk.min_platform_version, json.dumps(sdk.dependencies), sdk.file_size, sdk.checksum, sdk.download_count, sdk.created_at, sdk.updated_at, sdk.published_at, sdk.created_by, ), ) conn.commit() return sdk def get_sdk_release(self, sdk_id: str) -> SDKRelease | None: """获取 SDK 发布详情""" with self._get_db() as conn: row = conn.execute("SELECT * FROM sdk_releases WHERE id = ?", (sdk_id,)).fetchone() if row: return self._row_to_sdk_release(row) return None def list_sdk_releases( self, language: SDKLanguage | None = None, status: SDKStatus | None = None, search: str | None = None, ) -> list[SDKRelease]: """列出 SDK 发布""" query = "SELECT * FROM sdk_releases WHERE 1 = 1" params = [] if language: query += " AND language = ?" params.append(language.value) if status: query += " AND status = ?" params.append(status.value) if search: query += " AND (name LIKE ? OR description LIKE ? OR package_name LIKE ?)" params.extend([f"%{search}%", f"%{search}%", f"%{search}%"]) query += " ORDER BY created_at DESC" with self._get_db() as conn: rows = conn.execute(query, params).fetchall() return [self._row_to_sdk_release(row) for row in rows] def update_sdk_release(self, sdk_id: str, **kwargs) -> SDKRelease | None: """更新 SDK 发布""" allowed_fields = [ "name", "description", "changelog", "download_url", "documentation_url", "repository_url", "status", ] updates = {k: v for k, v in kwargs.items() if k in allowed_fields} if not updates: return self.get_sdk_release(sdk_id) updates["updated_at"] = datetime.now().isoformat() with self._get_db() as conn: set_clause = ", ".join([f"{k} = ?" for k in updates]) conn.execute( f"UPDATE sdk_releases SET {set_clause} WHERE id = ?", list(updates.values()) + [sdk_id], ) conn.commit() return self.get_sdk_release(sdk_id) def publish_sdk_release(self, sdk_id: str) -> SDKRelease | None: """发布 SDK""" now = datetime.now().isoformat() with self._get_db() as conn: conn.execute( """ UPDATE sdk_releases SET status = ?, published_at = ?, updated_at = ? WHERE id = ? """, (SDKStatus.STABLE.value, now, now, sdk_id), ) conn.commit() return self.get_sdk_release(sdk_id) def increment_sdk_download(self, sdk_id: str) -> None: """增加 SDK 下载计数""" with self._get_db() as conn: conn.execute( """ UPDATE sdk_releases SET download_count = download_count + 1 WHERE id = ? """, (sdk_id,), ) conn.commit() def get_sdk_versions(self, sdk_id: str) -> list[SDKVersion]: """获取 SDK 版本历史""" with self._get_db() as conn: rows = conn.execute( "SELECT * FROM sdk_versions WHERE sdk_id = ? ORDER BY created_at DESC", (sdk_id,), ).fetchall() return [self._row_to_sdk_version(row) for row in rows] def add_sdk_version( self, sdk_id: str, version: str, is_lts: bool, release_notes: str, download_url: str, checksum: str, file_size: int, ) -> SDKVersion: """添加 SDK 版本""" version_id = f"sv_{uuid.uuid4().hex[:16]}" now = datetime.now().isoformat() with self._get_db() as conn: # 如果设置为最新版本,取消其他版本的最新标记 if True: # 默认新版本为最新 conn.execute("UPDATE sdk_versions SET is_latest = 0 WHERE sdk_id = ?", (sdk_id,)) conn.execute( """ INSERT INTO sdk_versions (id, sdk_id, version, is_latest, is_lts, release_notes, download_url, checksum, file_size, download_count, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) """, ( version_id, sdk_id, version, True, is_lts, release_notes, download_url, checksum, file_size, 0, now, ), ) conn.commit() return SDKVersion( id=version_id, sdk_id=sdk_id, version=version, is_latest=True, is_lts=is_lts, release_notes=release_notes, download_url=download_url, checksum=checksum, file_size=file_size, download_count=0, created_at=now, ) # ==================== 模板市场 ==================== def create_template( self, name: str, description: str, category: TemplateCategory, subcategory: str | None, tags: list[str], author_id: str, author_name: str, price: float = 0.0, currency: str = "CNY", preview_image_url: str | None = None, demo_url: str | None = None, documentation_url: str | None = None, download_url: str | None = None, version: str = "1.0.0", min_platform_version: str = "1.0.0", file_size: int = 0, checksum: str = "", ) -> TemplateMarketItem: """创建模板""" template_id = f"tpl_{uuid.uuid4().hex[:16]}" now = datetime.now().isoformat() template = TemplateMarketItem( id=template_id, name=name, description=description, category=category, subcategory=subcategory, tags=tags, author_id=author_id, author_name=author_name, status=TemplateStatus.PENDING, price=price, currency=currency, preview_image_url=preview_image_url, demo_url=demo_url, documentation_url=documentation_url, download_url=download_url, install_count=0, rating=0.0, rating_count=0, review_count=0, version=version, min_platform_version=min_platform_version, file_size=file_size, checksum=checksum, created_at=now, updated_at=now, published_at=None, ) with self._get_db() as conn: conn.execute( """ INSERT INTO template_market (id, name, description, category, subcategory, tags, author_id, author_name, status, price, currency, preview_image_url, demo_url, documentation_url, download_url, install_count, rating, rating_count, review_count, version, min_platform_version, file_size, checksum, created_at, updated_at, published_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) """, ( template.id, template.name, template.description, template.category.value, template.subcategory, json.dumps(template.tags), template.author_id, template.author_name, template.status.value, template.price, template.currency, template.preview_image_url, template.demo_url, template.documentation_url, template.download_url, template.install_count, template.rating, template.rating_count, template.review_count, template.version, template.min_platform_version, template.file_size, template.checksum, template.created_at, template.updated_at, template.published_at, ), ) conn.commit() return template def get_template(self, template_id: str) -> TemplateMarketItem | None: """获取模板详情""" with self._get_db() as conn: row = conn.execute( "SELECT * FROM template_market WHERE id = ?", (template_id,), ).fetchone() if row: return self._row_to_template(row) return None def list_templates( self, category: TemplateCategory | None = None, status: TemplateStatus | None = None, search: str | None = None, author_id: str | None = None, min_price: float | None = None, max_price: float | None = None, sort_by: str = "created_at", ) -> list[TemplateMarketItem]: """列出模板""" query = "SELECT * FROM template_market WHERE 1 = 1" params = [] if category: query += " AND category = ?" params.append(category.value) if status: query += " AND status = ?" params.append(status.value) if author_id: query += " AND author_id = ?" params.append(author_id) if search: query += " AND (name LIKE ? OR description LIKE ? OR tags LIKE ?)" params.extend([f"%{search}%", f"%{search}%", f"%{search}%"]) if min_price is not None: query += " AND price >= ?" params.append(min_price) if max_price is not None: query += " AND price <= ?" params.append(max_price) # 排序 sort_mapping = { "created_at": "created_at DESC", "rating": "rating DESC", "install_count": "install_count DESC", "price": "price ASC", "name": "name ASC", } query += f" ORDER BY {sort_mapping.get(sort_by, 'created_at DESC')}" with self._get_db() as conn: rows = conn.execute(query, params).fetchall() return [self._row_to_template(row) for row in rows] def approve_template(self, template_id: str, reviewed_by: str) -> TemplateMarketItem | None: """审核通过模板""" now = datetime.now().isoformat() with self._get_db() as conn: conn.execute( """ UPDATE template_market SET status = ?, updated_at = ? WHERE id = ? """, (TemplateStatus.APPROVED.value, now, template_id), ) conn.commit() return self.get_template(template_id) def publish_template(self, template_id: str) -> TemplateMarketItem | None: """发布模板""" now = datetime.now().isoformat() with self._get_db() as conn: conn.execute( """ UPDATE template_market SET status = ?, published_at = ?, updated_at = ? WHERE id = ? """, (TemplateStatus.PUBLISHED.value, now, now, template_id), ) conn.commit() return self.get_template(template_id) def reject_template(self, template_id: str, reason: str) -> TemplateMarketItem | None: """拒绝模板""" now = datetime.now().isoformat() with self._get_db() as conn: conn.execute( """ UPDATE template_market SET status = ?, updated_at = ? WHERE id = ? """, (TemplateStatus.REJECTED.value, now, template_id), ) conn.commit() return self.get_template(template_id) def increment_template_install(self, template_id: str) -> None: """增加模板安装计数""" with self._get_db() as conn: conn.execute( """ UPDATE template_market SET install_count = install_count + 1 WHERE id = ? """, (template_id,), ) conn.commit() def add_template_review( self, template_id: str, user_id: str, user_name: str, rating: int, comment: str, is_verified_purchase: bool = False, ) -> TemplateReview: """添加模板评价""" review_id = f"tr_{uuid.uuid4().hex[:16]}" now = datetime.now().isoformat() review = TemplateReview( id=review_id, template_id=template_id, user_id=user_id, user_name=user_name, rating=rating, comment=comment, is_verified_purchase=is_verified_purchase, helpful_count=0, created_at=now, updated_at=now, ) with self._get_db() as conn: conn.execute( """ INSERT INTO template_reviews (id, template_id, user_id, user_name, rating, comment, is_verified_purchase, helpful_count, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) """, ( review.id, review.template_id, review.user_id, review.user_name, review.rating, review.comment, review.is_verified_purchase, review.helpful_count, review.created_at, review.updated_at, ), ) # 更新模板评分 self._update_template_rating(conn, template_id) conn.commit() return review def _update_template_rating(self, conn, template_id: str) -> None: """更新模板评分""" row = conn.execute( """ SELECT AVG(rating) as avg_rating, COUNT(*) as count FROM template_reviews WHERE template_id = ? """, (template_id,), ).fetchone() if row: conn.execute( """ UPDATE template_market SET rating = ?, rating_count = ?, review_count = ? WHERE id = ? """, ( round(row["avg_rating"], 2) if row["avg_rating"] else 0, row["count"], row["count"], template_id, ), ) def get_template_reviews(self, template_id: str, limit: int = 50) -> list[TemplateReview]: """获取模板评价""" with self._get_db() as conn: rows = conn.execute( """SELECT * FROM template_reviews WHERE template_id = ? ORDER BY created_at DESC LIMIT ?""", (template_id, limit), ).fetchall() return [self._row_to_template_review(row) for row in rows] # ==================== 插件市场 ==================== def create_plugin( self, name: str, description: str, category: PluginCategory, tags: list[str], author_id: str, author_name: str, price: float = 0.0, currency: str = "CNY", pricing_model: str = "free", preview_image_url: str | None = None, demo_url: str | None = None, documentation_url: str | None = None, repository_url: str | None = None, download_url: str | None = None, webhook_url: str | None = None, permissions: list[str] = None, version: str = "1.0.0", min_platform_version: str = "1.0.0", file_size: int = 0, checksum: str = "", ) -> PluginMarketItem: """创建插件""" plugin_id = f"plg_{uuid.uuid4().hex[:16]}" now = datetime.now().isoformat() plugin = PluginMarketItem( id=plugin_id, name=name, description=description, category=category, tags=tags, author_id=author_id, author_name=author_name, status=PluginStatus.PENDING, price=price, currency=currency, pricing_model=pricing_model, preview_image_url=preview_image_url, demo_url=demo_url, documentation_url=documentation_url, repository_url=repository_url, download_url=download_url, webhook_url=webhook_url, permissions=permissions or [], install_count=0, active_install_count=0, rating=0.0, rating_count=0, review_count=0, version=version, min_platform_version=min_platform_version, file_size=file_size, checksum=checksum, created_at=now, updated_at=now, published_at=None, reviewed_by=None, reviewed_at=None, review_notes=None, ) with self._get_db() as conn: conn.execute( """ INSERT INTO plugin_market (id, name, description, category, tags, author_id, author_name, status, price, currency, pricing_model, preview_image_url, demo_url, documentation_url, repository_url, download_url, webhook_url, permissions, install_count, active_install_count, rating, rating_count, review_count, version, min_platform_version, file_size, checksum, created_at, updated_at, published_at, reviewed_by, reviewed_at, review_notes) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) """, ( plugin.id, plugin.name, plugin.description, plugin.category.value, json.dumps(plugin.tags), plugin.author_id, plugin.author_name, plugin.status.value, plugin.price, plugin.currency, plugin.pricing_model, plugin.preview_image_url, plugin.demo_url, plugin.documentation_url, plugin.repository_url, plugin.download_url, plugin.webhook_url, json.dumps(plugin.permissions), plugin.install_count, plugin.active_install_count, plugin.rating, plugin.rating_count, plugin.review_count, plugin.version, plugin.min_platform_version, plugin.file_size, plugin.checksum, plugin.created_at, plugin.updated_at, plugin.published_at, plugin.reviewed_by, plugin.reviewed_at, plugin.review_notes, ), ) conn.commit() return plugin def get_plugin(self, plugin_id: str) -> PluginMarketItem | None: """获取插件详情""" with self._get_db() as conn: row = conn.execute("SELECT * FROM plugin_market WHERE id = ?", (plugin_id,)).fetchone() if row: return self._row_to_plugin(row) return None def list_plugins( self, category: PluginCategory | None = None, status: PluginStatus | None = None, search: str | None = None, author_id: str | None = None, sort_by: str = "created_at", ) -> list[PluginMarketItem]: """列出插件""" query = "SELECT * FROM plugin_market WHERE 1 = 1" params = [] if category: query += " AND category = ?" params.append(category.value) if status: query += " AND status = ?" params.append(status.value) if author_id: query += " AND author_id = ?" params.append(author_id) if search: query += " AND (name LIKE ? OR description LIKE ? OR tags LIKE ?)" params.extend([f"%{search}%", f"%{search}%", f"%{search}%"]) sort_mapping = { "created_at": "created_at DESC", "rating": "rating DESC", "install_count": "install_count DESC", "name": "name ASC", } query += f" ORDER BY {sort_mapping.get(sort_by, 'created_at DESC')}" with self._get_db() as conn: rows = conn.execute(query, params).fetchall() return [self._row_to_plugin(row) for row in rows] def review_plugin( self, plugin_id: str, reviewed_by: str, status: PluginStatus, notes: str = "", ) -> PluginMarketItem | None: """审核插件""" now = datetime.now().isoformat() with self._get_db() as conn: conn.execute( """ UPDATE plugin_market SET status = ?, reviewed_by = ?, reviewed_at = ?, review_notes = ?, updated_at = ? WHERE id = ? """, (status.value, reviewed_by, now, notes, now, plugin_id), ) conn.commit() return self.get_plugin(plugin_id) def publish_plugin(self, plugin_id: str) -> PluginMarketItem | None: """发布插件""" now = datetime.now().isoformat() with self._get_db() as conn: conn.execute( """ UPDATE plugin_market SET status = ?, published_at = ?, updated_at = ? WHERE id = ? """, (PluginStatus.PUBLISHED.value, now, now, plugin_id), ) conn.commit() return self.get_plugin(plugin_id) def increment_plugin_install(self, plugin_id: str, active: bool = True) -> None: """增加插件安装计数""" with self._get_db() as conn: conn.execute( """ UPDATE plugin_market SET install_count = install_count + 1 WHERE id = ? """, (plugin_id,), ) if active: conn.execute( """ UPDATE plugin_market SET active_install_count = active_install_count + 1 WHERE id = ? """, (plugin_id,), ) conn.commit() def add_plugin_review( self, plugin_id: str, user_id: str, user_name: str, rating: int, comment: str, is_verified_purchase: bool = False, ) -> PluginReview: """添加插件评价""" review_id = f"pr_{uuid.uuid4().hex[:16]}" now = datetime.now().isoformat() review = PluginReview( id=review_id, plugin_id=plugin_id, user_id=user_id, user_name=user_name, rating=rating, comment=comment, is_verified_purchase=is_verified_purchase, helpful_count=0, created_at=now, updated_at=now, ) with self._get_db() as conn: conn.execute( """ INSERT INTO plugin_reviews (id, plugin_id, user_id, user_name, rating, comment, is_verified_purchase, helpful_count, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) """, ( review.id, review.plugin_id, review.user_id, review.user_name, review.rating, review.comment, review.is_verified_purchase, review.helpful_count, review.created_at, review.updated_at, ), ) self._update_plugin_rating(conn, plugin_id) conn.commit() return review def _update_plugin_rating(self, conn, plugin_id: str) -> None: """更新插件评分""" row = conn.execute( """ SELECT AVG(rating) as avg_rating, COUNT(*) as count FROM plugin_reviews WHERE plugin_id = ? """, (plugin_id,), ).fetchone() if row: conn.execute( """ UPDATE plugin_market SET rating = ?, rating_count = ?, review_count = ? WHERE id = ? """, ( round(row["avg_rating"], 2) if row["avg_rating"] else 0, row["count"], row["count"], plugin_id, ), ) def get_plugin_reviews(self, plugin_id: str, limit: int = 50) -> list[PluginReview]: """获取插件评价""" with self._get_db() as conn: rows = conn.execute( """SELECT * FROM plugin_reviews WHERE plugin_id = ? ORDER BY created_at DESC LIMIT ?""", (plugin_id, limit), ).fetchall() return [self._row_to_plugin_review(row) for row in rows] # ==================== 开发者收益分成 ==================== def record_revenue( self, developer_id: str, item_type: str, item_id: str, item_name: str, sale_amount: float, currency: str, buyer_id: str, transaction_id: str, ) -> DeveloperRevenue: """记录开发者收益""" revenue_id = f"rev_{uuid.uuid4().hex[:16]}" now = datetime.now().isoformat() platform_fee = sale_amount * self.platform_fee_rate developer_earnings = sale_amount - platform_fee revenue = DeveloperRevenue( id=revenue_id, developer_id=developer_id, item_type=item_type, item_id=item_id, item_name=item_name, sale_amount=sale_amount, platform_fee=platform_fee, developer_earnings=developer_earnings, currency=currency, buyer_id=buyer_id, transaction_id=transaction_id, created_at=now, ) with self._get_db() as conn: conn.execute( """ INSERT INTO developer_revenues (id, developer_id, item_type, item_id, item_name, sale_amount, platform_fee, developer_earnings, currency, buyer_id, transaction_id, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) """, ( revenue.id, revenue.developer_id, revenue.item_type, revenue.item_id, revenue.item_name, revenue.sale_amount, revenue.platform_fee, revenue.developer_earnings, revenue.currency, revenue.buyer_id, revenue.transaction_id, revenue.created_at, ), ) # 更新开发者总收入 conn.execute( """ UPDATE developer_profiles SET total_sales = total_sales + ? WHERE id = ? """, (sale_amount, developer_id), ) conn.commit() return revenue def get_developer_revenues( self, developer_id: str, start_date: datetime | None = None, end_date: datetime | None = None, ) -> list[DeveloperRevenue]: """获取开发者收益记录""" query = "SELECT * FROM developer_revenues WHERE developer_id = ?" params = [developer_id] if start_date: query += " AND created_at >= ?" params.append(start_date.isoformat()) if end_date: query += " AND created_at <= ?" params.append(end_date.isoformat()) query += " ORDER BY created_at DESC" with self._get_db() as conn: rows = conn.execute(query, params).fetchall() return [self._row_to_developer_revenue(row) for row in rows] def get_developer_revenue_summary(self, developer_id: str) -> dict: """获取开发者收益汇总""" with self._get_db() as conn: row = conn.execute( """ SELECT SUM(sale_amount) as total_sales, SUM(platform_fee) as total_fees, SUM(developer_earnings) as total_earnings, COUNT(*) as transaction_count FROM developer_revenues WHERE developer_id = ? """, (developer_id,), ).fetchone() return { "total_sales": row["total_sales"] or 0, "total_fees": row["total_fees"] or 0, "total_earnings": row["total_earnings"] or 0, "transaction_count": row["transaction_count"] or 0, "platform_fee_rate": self.platform_fee_rate, } # ==================== 开发者认证与管理 ==================== def create_developer_profile( self, user_id: str, display_name: str, email: str, bio: str | None = None, website: str | None = None, github_url: str | None = None, avatar_url: str | None = None, ) -> DeveloperProfile: """创建开发者档案""" profile_id = f"dev_{uuid.uuid4().hex[:16]}" now = datetime.now().isoformat() profile = DeveloperProfile( id=profile_id, user_id=user_id, display_name=display_name, email=email, bio=bio, website=website, github_url=github_url, avatar_url=avatar_url, status=DeveloperStatus.UNVERIFIED, verification_documents={}, total_sales=0.0, total_downloads=0, plugin_count=0, template_count=0, rating_average=0.0, created_at=now, updated_at=now, verified_at=None, ) with self._get_db() as conn: conn.execute( """ INSERT INTO developer_profiles (id, user_id, display_name, email, bio, website, github_url, avatar_url, status, verification_documents, total_sales, total_downloads, plugin_count, template_count, rating_average, created_at, updated_at, verified_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) """, ( profile.id, profile.user_id, profile.display_name, profile.email, profile.bio, profile.website, profile.github_url, profile.avatar_url, profile.status.value, json.dumps(profile.verification_documents), profile.total_sales, profile.total_downloads, profile.plugin_count, profile.template_count, profile.rating_average, profile.created_at, profile.updated_at, profile.verified_at, ), ) conn.commit() return profile def get_developer_profile(self, developer_id: str) -> DeveloperProfile | None: """获取开发者档案""" with self._get_db() as conn: row = conn.execute( "SELECT * FROM developer_profiles WHERE id = ?", (developer_id,), ).fetchone() if row: return self._row_to_developer_profile(row) return None def get_developer_profile_by_user(self, user_id: str) -> DeveloperProfile | None: """通过用户 ID 获取开发者档案""" with self._get_db() as conn: row = conn.execute( "SELECT * FROM developer_profiles WHERE user_id = ?", (user_id,), ).fetchone() if row: return self._row_to_developer_profile(row) return None def verify_developer( self, developer_id: str, status: DeveloperStatus, ) -> DeveloperProfile | None: """验证开发者""" now = datetime.now().isoformat() with self._get_db() as conn: conn.execute( """ UPDATE developer_profiles SET status = ?, verified_at = ?, updated_at = ? WHERE id = ? """, ( status.value, ( now if status in [DeveloperStatus.VERIFIED, DeveloperStatus.CERTIFIED] else None ), now, developer_id, ), ) conn.commit() return self.get_developer_profile(developer_id) def update_developer_stats(self, developer_id: str) -> None: """更新开发者统计信息""" with self._get_db() as conn: # 统计插件数量 plugin_row = conn.execute( "SELECT COUNT(*) as count FROM plugin_market WHERE author_id = ?", (developer_id,), ).fetchone() # 统计模板数量 template_row = conn.execute( "SELECT COUNT(*) as count FROM template_market WHERE author_id = ?", (developer_id,), ).fetchone() # 统计总下载量 download_row = conn.execute( """ SELECT SUM(install_count) as total FROM ( SELECT install_count FROM plugin_market WHERE author_id = ? UNION ALL SELECT install_count FROM template_market WHERE author_id = ? ) """, (developer_id, developer_id), ).fetchone() conn.execute( """ UPDATE developer_profiles SET plugin_count = ?, template_count = ?, total_downloads = ?, updated_at = ? WHERE id = ? """, ( plugin_row["count"], template_row["count"], download_row["total"] or 0, datetime.now().isoformat(), developer_id, ), ) conn.commit() # ==================== 代码示例库 ==================== def create_code_example( self, title: str, description: str, language: str, category: str, code: str, explanation: str, tags: list[str], author_id: str, author_name: str, sdk_id: str | None = None, api_endpoints: list[str] = None, ) -> CodeExample: """创建代码示例""" example_id = f"ex_{uuid.uuid4().hex[:16]}" now = datetime.now().isoformat() example = CodeExample( id=example_id, title=title, description=description, language=language, category=category, code=code, explanation=explanation, tags=tags, author_id=author_id, author_name=author_name, sdk_id=sdk_id, api_endpoints=api_endpoints or [], view_count=0, copy_count=0, rating=0.0, created_at=now, updated_at=now, ) with self._get_db() as conn: conn.execute( """ INSERT INTO code_examples (id, title, description, language, category, code, explanation, tags, author_id, author_name, sdk_id, api_endpoints, view_count, copy_count, rating, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) """, ( example.id, example.title, example.description, example.language, example.category, example.code, example.explanation, json.dumps(example.tags), example.author_id, example.author_name, example.sdk_id, json.dumps(example.api_endpoints), example.view_count, example.copy_count, example.rating, example.created_at, example.updated_at, ), ) conn.commit() return example def get_code_example(self, example_id: str) -> CodeExample | None: """获取代码示例""" with self._get_db() as conn: row = conn.execute( "SELECT * FROM code_examples WHERE id = ?", (example_id,), ).fetchone() if row: return self._row_to_code_example(row) return None def list_code_examples( self, language: str | None = None, category: str | None = None, sdk_id: str | None = None, search: str | None = None, ) -> list[CodeExample]: """列出代码示例""" query = "SELECT * FROM code_examples WHERE 1 = 1" params = [] if language: query += " AND language = ?" params.append(language) if category: query += " AND category = ?" params.append(category) if sdk_id: query += " AND sdk_id = ?" params.append(sdk_id) if search: query += " AND (title LIKE ? OR description LIKE ? OR tags LIKE ?)" params.extend([f"%{search}%", f"%{search}%", f"%{search}%"]) query += " ORDER BY created_at DESC" with self._get_db() as conn: rows = conn.execute(query, params).fetchall() return [self._row_to_code_example(row) for row in rows] def increment_example_view(self, example_id: str) -> None: """增加代码示例查看计数""" with self._get_db() as conn: conn.execute( """ UPDATE code_examples SET view_count = view_count + 1 WHERE id = ? """, (example_id,), ) conn.commit() def increment_example_copy(self, example_id: str) -> None: """增加代码示例复制计数""" with self._get_db() as conn: conn.execute( """ UPDATE code_examples SET copy_count = copy_count + 1 WHERE id = ? """, (example_id,), ) conn.commit() # ==================== API 文档生成 ==================== def create_api_documentation( self, version: str, openapi_spec: str, markdown_content: str, html_content: str, changelog: str, generated_by: str, ) -> APIDocumentation: """创建 API 文档""" doc_id = f"api_{uuid.uuid4().hex[:16]}" now = datetime.now().isoformat() doc = APIDocumentation( id=doc_id, version=version, openapi_spec=openapi_spec, markdown_content=markdown_content, html_content=html_content, changelog=changelog, generated_at=now, generated_by=generated_by, ) with self._get_db() as conn: conn.execute( """ INSERT INTO api_documentation (id, version, openapi_spec, markdown_content, html_content, changelog, generated_at, generated_by) VALUES (?, ?, ?, ?, ?, ?, ?, ?) """, ( doc.id, doc.version, doc.openapi_spec, doc.markdown_content, doc.html_content, doc.changelog, doc.generated_at, doc.generated_by, ), ) conn.commit() return doc def get_api_documentation(self, doc_id: str) -> APIDocumentation | None: """获取 API 文档""" with self._get_db() as conn: row = conn.execute( "SELECT * FROM api_documentation WHERE id = ?", (doc_id,), ).fetchone() if row: return self._row_to_api_documentation(row) return None def get_latest_api_documentation(self) -> APIDocumentation | None: """获取最新 API 文档""" with self._get_db() as conn: row = conn.execute( "SELECT * FROM api_documentation ORDER BY generated_at DESC LIMIT 1", ).fetchone() if row: return self._row_to_api_documentation(row) return None # ==================== 开发者门户 ==================== def create_portal_config( self, name: str, description: str, theme: str = "default", custom_css: str | None = None, custom_js: str | None = None, logo_url: str | None = None, favicon_url: str | None = None, primary_color: str = "#1890ff", secondary_color: str = "#52c41a", support_email: str = "support@insightflow.io", support_url: str | None = None, github_url: str | None = None, discord_url: str | None = None, api_base_url: str = "https://api.insightflow.io", ) -> DeveloperPortalConfig: """创建开发者门户配置""" config_id = f"portal_{uuid.uuid4().hex[:16]}" now = datetime.now().isoformat() config = DeveloperPortalConfig( id=config_id, name=name, description=description, theme=theme, custom_css=custom_css, custom_js=custom_js, logo_url=logo_url, favicon_url=favicon_url, primary_color=primary_color, secondary_color=secondary_color, support_email=support_email, support_url=support_url, github_url=github_url, discord_url=discord_url, api_base_url=api_base_url, is_active=True, created_at=now, updated_at=now, ) with self._get_db() as conn: conn.execute( """ INSERT INTO developer_portal_configs (id, name, description, theme, custom_css, custom_js, logo_url, favicon_url, primary_color, secondary_color, support_email, support_url, github_url, discord_url, api_base_url, is_active, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) """, ( config.id, config.name, config.description, config.theme, config.custom_css, config.custom_js, config.logo_url, config.favicon_url, config.primary_color, config.secondary_color, config.support_email, config.support_url, config.github_url, config.discord_url, config.api_base_url, config.is_active, config.created_at, config.updated_at, ), ) conn.commit() return config def get_portal_config(self, config_id: str) -> DeveloperPortalConfig | None: """获取开发者门户配置""" with self._get_db() as conn: row = conn.execute( "SELECT * FROM developer_portal_configs WHERE id = ?", (config_id,), ).fetchone() if row: return self._row_to_portal_config(row) return None def get_active_portal_config(self) -> DeveloperPortalConfig | None: """获取活跃的开发者门户配置""" with self._get_db() as conn: row = conn.execute( "SELECT * FROM developer_portal_configs WHERE is_active = 1 LIMIT 1", ).fetchone() if row: return self._row_to_portal_config(row) return None # ==================== 辅助方法 ==================== def _row_to_sdk_release(self, row) -> SDKRelease: """将数据库行转换为 SDKRelease""" return SDKRelease( id=row["id"], name=row["name"], language=SDKLanguage(row["language"]), version=row["version"], description=row["description"], changelog=row["changelog"], download_url=row["download_url"], documentation_url=row["documentation_url"], repository_url=row["repository_url"], package_name=row["package_name"], status=SDKStatus(row["status"]), min_platform_version=row["min_platform_version"], dependencies=json.loads(row["dependencies"]), file_size=row["file_size"], checksum=row["checksum"], download_count=row["download_count"], created_at=row["created_at"], updated_at=row["updated_at"], published_at=row["published_at"], created_by=row["created_by"], ) def _row_to_sdk_version(self, row) -> SDKVersion: """将数据库行转换为 SDKVersion""" return SDKVersion( id=row["id"], sdk_id=row["sdk_id"], version=row["version"], is_latest=bool(row["is_latest"]), is_lts=bool(row["is_lts"]), release_notes=row["release_notes"], download_url=row["download_url"], checksum=row["checksum"], file_size=row["file_size"], download_count=row["download_count"], created_at=row["created_at"], ) def _row_to_template(self, row) -> TemplateMarketItem: """将数据库行转换为 TemplateMarketItem""" return TemplateMarketItem( id=row["id"], name=row["name"], description=row["description"], category=TemplateCategory(row["category"]), subcategory=row["subcategory"], tags=json.loads(row["tags"]), author_id=row["author_id"], author_name=row["author_name"], status=TemplateStatus(row["status"]), price=row["price"], currency=row["currency"], preview_image_url=row["preview_image_url"], demo_url=row["demo_url"], documentation_url=row["documentation_url"], download_url=row["download_url"], install_count=row["install_count"], rating=row["rating"], rating_count=row["rating_count"], review_count=row["review_count"], version=row["version"], min_platform_version=row["min_platform_version"], file_size=row["file_size"], checksum=row["checksum"], created_at=row["created_at"], updated_at=row["updated_at"], published_at=row["published_at"], ) def _row_to_template_review(self, row) -> TemplateReview: """将数据库行转换为 TemplateReview""" return TemplateReview( id=row["id"], template_id=row["template_id"], user_id=row["user_id"], user_name=row["user_name"], rating=row["rating"], comment=row["comment"], is_verified_purchase=bool(row["is_verified_purchase"]), helpful_count=row["helpful_count"], created_at=row["created_at"], updated_at=row["updated_at"], ) def _row_to_plugin(self, row) -> PluginMarketItem: """将数据库行转换为 PluginMarketItem""" return PluginMarketItem( id=row["id"], name=row["name"], description=row["description"], category=PluginCategory(row["category"]), tags=json.loads(row["tags"]), author_id=row["author_id"], author_name=row["author_name"], status=PluginStatus(row["status"]), price=row["price"], currency=row["currency"], pricing_model=row["pricing_model"], preview_image_url=row["preview_image_url"], demo_url=row["demo_url"], documentation_url=row["documentation_url"], repository_url=row["repository_url"], download_url=row["download_url"], webhook_url=row["webhook_url"], permissions=json.loads(row["permissions"]), install_count=row["install_count"], active_install_count=row["active_install_count"], rating=row["rating"], rating_count=row["rating_count"], review_count=row["review_count"], version=row["version"], min_platform_version=row["min_platform_version"], file_size=row["file_size"], checksum=row["checksum"], created_at=row["created_at"], updated_at=row["updated_at"], published_at=row["published_at"], reviewed_by=row["reviewed_by"], reviewed_at=row["reviewed_at"], review_notes=row["review_notes"], ) def _row_to_plugin_review(self, row) -> PluginReview: """将数据库行转换为 PluginReview""" return PluginReview( id=row["id"], plugin_id=row["plugin_id"], user_id=row["user_id"], user_name=row["user_name"], rating=row["rating"], comment=row["comment"], is_verified_purchase=bool(row["is_verified_purchase"]), helpful_count=row["helpful_count"], created_at=row["created_at"], updated_at=row["updated_at"], ) def _row_to_developer_profile(self, row) -> DeveloperProfile: """将数据库行转换为 DeveloperProfile""" return DeveloperProfile( id=row["id"], user_id=row["user_id"], display_name=row["display_name"], email=row["email"], bio=row["bio"], website=row["website"], github_url=row["github_url"], avatar_url=row["avatar_url"], status=DeveloperStatus(row["status"]), verification_documents=json.loads(row["verification_documents"]), total_sales=row["total_sales"], total_downloads=row["total_downloads"], plugin_count=row["plugin_count"], template_count=row["template_count"], rating_average=row["rating_average"], created_at=row["created_at"], updated_at=row["updated_at"], verified_at=row["verified_at"], ) def _row_to_developer_revenue(self, row) -> DeveloperRevenue: """将数据库行转换为 DeveloperRevenue""" return DeveloperRevenue( id=row["id"], developer_id=row["developer_id"], item_type=row["item_type"], item_id=row["item_id"], item_name=row["item_name"], sale_amount=row["sale_amount"], platform_fee=row["platform_fee"], developer_earnings=row["developer_earnings"], currency=row["currency"], buyer_id=row["buyer_id"], transaction_id=row["transaction_id"], created_at=row["created_at"], ) def _row_to_code_example(self, row) -> CodeExample: """将数据库行转换为 CodeExample""" return CodeExample( id=row["id"], title=row["title"], description=row["description"], language=row["language"], category=row["category"], code=row["code"], explanation=row["explanation"], tags=json.loads(row["tags"]), author_id=row["author_id"], author_name=row["author_name"], sdk_id=row["sdk_id"], api_endpoints=json.loads(row["api_endpoints"]), view_count=row["view_count"], copy_count=row["copy_count"], rating=row["rating"], created_at=row["created_at"], updated_at=row["updated_at"], ) def _row_to_api_documentation(self, row) -> APIDocumentation: """将数据库行转换为 APIDocumentation""" return APIDocumentation( id=row["id"], version=row["version"], openapi_spec=row["openapi_spec"], markdown_content=row["markdown_content"], html_content=row["html_content"], changelog=row["changelog"], generated_at=row["generated_at"], generated_by=row["generated_by"], ) def _row_to_portal_config(self, row) -> DeveloperPortalConfig: """将数据库行转换为 DeveloperPortalConfig""" return DeveloperPortalConfig( id=row["id"], name=row["name"], description=row["description"], theme=row["theme"], custom_css=row["custom_css"], custom_js=row["custom_js"], logo_url=row["logo_url"], favicon_url=row["favicon_url"], primary_color=row["primary_color"], secondary_color=row["secondary_color"], support_email=row["support_email"], support_url=row["support_url"], github_url=row["github_url"], discord_url=row["discord_url"], api_base_url=row["api_base_url"], is_active=bool(row["is_active"]), created_at=row["created_at"], updated_at=row["updated_at"], ) # Singleton instance _developer_ecosystem_manager = None def get_developer_ecosystem_manager() -> DeveloperEcosystemManager: """获取开发者生态系统管理器单例""" global _developer_ecosystem_manager if _developer_ecosystem_manager is None: _developer_ecosystem_manager = DeveloperEcosystemManager() return _developer_ecosystem_manager