From bc6ff19568d89e18be82ba9ea52a8c9c54a29c8f Mon Sep 17 00:00:00 2001 From: aitbc Date: Fri, 15 May 2026 00:29:43 +0200 Subject: [PATCH] Implement plugin marketplace backend with database Marketplace service: - Added Plugin model to database schema (id, name, description, author, type, version, ipfs_cid, metadata, status, created_at, updated_at, download_count, rating) - Added list_plugins() service method with type and status filters - Added register_plugin() service method - Updated GET /v1/marketplace/plugins to use database instead of mock data - Added POST /v1/marketplace/plugins endpoint for plugin registration - Created plugin table in aitbc_marketplace database Replaces mock plugin data with real database-backed plugin marketplace --- .../marketplace_service/domain/marketplace.py | 19 +++++++ .../src/marketplace_service/main.py | 49 +++++++---------- .../services/marketplace_service.py | 55 +++++++++++++++++++ 3 files changed, 93 insertions(+), 30 deletions(-) diff --git a/apps/marketplace-service/src/marketplace_service/domain/marketplace.py b/apps/marketplace-service/src/marketplace_service/domain/marketplace.py index 6db7cf42..1108af69 100644 --- a/apps/marketplace-service/src/marketplace_service/domain/marketplace.py +++ b/apps/marketplace-service/src/marketplace_service/domain/marketplace.py @@ -39,3 +39,22 @@ class MarketplaceBid(SQLModel, table=True): notes: str | None = Field(default=None) status: str = Field(default="pending", nullable=False) submitted_at: datetime = Field(default_factory=datetime.utcnow, nullable=False, index=True) + + +class Plugin(SQLModel, table=True): + __tablename__ = "plugin" + __table_args__ = {"extend_existing": True} + + id: str = Field(default_factory=lambda: uuid4().hex, primary_key=True) + name: str = Field(index=True) + description: str = Field(default="") + author: str = Field(default="") + type: str = Field(default="cli", index=True) # cli, web, blockchain, ai + version: str = Field(default="1.0.0") + ipfs_cid: str | None = Field(default=None, index=True) # IPFS CID for plugin code + metadata: dict = Field(default_factory=dict, sa_column=Column(JSON, nullable=False)) + status: str = Field(default="pending", index=True) # pending, approved, rejected + created_at: datetime = Field(default_factory=datetime.utcnow, nullable=False, index=True) + updated_at: datetime = Field(default_factory=datetime.utcnow, nullable=False) + download_count: int = Field(default=0) + rating: float = Field(default=0.0) diff --git a/apps/marketplace-service/src/marketplace_service/main.py b/apps/marketplace-service/src/marketplace_service/main.py index 52332906..5e452e3e 100644 --- a/apps/marketplace-service/src/marketplace_service/main.py +++ b/apps/marketplace-service/src/marketplace_service/main.py @@ -249,46 +249,35 @@ async def get_analytics( @app.get("/v1/marketplace/plugins") async def get_plugins( type: str | None = None, + status: str = "approved", svc: MarketplaceService = Depends(get_marketplace_service), ): """Get marketplace plugins""" try: - logger.info(f"GET /v1/marketplace/plugins called with type={type}") - # Return mock plugin data for now - plugins = [ - { - "id": "plugin_001", - "name": "cli_enhancer", - "type": "cli", - "author": "AITBC Team", - "description": "Enhances CLI with additional commands", - "version": "1.0.0" - }, - { - "id": "plugin_002", - "name": "web_dashboard", - "type": "web", - "author": "AITBC Team", - "description": "Web dashboard plugin for monitoring", - "version": "1.2.0" - }, - { - "id": "plugin_003", - "name": "security_scanner", - "type": "blockchain", - "author": "Security Team", - "description": "Security scanning plugin for blockchain", - "version": "0.9.0" - } - ] - if type: - plugins = [p for p in plugins if p.get("type") == type] + logger.info(f"GET /v1/marketplace/plugins called with type={type}, status={status}") + plugins = await svc.list_plugins(type=type, status=status) return {"plugins": plugins} except Exception as e: logger.error(f"Error in GET /v1/marketplace/plugins: {type(e).__name__}: {str(e)}") raise +@app.post("/v1/marketplace/plugins") +async def register_plugin( + plugin_data: dict, + svc: MarketplaceService = Depends(get_marketplace_service), +): + """Register a new plugin""" + try: + logger.info(f"POST /v1/marketplace/plugins called with data keys: {plugin_data.keys()}") + result = await svc.register_plugin(plugin_data) + logger.info(f"POST /v1/marketplace/plugins registered plugin with id: {result['id']}") + return result + except Exception as e: + logger.error(f"Error in POST /v1/marketplace/plugins: {type(e).__name__}: {str(e)}") + raise + + @app.post("/v1/transactions") async def submit_transaction(transaction_data: dict, session: AsyncSession = Depends(get_session_dep)): """Submit marketplace transaction""" diff --git a/apps/marketplace-service/src/marketplace_service/services/marketplace_service.py b/apps/marketplace-service/src/marketplace_service/services/marketplace_service.py index 21576db2..677bb336 100644 --- a/apps/marketplace-service/src/marketplace_service/services/marketplace_service.py +++ b/apps/marketplace-service/src/marketplace_service/services/marketplace_service.py @@ -207,3 +207,58 @@ class MarketplaceService: "total_capacity": total_capacity, "average_price": round(float(avg_price), 2), } + + async def list_plugins(self, type: str | None = None, status: str = "approved") -> list[dict]: + """List plugins from database""" + from sqlalchemy import select + from .domain.marketplace import Plugin + + try: + stmt = select(Plugin) + if type: + stmt = stmt.where(Plugin.type == type) + if status: + stmt = stmt.where(Plugin.status == status) + stmt = stmt.order_by(Plugin.created_at.desc()) + + result = await self.session.execute(stmt) + plugins = result.scalars().all() + + return [ + { + "id": p.id, + "name": p.name, + "description": p.description, + "author": p.author, + "type": p.type, + "version": p.version, + "ipfs_cid": p.ipfs_cid, + "status": p.status, + "download_count": p.download_count, + "rating": p.rating, + "created_at": p.created_at.isoformat() if p.created_at else None, + } + for p in plugins + ] + except Exception as e: + logger.error(f"Error in list_plugins: {type(e).__name__}: {str(e)}") + raise + + async def register_plugin(self, plugin_data: dict) -> dict: + """Register a new plugin""" + from .domain.marketplace import Plugin + + try: + plugin = Plugin(**plugin_data) + self.session.add(plugin) + await self.session.commit() + await self.session.refresh(plugin) + logger.info(f"Registered plugin with id: {plugin.id}") + return { + "id": plugin.id, + "name": plugin.name, + "status": plugin.status, + } + except Exception as e: + logger.error(f"Error in register_plugin: {type(e).__name__}: {str(e)}") + raise