🐛 fix(store.py): add missing import for user_data_context and update_components_with_user_data functions
✨ feat(store.py): add support for user_data_context context manager to fetch and set user data for requests made inside the context ✨ feat(store.py): add support for in_user_collection attribute in ListComponentResponse schema to indicate if a component is in the user's collection 🐛 fix(store.py): fix get_liked_by_user_components function to use user_data_var context variable instead of making the request multiple times 🐛 fix(store.py): fix get_components_in_users_collection function to use user_data_var context variable instead of making the request multiple times ✨ feat(store.py): add update_components_with_user_data function to update components with user data (liked_by_user and in_users_collection attributes)
This commit is contained in:
parent
6799007514
commit
0339072079
4 changed files with 80 additions and 22 deletions
|
|
@ -18,7 +18,8 @@ from langflow.services.store.schema import (
|
|||
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||
from datetime import datetime
|
||||
|
||||
from langflow.services.store.service import StoreService
|
||||
from langflow.services.store.service import StoreService, user_data_context
|
||||
from langflow.services.store.utils import update_components_with_user_data
|
||||
|
||||
|
||||
router = APIRouter(prefix="/store", tags=["Components Store"])
|
||||
|
|
@ -78,26 +79,20 @@ def list_components(
|
|||
store_api_Key: Optional[str] = Depends(get_optional_user_store_api_key),
|
||||
):
|
||||
try:
|
||||
result = store_service.query_components(
|
||||
api_key=store_api_Key,
|
||||
page=page,
|
||||
limit=limit,
|
||||
filter_by_user=filter_by_user,
|
||||
)
|
||||
with user_data_context(store_api_Key, store_service):
|
||||
result = store_service.query_components(
|
||||
api_key=store_api_Key,
|
||||
page=page,
|
||||
limit=limit,
|
||||
filter_by_user=filter_by_user,
|
||||
)
|
||||
|
||||
if not store_api_Key:
|
||||
return result
|
||||
|
||||
# Now, from the result, we need to get the components
|
||||
# the user likes and set the liked_by_user to True
|
||||
liked_by_user_ids = store_service.get_liked_by_user_components(
|
||||
component_ids=[str(component.id) for component in result],
|
||||
api_key=store_api_Key,
|
||||
)
|
||||
# Now we need to set the liked_by_user attribute
|
||||
for component in result:
|
||||
component.liked_by_user = str(component.id) in liked_by_user_ids
|
||||
|
||||
result = update_components_with_user_data(result, store_service, store_api_Key)
|
||||
return result
|
||||
except Exception as exc:
|
||||
raise HTTPException(status_code=400, detail=str(exc))
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ class ListComponentResponse(BaseModel):
|
|||
description: Optional[str]
|
||||
liked_by_count: Optional[int]
|
||||
liked_by_user: Optional[bool]
|
||||
in_user_collection: Optional[bool]
|
||||
is_component: Optional[bool]
|
||||
metadata: Optional[dict]
|
||||
user_created: Optional[dict]
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ from typing import TYPE_CHECKING, List, Dict, Any, Optional, Union
|
|||
import httpx
|
||||
|
||||
from httpx import HTTPError
|
||||
from langflow.services.database.models import user
|
||||
from langflow.services.store.schema import (
|
||||
ComponentResponse,
|
||||
DownloadComponentResponse,
|
||||
|
|
@ -17,6 +18,27 @@ from langflow.services.store.utils import process_tags_for_post
|
|||
|
||||
if TYPE_CHECKING:
|
||||
from langflow.services.settings.service import SettingsService
|
||||
from contextlib import contextmanager
|
||||
from contextvars import ContextVar
|
||||
|
||||
user_data_var: ContextVar[Optional[Dict[str, Any]]] = ContextVar(
|
||||
"user_data", default=None
|
||||
)
|
||||
|
||||
|
||||
@contextmanager
|
||||
def user_data_context(api_key: str, store_service: "StoreService"):
|
||||
# Fetch and set user data to the context variable
|
||||
if api_key:
|
||||
user_data = store_service._get(
|
||||
f"{store_service.base_url}/users/me", api_key, params={"fields": "id"}
|
||||
)
|
||||
user_data_var.set(user_data)
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
# Clear the user data from the context variable
|
||||
user_data_var.set(None)
|
||||
|
||||
|
||||
class StoreService(Service):
|
||||
|
|
@ -45,6 +67,11 @@ class StoreService(Service):
|
|||
"metadata",
|
||||
]
|
||||
|
||||
# Create a context manager that will use the api key to
|
||||
# get the user data and all requests inside the context manager
|
||||
# will make a property return that data
|
||||
# Without making the request multiple times
|
||||
|
||||
def _get(
|
||||
self, url: str, api_key: str, params: Dict[str, Any] = None
|
||||
) -> List[Dict[str, Any]]:
|
||||
|
|
@ -175,9 +202,7 @@ class StoreService(Service):
|
|||
raise ValueError("No API key provided")
|
||||
|
||||
if filter_by_user and api_key:
|
||||
user_data = self._get(
|
||||
f"{self.base_url}/users/me", api_key, params={"fields": "id"}
|
||||
)
|
||||
user_data = user_data_var.get()
|
||||
params["filter"] = json.dumps({"user_created": {"_eq": user_data["id"]}})
|
||||
else:
|
||||
params["filter"] = params["filter"] = json.dumps(
|
||||
|
|
@ -193,14 +218,12 @@ class StoreService(Service):
|
|||
return results_objects
|
||||
|
||||
def get_liked_by_user_components(
|
||||
self, component_ids: List[UUID], api_key: str
|
||||
self, component_ids: List[UUID], api_key: str, user_data: Dict[str, Any]
|
||||
) -> List[UUID]:
|
||||
# Get fields id
|
||||
# filter should be "id is in component_ids AND liked_by directus_users_id token is api_key"
|
||||
# return the ids
|
||||
user_data = self._get(
|
||||
f"{self.base_url}/users/me", api_key, params={"fields": "id"}
|
||||
)
|
||||
user_data = user_data_var.get()
|
||||
params = {
|
||||
"fields": "id",
|
||||
"filter": json.dumps(
|
||||
|
|
@ -215,6 +238,26 @@ class StoreService(Service):
|
|||
results = self._get(self.components_url, api_key, params)
|
||||
return [result["id"] for result in results]
|
||||
|
||||
# Which of the components is parent of the user's components
|
||||
def get_components_in_users_collection(
|
||||
self, component_ids: List[UUID], api_key: str
|
||||
):
|
||||
user_data = user_data_var.get()
|
||||
params = {
|
||||
"fields": "id",
|
||||
"filter": json.dumps(
|
||||
{
|
||||
"_and": [
|
||||
{"user_created": {"_eq": user_data["id"]}},
|
||||
{"parent": {"_in": component_ids}},
|
||||
]
|
||||
}
|
||||
),
|
||||
}
|
||||
results = self._get(self.components_url, api_key, params)
|
||||
return [result["id"] for result in results]
|
||||
|
||||
|
||||
def download(self, api_key: str, component_id: str) -> DownloadComponentResponse:
|
||||
url = f"{self.components_url}/{component_id}"
|
||||
params = {
|
||||
|
|
|
|||
|
|
@ -3,3 +3,22 @@ def process_tags_for_post(component_dict):
|
|||
if tags and all(isinstance(tag, str) for tag in tags):
|
||||
component_dict["tags"] = [{"tags_id": tag} for tag in tags]
|
||||
return component_dict
|
||||
|
||||
|
||||
def update_components_with_user_data(components, store_service, store_api_Key):
|
||||
"""
|
||||
Updates the components with the user data (liked_by_user and in_users_collection)
|
||||
"""
|
||||
liked_by_user_ids = store_service.get_liked_by_user_components(
|
||||
component_ids=[str(component.id) for component in components],
|
||||
api_key=store_api_Key,
|
||||
)
|
||||
in_users_collection_ids = store_service.get_components_in_users_collection(
|
||||
component_ids=[str(component.id) for component in components],
|
||||
api_key=store_api_Key,
|
||||
)
|
||||
# Now we need to set the liked_by_user attribute
|
||||
for component in components:
|
||||
component.liked_by_user = str(component.id) in liked_by_user_ids
|
||||
component.in_users_collection = str(component.id) in in_users_collection_ids
|
||||
return components
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue