This commit is contained in:
simonwt 2026-04-08 12:17:30 +01:00
commit eabca3e7bf
21 changed files with 276 additions and 22 deletions

View file

@ -1,7 +1,7 @@
[project]
name = "trustcafeapiwrapper"
version = "0.1.0.5"
description = "Add your description here"
version = "0.1.0.6"
description = "Wraps the Trust Cafe API"
readme = "README.md"
requires-python = ">=3.13"
dependencies = [

View file

@ -11,7 +11,17 @@ endpoints = {
"auth": "https://oo0wks9pbi.execute-api.us-east-1.amazonaws.com/alpha/",
"content": "https://w1yygdhayc.execute-api.us-east-1.amazonaws.com/alpha/",
"megaphone": "https://opdhjaktnl.execute-api.us-east-1.amazonaws.com/alpha/",
}
"moderation": "https://sbb1xrqsf1.execute-api.us-east-1.amazonaws.com/alpha/",
"spider": "https://xuvz1oj1sk.execute-api.us-east-1.amazonaws.com/dev/"
},
"production": {
"audrey": "https://iiouau5d2k.execute-api.us-east-1.amazonaws.com/production/",
"auth": "https://e2we3nktl4.execute-api.us-east-1.amazonaws.com/production/",
"content": "https://32hho6rvg1.execute-api.us-east-1.amazonaws.com/production/",
"megaphone": "https://yfnamdpnc8.execute-api.us-east-1.amazonaws.com/production/",
"moderation": "https://egfpoo3mw3.execute-api.us-east-1.amazonaws.com/production/",
"spider": "https://coi5kvgypc.execute-api.us-east-1.amazonaws.com/production/"
},
}
class APIClient(BaseModel):
# Internal State (Not passed in __init__)
@ -22,10 +32,16 @@ class APIClient(BaseModel):
client_id: SecretStr
client_secret: SecretStr
_access_token: str = PrivateAttr(default="")
_access_token_timeout: int = PrivateAttr(default=0)
def __init__(self, **data):
super().__init__(**data)
self.validate_environment()
def validate_environment(self):
if self.environment not in endpoints:
raise ValueError(f"Environment '{self.environment}' is not valid. Must be one of: {list(endpoints.keys())}")
def make_request(self, method: str, endpoint: str, path: str, data: dict = None, authenticate: bool = True, query_params: dict = None) -> dict:
@ -112,6 +128,17 @@ class APIClient(BaseModel):
self._access_token = token_data.get("access_token", "")
self._access_token_timeout = token_data.get("access_token_timeout", 0)
def set_environment(self, environment: str) -> None:
"""
Set the environment for the API client.
Args:
environment (str): The environment to set (e.g., "alpha", "production").
"""
self.validate_environment()
self.environment = environment
def is_token_valid(self) -> bool:
"""
Checks if the current access token is still valid based on the current time and the token's expiration time.

View file

@ -1,7 +1,8 @@
from .update import update
from .create import create
from .get import get
from .listbybranch import listbybranch
from .listbyuserprofile import listbyuserprofile
from .create import create
from .listall import listall
from .listpublic import listpublic
from .listremoved import listremoved

View file

@ -0,0 +1,12 @@
def update(API, payload: dict) -> dict:
"""
Updates an existing post in the API.
Args:
payload (dict): The data for the post update.
Returns:
dict: The post data.
"""
post_data = API.make_request("PUT", "content", "post/update", data=payload, authenticate=True)
return post_data

View file

@ -8,5 +8,5 @@ def createorupdate(API, payload: dict) -> dict:
Returns:
dict: The trust relationship data.
"""
trust_data = API.make_request("POST", "content", "reltrust", data=payload, authenticate=True)
trust_data = API.make_request("PUT", "content", "reltrust", data=payload, authenticate=True)
return trust_data

View file

@ -3,3 +3,5 @@ from .get_post_pksk import get_post_pksk
from .make_comment_sk import make_comment_sk
from .make_post_sk import make_post_sk
from .get_child_spksk_from_paths import get_child_spksk_from_paths
from .get_user_slug_from_path import get_user_slug_from_path
from .get_userprofile_pksk_from_slug import get_userprofile_pksk_from_slug

View file

@ -0,0 +1,21 @@
def get_user_slug_from_path(path: str):
"""
Extracts the user slug from a given path.
Args:
path (str): The path from which to extract the user slug.
Returns:
str: The extracted user slug.
"""
if not isinstance(path, str):
raise ValueError("Input path must be a string.")
if '/userprofile/' in path:
return path.split('/userprofile/')[-1]
elif '/user/' in path:
return path.split('/user/')[-1]
elif '/' not in path:
return path
else:
return None

View file

@ -0,0 +1,6 @@
def get_userprofile_pksk_from_slug(slug: str):
pksk = "userprofile#" + slug
return {
"pk": pksk,
"sk": pksk
}

View file

@ -1 +1,2 @@
from .create_post import create_post
from .update_post import update_post

View file

@ -0,0 +1,37 @@
from trustcafeapiwrapper.utils import get_post_pksk, get_parent_pksk_from_path
def update_post(parent_path, post_path, post_text, blur_label=None, card_url=None, collaborative=False):
"""
Updates an existing post.
Args:
post_slug (str): The slug of the post to update.
post_text (str): The new text for the post.
parent_path (str, optional): The parent path for the post. Defaults to '/'.
blur_label (str, optional): The blur label for the post. Defaults to None.
card_url (str, optional): The card URL for the post. Defaults to None.
collaborative (bool, optional): Whether the post is collaborative. Defaults to False.
Returns:
dict: The updated post data.
"""
parent_pksk = get_parent_pksk_from_path(parent_path)
post_pksk = get_post_pksk(parent_pksk, post_path)
payload = {
"key": {
"pk": post_pksk.get('pk', None),
"sk": post_pksk.get('sk', None)
},
"postSlug": post_path.strip('/post/'),
"blurLabel": blur_label,
"cardUrl": card_url,
"postText": post_text,
"collaborative": collaborative,
}
return {
"job_function": "post.update",
"payload": payload
}

View file

@ -0,0 +1 @@
from .trust import trust

View file

@ -0,0 +1,22 @@
from trustcafeapiwrapper.utils import get_user_slug_from_path, get_userprofile_pksk_from_slug
def trust(trustLevel: str, userprofile_path: str):
"""
Creates new or update existing trust entry in the API.
Args:
Returns:
dict: A dictionary containing the job name and payload for creating the post
that will be processed by the API client wrapper function.
"""
userProfileSlug = get_user_slug_from_path(userprofile_path)
userPKSK = get_userprofile_pksk_from_slug(userProfileSlug)
return {
"job_function": "trust.createorupdate",
"payload": {
"trustLevel": trustLevel,
"parentSlug": userProfileSlug,
"parent": userPKSK
}
}

View file

@ -80,6 +80,16 @@ def save_response(response):
# print(feed)
# print("-----------------------------")
# save_response(API.run_job('post.create', {
# "blurLabel": None,
# "cardUrl": None,
# "postText": "This is a test post created via the API wrapper.",
# "collaborative": False,
# "parent": {
# "pk": "maintrunk#maintrunk",
# "sk": "maintrunk#maintrunk"
# }
# }))
# save_response(API.run_job('post.create', {
# "blurLabel": None,
# "cardUrl": None,
@ -141,7 +151,7 @@ def save_response(response):
# save_response(API.run_job('post.listall'))
# save_response(API.run_job('post.listpublic'))
from trustcafeapiwrapper.wrappers.post.create_post import create_post
# from trustcafeapiwrapper.wrappers.post.create_post import create_post
# save_response(create_post(
# post_text="This is a test post created via the create_post wrapper function.",
@ -182,3 +192,16 @@ from trustcafeapiwrapper.wrappers.post.create_post import create_post
# print(users)
# users = API.run_job('trust.listbyuserhas', "simon-little ")
# print(users)
# from trustcafeapiwrapper.wrappers.trust import trust
# save_response(API.wrapped(trust(
# 100,
# "/user/bossman"
# )))
from trustcafeapiwrapper.wrappers.post.update_post import update_post
save_response(API.wrapped(update_post(
post_text="This is an updated version of the test post created via the create_post wrapper function.",
post_path="/post/1775143460-ef45186a",
parent_path="/",
)))

View file

@ -47,10 +47,42 @@ class TestAPIClient(unittest.TestCase):
result = self.api_client.run_job(mock_job, "value1")
self.assertEqual(result, "Job executed with value1")
def test_set_production_env(self):
Prod_API = APIClient(
client_id="prod_client_id",
client_secret="prod_client_secret",
debug=False,
environment="production"
)
self.assertEqual(Prod_API.environment, "production")
def test_set_bad_env(self):
with self.assertRaises(ValueError):
APIClient(
client_id="test_client_id",
client_secret="test_client_secret",
debug=False,
environment="invalid_env"
)
def test_set_environment_method(self):
self.api_client.set_environment("production")
self.assertEqual(self.api_client.environment, "production")
def test_make_non_supported_request_type(self):
with self.assertRaises(ValueError):
self.api_client.make_request("PATCH", "content", "test")
def test_make_request_with_bad_endpoint(self):
with self.assertRaises(ValueError):
self.api_client.make_request("GET", "invalid_endpoint", "test")
@patch('trustcafeapiwrapper.apiclient.requests.request')
def test_make_request(self, mock_request):
# This is a placeholder test. In a real test, you'd mock the HTTP request and response.
response = self.api_client.make_request("GET", "content", "https://api.example.com/test")
# This test should be expanded
# Or the the functions should be broken up more to be more easily testable
response = self.api_client.make_request("GET", "content", "test")
#
mock_request.assert_called_once()

View file

@ -13,10 +13,10 @@ class TestGetChildSpkskFromPaths(unittest.TestCase):
self.assertEqual(get_child_spksk_from_paths(parent_path, item_path), expected_output)
def test_comment_reaction(self):
parent_path = '/post/12345'
parent_path = '/post/12345-abcv'
item_path = '/comment/67890'
expected_output = {
"pk": "post#12345",
"pk": "post#12345-abcv",
"sk": "comment#67890",
"entity": "comment",
"slug": "67890"

View file

@ -0,0 +1,8 @@
import unittest
from trustcafeapiwrapper.utils.get_user_slug_from_path import get_user_slug_from_path
class TestGetUserSlugFromPath(unittest.TestCase):
def test_get_user_slug_from_path(self):
# Test with a valid user path
self.assertEqual(get_user_slug_from_path('/user/johndoe'), 'johndoe')

View file

@ -0,0 +1,11 @@
import unittest
from trustcafeapiwrapper.utils.get_userprofile_pksk_from_slug import get_userprofile_pksk_from_slug
class TestGetUserprofilePkskFromSlug(unittest.TestCase):
def test_get_userprofile_pksk_from_slug(self):
slug = 'testuser'
expected_result = {
"pk": "userprofile#testuser",
"sk": "userprofile#testuser"
}
self.assertEqual(get_userprofile_pksk_from_slug(slug), expected_result)

View file

@ -5,7 +5,7 @@ class TestReact(unittest.TestCase):
def test_react_to_post(self):
reaction_type = 'like'
parent_path = '/'
item_path = '/post/12345'
item_path = '/post/12345-abcv'
result = react(reaction_type, parent_path, item_path)
self.assertIsInstance(result, dict)
@ -14,13 +14,13 @@ class TestReact(unittest.TestCase):
self.assertEqual(result["job_function"], "reaction.reacttosomething")
self.assertEqual(result["payload"]["reaction"], reaction_type)
self.assertEqual(result["payload"]["parent"]["pk"], "maintrunk#maintrunk")
self.assertEqual(result["payload"]["parent"]["sk"], "post#12345")
self.assertEqual(result["payload"]["parent"]["sk"], "post#12345-abcv")
self.assertEqual(result["payload"]["parent"]["entity"], "post")
self.assertEqual(result["payload"]["parent"]["slug"], "12345")
self.assertEqual(result["payload"]["parent"]["slug"], "12345-abcv")
def test_react_to_comment(self):
reaction_type = 'like'
parent_path = '/post/12345'
parent_path = '/post/12345-abcv'
item_path = '/comment/67890'
result = react(reaction_type, parent_path, item_path)
@ -29,7 +29,7 @@ class TestReact(unittest.TestCase):
self.assertIn("payload", result)
self.assertEqual(result["job_function"], "reaction.reacttosomething")
self.assertEqual(result["payload"]["reaction"], reaction_type)
self.assertEqual(result["payload"]["parent"]["pk"], "post#12345")
self.assertEqual(result["payload"]["parent"]["pk"], "post#12345-abcv")
self.assertEqual(result["payload"]["parent"]["sk"], "comment#67890")
self.assertEqual(result["payload"]["parent"]["entity"], "comment")
self.assertEqual(result["payload"]["parent"]["slug"], "67890")

15
tests/wrappers/trust.py Normal file
View file

@ -0,0 +1,15 @@
import unittest
from trustcafeapiwrapper.wrappers.trust.trust import trust
class TestTrustCreateOrUpdate(unittest.TestCase):
def test_trust(self):
trustLevel = 100
userprofile_path = '/user/johndoe'
result = trust(trustLevel, userprofile_path)
self.assertIsInstance(result, dict)
self.assertIn("job_function", result)
self.assertIn("payload", result)
self.assertEqual(result["job_function"], "trust.createorupdate")
self.assertEqual(result["payload"]["trustLevel"], trustLevel)
self.assertEqual(result["payload"]["parentSlug"], "johndoe")

View file

@ -0,0 +1,30 @@
import unittest
from trustcafeapiwrapper.wrappers.post.update_post import update_post
class TestUpdatePost(unittest.TestCase):
def setUp(self):
self.post_text = "This is an updated test post created via the update_post wrapper function."
self.blur_label = None
self.card_url = None
self.collaborative = False
def test_update_post(self):
result = update_post(
parent_path='/',
post_path='/post/1235-abcv',
post_text=self.post_text,
blur_label=self.blur_label,
card_url=self.card_url,
collaborative=self.collaborative
)
self.assertIsInstance(result, dict)
self.assertIn("job_function", result)
self.assertIn("payload", result)
self.assertEqual(result["job_function"], "post.update")
self.assertEqual(result["payload"]["postText"], self.post_text)
self.assertEqual(result["payload"]["blurLabel"], self.blur_label)
self.assertEqual(result["payload"]["cardUrl"], self.card_url)
self.assertEqual(result["payload"]["collaborative"], self.collaborative)
self.assertEqual(result["payload"]["postSlug"], "1235-abcv")
self.assertEqual(result["payload"]["key"]["pk"], "maintrunk#maintrunk")
self.assertEqual(result["payload"]["key"]["sk"], "post#1235-abcv")
self.assertNotIn("slug", result["payload"]["key"])

View file

@ -7,11 +7,16 @@ from tests.utils.get_parent_pksk_from_path import TestGetParentPkskFromPath
from tests.utils.make_comment_sk import TestMakeCommentSk
from tests.utils.make_post_sk import TestMakePostSk
from tests.utils.get_child_spksk_from_paths import TestGetChildSpkskFromPaths
from tests.utils.get_user_slug_from_path import TestGetUserSlugFromPath
from tests.utils.get_userprofile_pksk_from_slug import TestGetUserprofilePkskFromSlug
from tests.wrappers.create_post import TestCreatePost
from tests.wrappers.update_post import TestUpdatePost
from tests.wrappers.create_comment import TestCreateComment
from tests.wrappers.react import TestReact
from tests.wrappers.vote import TestVoteCast
from tests.wrappers.trust import TestTrustCreateOrUpdate
from tests.apiclient import TestAPIClient