mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-04-08 03:00:28 -04:00
refactor(backend): remove Ayrshare from execution & credentials manager (#10538)
This PR refactors the Ayrshare integration to remove the centralized `get_ayrshare_profile_key` function from the credentials store and instead retrieve the profile key directly within each Ayrshare block. This change improves code organization by keeping Ayrshare-specific logic within the Ayrshare module. ### Changes 🏗️ - **Refactored Ayrshare profile key retrieval**: Moved profile key fetching logic from the credentials store into the Ayrshare blocks - **Added `get_profile_key` helper function** in `autogpt_platform/backend/backend/blocks/ayrshare/_util.py` to fetch the profile key from user integrations - **Updated all 15 Ayrshare social media blocks** to use `user_id` instead of `profile_key` parameter and fetch the profile key internally - **Removed `get_ayrshare_profile_key` method** from `autogpt_platform/backend/backend/integrations/credentials_store.py` - **Removed Ayrshare-specific logic** from `autogpt_platform/backend/backend/executor/manager.py` that was passing profile keys to blocks - **Updated router** in `autogpt_platform/backend/backend/server/integrations/router.py` to directly fetch user integrations instead of using the removed method ### Checklist 📋 #### For code changes: - [x] I have clearly listed my changes in the PR description - [x] I have made a test plan - [x] I have tested my changes according to the test plan: - [x] Test posting to X/Twitter to check credentials flow - [x] Verify profile key retrieval works correctly for authenticated users - [x] Test Ayrshare SSO URL generation flow --------- Co-authored-by: Zamil Majdy <zamil.majdy@agpt.co>
This commit is contained in:
@@ -1,14 +1,30 @@
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
from autogpt_libs.utils.cache import thread_cached
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from backend.data.block import BlockSchema
|
||||
from backend.data.model import SchemaField
|
||||
from backend.data.model import SchemaField, UserIntegrations
|
||||
from backend.integrations.ayrshare import AyrshareClient
|
||||
from backend.util.exceptions import MissingConfigError
|
||||
|
||||
|
||||
@thread_cached
|
||||
def get_database_manager_client():
|
||||
from backend.executor import DatabaseManagerAsyncClient
|
||||
from backend.util.service import get_service_client
|
||||
|
||||
return get_service_client(DatabaseManagerAsyncClient, health_check=False)
|
||||
|
||||
|
||||
async def get_profile_key(user_id: str):
|
||||
user_integrations: UserIntegrations = (
|
||||
await get_database_manager_client().get_user_integrations(user_id)
|
||||
)
|
||||
return user_integrations.managed_credentials.ayrshare_profile_key
|
||||
|
||||
|
||||
class BaseAyrshareInput(BlockSchema):
|
||||
"""Base input model for Ayrshare social media posts with common fields."""
|
||||
|
||||
|
||||
@@ -6,10 +6,9 @@ from backend.sdk import (
|
||||
BlockSchema,
|
||||
BlockType,
|
||||
SchemaField,
|
||||
SecretStr,
|
||||
)
|
||||
|
||||
from ._util import BaseAyrshareInput, create_ayrshare_client
|
||||
from ._util import BaseAyrshareInput, create_ayrshare_client, get_profile_key
|
||||
|
||||
|
||||
class PostToBlueskyBlock(Block):
|
||||
@@ -58,10 +57,12 @@ class PostToBlueskyBlock(Block):
|
||||
self,
|
||||
input_data: "PostToBlueskyBlock.Input",
|
||||
*,
|
||||
profile_key: SecretStr,
|
||||
user_id: str,
|
||||
**kwargs,
|
||||
) -> BlockOutput:
|
||||
"""Post to Bluesky with Bluesky-specific options."""
|
||||
|
||||
profile_key = await get_profile_key(user_id)
|
||||
if not profile_key:
|
||||
yield "error", "Please link a social account via Ayrshare"
|
||||
return
|
||||
|
||||
@@ -6,10 +6,14 @@ from backend.sdk import (
|
||||
BlockSchema,
|
||||
BlockType,
|
||||
SchemaField,
|
||||
SecretStr,
|
||||
)
|
||||
|
||||
from ._util import BaseAyrshareInput, CarouselItem, create_ayrshare_client
|
||||
from ._util import (
|
||||
BaseAyrshareInput,
|
||||
CarouselItem,
|
||||
create_ayrshare_client,
|
||||
get_profile_key,
|
||||
)
|
||||
|
||||
|
||||
class PostToFacebookBlock(Block):
|
||||
@@ -116,10 +120,11 @@ class PostToFacebookBlock(Block):
|
||||
self,
|
||||
input_data: "PostToFacebookBlock.Input",
|
||||
*,
|
||||
profile_key: SecretStr,
|
||||
user_id: str,
|
||||
**kwargs,
|
||||
) -> BlockOutput:
|
||||
"""Post to Facebook with Facebook-specific options."""
|
||||
profile_key = await get_profile_key(user_id)
|
||||
if not profile_key:
|
||||
yield "error", "Please link a social account via Ayrshare"
|
||||
return
|
||||
|
||||
@@ -6,10 +6,9 @@ from backend.sdk import (
|
||||
BlockSchema,
|
||||
BlockType,
|
||||
SchemaField,
|
||||
SecretStr,
|
||||
)
|
||||
|
||||
from ._util import BaseAyrshareInput, create_ayrshare_client
|
||||
from ._util import BaseAyrshareInput, create_ayrshare_client, get_profile_key
|
||||
|
||||
|
||||
class PostToGMBBlock(Block):
|
||||
@@ -111,9 +110,10 @@ class PostToGMBBlock(Block):
|
||||
)
|
||||
|
||||
async def run(
|
||||
self, input_data: "PostToGMBBlock.Input", *, profile_key: SecretStr, **kwargs
|
||||
self, input_data: "PostToGMBBlock.Input", *, user_id: str, **kwargs
|
||||
) -> BlockOutput:
|
||||
"""Post to Google My Business with GMB-specific options."""
|
||||
profile_key = await get_profile_key(user_id)
|
||||
if not profile_key:
|
||||
yield "error", "Please link a social account via Ayrshare"
|
||||
return
|
||||
|
||||
@@ -8,10 +8,14 @@ from backend.sdk import (
|
||||
BlockSchema,
|
||||
BlockType,
|
||||
SchemaField,
|
||||
SecretStr,
|
||||
)
|
||||
|
||||
from ._util import BaseAyrshareInput, InstagramUserTag, create_ayrshare_client
|
||||
from ._util import (
|
||||
BaseAyrshareInput,
|
||||
InstagramUserTag,
|
||||
create_ayrshare_client,
|
||||
get_profile_key,
|
||||
)
|
||||
|
||||
|
||||
class PostToInstagramBlock(Block):
|
||||
@@ -108,10 +112,11 @@ class PostToInstagramBlock(Block):
|
||||
self,
|
||||
input_data: "PostToInstagramBlock.Input",
|
||||
*,
|
||||
profile_key: SecretStr,
|
||||
user_id: str,
|
||||
**kwargs,
|
||||
) -> BlockOutput:
|
||||
"""Post to Instagram with Instagram-specific options."""
|
||||
profile_key = await get_profile_key(user_id)
|
||||
if not profile_key:
|
||||
yield "error", "Please link a social account via Ayrshare"
|
||||
return
|
||||
|
||||
@@ -6,10 +6,9 @@ from backend.sdk import (
|
||||
BlockSchema,
|
||||
BlockType,
|
||||
SchemaField,
|
||||
SecretStr,
|
||||
)
|
||||
|
||||
from ._util import BaseAyrshareInput, create_ayrshare_client
|
||||
from ._util import BaseAyrshareInput, create_ayrshare_client, get_profile_key
|
||||
|
||||
|
||||
class PostToLinkedInBlock(Block):
|
||||
@@ -113,10 +112,11 @@ class PostToLinkedInBlock(Block):
|
||||
self,
|
||||
input_data: "PostToLinkedInBlock.Input",
|
||||
*,
|
||||
profile_key: SecretStr,
|
||||
user_id: str,
|
||||
**kwargs,
|
||||
) -> BlockOutput:
|
||||
"""Post to LinkedIn with LinkedIn-specific options."""
|
||||
profile_key = await get_profile_key(user_id)
|
||||
if not profile_key:
|
||||
yield "error", "Please link a social account via Ayrshare"
|
||||
return
|
||||
|
||||
@@ -6,10 +6,14 @@ from backend.sdk import (
|
||||
BlockSchema,
|
||||
BlockType,
|
||||
SchemaField,
|
||||
SecretStr,
|
||||
)
|
||||
|
||||
from ._util import BaseAyrshareInput, PinterestCarouselOption, create_ayrshare_client
|
||||
from ._util import (
|
||||
BaseAyrshareInput,
|
||||
PinterestCarouselOption,
|
||||
create_ayrshare_client,
|
||||
get_profile_key,
|
||||
)
|
||||
|
||||
|
||||
class PostToPinterestBlock(Block):
|
||||
@@ -88,10 +92,11 @@ class PostToPinterestBlock(Block):
|
||||
self,
|
||||
input_data: "PostToPinterestBlock.Input",
|
||||
*,
|
||||
profile_key: SecretStr,
|
||||
user_id: str,
|
||||
**kwargs,
|
||||
) -> BlockOutput:
|
||||
"""Post to Pinterest with Pinterest-specific options."""
|
||||
profile_key = await get_profile_key(user_id)
|
||||
if not profile_key:
|
||||
yield "error", "Please link a social account via Ayrshare"
|
||||
return
|
||||
|
||||
@@ -6,10 +6,9 @@ from backend.sdk import (
|
||||
BlockSchema,
|
||||
BlockType,
|
||||
SchemaField,
|
||||
SecretStr,
|
||||
)
|
||||
|
||||
from ._util import BaseAyrshareInput, create_ayrshare_client
|
||||
from ._util import BaseAyrshareInput, create_ayrshare_client, get_profile_key
|
||||
|
||||
|
||||
class PostToRedditBlock(Block):
|
||||
@@ -36,8 +35,9 @@ class PostToRedditBlock(Block):
|
||||
)
|
||||
|
||||
async def run(
|
||||
self, input_data: "PostToRedditBlock.Input", *, profile_key: SecretStr, **kwargs
|
||||
self, input_data: "PostToRedditBlock.Input", *, user_id: str, **kwargs
|
||||
) -> BlockOutput:
|
||||
profile_key = await get_profile_key(user_id)
|
||||
if not profile_key:
|
||||
yield "error", "Please link a social account via Ayrshare"
|
||||
return
|
||||
|
||||
@@ -6,10 +6,9 @@ from backend.sdk import (
|
||||
BlockSchema,
|
||||
BlockType,
|
||||
SchemaField,
|
||||
SecretStr,
|
||||
)
|
||||
|
||||
from ._util import BaseAyrshareInput, create_ayrshare_client
|
||||
from ._util import BaseAyrshareInput, create_ayrshare_client, get_profile_key
|
||||
|
||||
|
||||
class PostToSnapchatBlock(Block):
|
||||
@@ -63,10 +62,11 @@ class PostToSnapchatBlock(Block):
|
||||
self,
|
||||
input_data: "PostToSnapchatBlock.Input",
|
||||
*,
|
||||
profile_key: SecretStr,
|
||||
user_id: str,
|
||||
**kwargs,
|
||||
) -> BlockOutput:
|
||||
"""Post to Snapchat with Snapchat-specific options."""
|
||||
profile_key = await get_profile_key(user_id)
|
||||
if not profile_key:
|
||||
yield "error", "Please link a social account via Ayrshare"
|
||||
return
|
||||
|
||||
@@ -6,10 +6,9 @@ from backend.sdk import (
|
||||
BlockSchema,
|
||||
BlockType,
|
||||
SchemaField,
|
||||
SecretStr,
|
||||
)
|
||||
|
||||
from ._util import BaseAyrshareInput, create_ayrshare_client
|
||||
from ._util import BaseAyrshareInput, create_ayrshare_client, get_profile_key
|
||||
|
||||
|
||||
class PostToTelegramBlock(Block):
|
||||
@@ -58,10 +57,11 @@ class PostToTelegramBlock(Block):
|
||||
self,
|
||||
input_data: "PostToTelegramBlock.Input",
|
||||
*,
|
||||
profile_key: SecretStr,
|
||||
user_id: str,
|
||||
**kwargs,
|
||||
) -> BlockOutput:
|
||||
"""Post to Telegram with Telegram-specific validation."""
|
||||
profile_key = await get_profile_key(user_id)
|
||||
if not profile_key:
|
||||
yield "error", "Please link a social account via Ayrshare"
|
||||
return
|
||||
|
||||
@@ -6,10 +6,9 @@ from backend.sdk import (
|
||||
BlockSchema,
|
||||
BlockType,
|
||||
SchemaField,
|
||||
SecretStr,
|
||||
)
|
||||
|
||||
from ._util import BaseAyrshareInput, create_ayrshare_client
|
||||
from ._util import BaseAyrshareInput, create_ayrshare_client, get_profile_key
|
||||
|
||||
|
||||
class PostToThreadsBlock(Block):
|
||||
@@ -51,10 +50,11 @@ class PostToThreadsBlock(Block):
|
||||
self,
|
||||
input_data: "PostToThreadsBlock.Input",
|
||||
*,
|
||||
profile_key: SecretStr,
|
||||
user_id: str,
|
||||
**kwargs,
|
||||
) -> BlockOutput:
|
||||
"""Post to Threads with Threads-specific validation."""
|
||||
profile_key = await get_profile_key(user_id)
|
||||
if not profile_key:
|
||||
yield "error", "Please link a social account via Ayrshare"
|
||||
return
|
||||
|
||||
@@ -6,10 +6,9 @@ from backend.sdk import (
|
||||
BlockSchema,
|
||||
BlockType,
|
||||
SchemaField,
|
||||
SecretStr,
|
||||
)
|
||||
|
||||
from ._util import BaseAyrshareInput, create_ayrshare_client
|
||||
from ._util import BaseAyrshareInput, create_ayrshare_client, get_profile_key
|
||||
|
||||
|
||||
class PostToTikTokBlock(Block):
|
||||
@@ -108,9 +107,10 @@ class PostToTikTokBlock(Block):
|
||||
)
|
||||
|
||||
async def run(
|
||||
self, input_data: "PostToTikTokBlock.Input", *, profile_key: SecretStr, **kwargs
|
||||
self, input_data: "PostToTikTokBlock.Input", *, user_id: str, **kwargs
|
||||
) -> BlockOutput:
|
||||
"""Post to TikTok with TikTok-specific validation and options."""
|
||||
profile_key = await get_profile_key(user_id)
|
||||
if not profile_key:
|
||||
yield "error", "Please link a social account via Ayrshare"
|
||||
return
|
||||
|
||||
@@ -6,10 +6,9 @@ from backend.sdk import (
|
||||
BlockSchema,
|
||||
BlockType,
|
||||
SchemaField,
|
||||
SecretStr,
|
||||
)
|
||||
|
||||
from ._util import BaseAyrshareInput, create_ayrshare_client
|
||||
from ._util import BaseAyrshareInput, create_ayrshare_client, get_profile_key
|
||||
|
||||
|
||||
class PostToXBlock(Block):
|
||||
@@ -116,10 +115,11 @@ class PostToXBlock(Block):
|
||||
self,
|
||||
input_data: "PostToXBlock.Input",
|
||||
*,
|
||||
profile_key: SecretStr,
|
||||
user_id: str,
|
||||
**kwargs,
|
||||
) -> BlockOutput:
|
||||
"""Post to X / Twitter with enhanced X-specific options."""
|
||||
profile_key = await get_profile_key(user_id)
|
||||
if not profile_key:
|
||||
yield "error", "Please link a social account via Ayrshare"
|
||||
return
|
||||
|
||||
@@ -9,10 +9,9 @@ from backend.sdk import (
|
||||
BlockSchema,
|
||||
BlockType,
|
||||
SchemaField,
|
||||
SecretStr,
|
||||
)
|
||||
|
||||
from ._util import BaseAyrshareInput, create_ayrshare_client
|
||||
from ._util import BaseAyrshareInput, create_ayrshare_client, get_profile_key
|
||||
|
||||
|
||||
class YouTubeVisibility(str, Enum):
|
||||
@@ -138,10 +137,12 @@ class PostToYouTubeBlock(Block):
|
||||
self,
|
||||
input_data: "PostToYouTubeBlock.Input",
|
||||
*,
|
||||
profile_key: SecretStr,
|
||||
user_id: str,
|
||||
**kwargs,
|
||||
) -> BlockOutput:
|
||||
"""Post to YouTube with YouTube-specific validation and options."""
|
||||
|
||||
profile_key = await get_profile_key(user_id)
|
||||
if not profile_key:
|
||||
yield "error", "Please link a social account via Ayrshare"
|
||||
return
|
||||
|
||||
@@ -38,7 +38,6 @@ from autogpt_libs.utils.cache import thread_cached
|
||||
from prometheus_client import Gauge, start_http_server
|
||||
|
||||
from backend.blocks.agent import AgentExecutorBlock
|
||||
from backend.blocks.ayrshare import AYRSHARE_BLOCK_IDS
|
||||
from backend.data import redis_client as redis
|
||||
from backend.data.block import (
|
||||
BlockData,
|
||||
@@ -186,17 +185,6 @@ async def execute_node(
|
||||
)
|
||||
extra_exec_kwargs[field_name] = credentials
|
||||
|
||||
if node_block.id in AYRSHARE_BLOCK_IDS:
|
||||
profile_key = await creds_manager.store.get_ayrshare_profile_key(user_id)
|
||||
if not profile_key:
|
||||
logger.error(
|
||||
"Ayrshare profile not configured. Please link a social account via Ayrshare integration first."
|
||||
)
|
||||
raise ValueError(
|
||||
"Ayrshare profile not configured. Please link a social account via Ayrshare integration first."
|
||||
)
|
||||
extra_exec_kwargs["profile_key"] = profile_key
|
||||
|
||||
output_size = 0
|
||||
try:
|
||||
async for output_name, output_data in node_block.execute(
|
||||
|
||||
@@ -363,21 +363,6 @@ class IntegrationCredentialsStore:
|
||||
|
||||
# ============== SYSTEM-MANAGED CREDENTIALS ============== #
|
||||
|
||||
async def get_ayrshare_profile_key(self, user_id: str) -> SecretStr | None:
|
||||
"""Get the Ayrshare profile key for a user.
|
||||
|
||||
The profile key is used to authenticate API requests to Ayrshare's social media posting service.
|
||||
See https://www.ayrshare.com/docs/apis/profiles/overview for more details.
|
||||
|
||||
Args:
|
||||
user_id: The ID of the user to get the profile key for
|
||||
|
||||
Returns:
|
||||
The profile key as a SecretStr if set, None otherwise
|
||||
"""
|
||||
user_integrations = await self._get_user_integrations(user_id)
|
||||
return user_integrations.managed_credentials.ayrshare_profile_key
|
||||
|
||||
async def set_ayrshare_profile_key(self, user_id: str, profile_key: str) -> None:
|
||||
"""Set the Ayrshare profile key for a user.
|
||||
|
||||
|
||||
@@ -29,7 +29,9 @@ from backend.data.model import (
|
||||
CredentialsType,
|
||||
HostScopedCredentials,
|
||||
OAuth2Credentials,
|
||||
UserIntegrations,
|
||||
)
|
||||
from backend.data.user import get_user_integrations
|
||||
from backend.executor.utils import add_graph_execution
|
||||
from backend.integrations.ayrshare import AyrshareClient, SocialPlatform
|
||||
from backend.integrations.creds_manager import IntegrationCredentialsManager
|
||||
@@ -585,7 +587,10 @@ async def get_ayrshare_sso_url(
|
||||
# Ayrshare profile key is stored in the credentials store
|
||||
# It is generated when creating a new profile, if there is no profile key,
|
||||
# we create a new profile and store the profile key in the credentials store
|
||||
profile_key = await creds_manager.store.get_ayrshare_profile_key(user_id)
|
||||
|
||||
user_integrations: UserIntegrations = await get_user_integrations(user_id)
|
||||
profile_key = user_integrations.managed_credentials.ayrshare_profile_key
|
||||
|
||||
if not profile_key:
|
||||
logger.debug(f"Creating new Ayrshare profile for user {user_id}")
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user