🐛 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:
Gabriel Luiz Freitas Almeida 2023-11-01 09:31:50 -03:00
commit 0339072079
4 changed files with 80 additions and 22 deletions

View file

@ -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))

View file

@ -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]

View file

@ -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 = {

View file

@ -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