1+ """OCS (Open Collaboration Services) client for NextCloud API.
2+
3+ Reference: https://docs.nextcloud.com/server/latest/developer_manual/client_apis/index.html
4+ """
5+
16import logging
27from typing import cast
38
1015logger = logging .getLogger (__name__ )
1116
1217
13- # https://docs.nextcloud.com/server/latest/developer_manual/client_apis/index.html
1418class OCSClient :
15- def __init__ (self , base_url : str , token : str ) -> None :
16- self .base_url = base_url
19+ """Client for NextCloud OCS API.
20+
21+ Handles business logic for activities, file search, calendar search, and task search.
22+ """
23+
24+ def __init__ (self , http_client : httpx .AsyncClient , base_url : str , token : str ) -> None :
25+ """Initialize OCSClient.
26+
27+ Args:
28+ http_client: Shared httpx.AsyncClient instance
29+ base_url: Base URL for the OCS service
30+ token: Authentication token for this request
31+ """
32+ self .client = http_client
33+ self .base_url = base_url .rstrip ("/" )
1734 self .token = token
18- self .client = httpx .Client (
19- headers = {
20- "Authorization" : f"Bearer { self .token } " ,
21- "Content-Type" : "application/json" ,
22- "OCS-APIRequest" : "true" ,
23- "Accept" : "application/json" ,
24- }
25- )
2635
27- def get_activities (
36+ async def get_activities (
2837 self ,
2938 path : str = "/ocs/v2.php/apps/activity/api/v2/activity" ,
3039 limit : int = 6 ,
3140 since : int = 0 ,
3241 filter : None | str = "files" ,
3342 ) -> list [Activity ]:
34- url_string = f"{ self .base_url } /{ path } " if not filter else f"{ self .base_url } /{ path } /{ filter } "
35-
36- url = httpx .URL (url_string , params = {"format" : "json" })
43+ url_string = f"{ path } /{ filter } " if filter else path
3744
45+ params = {"format" : "json" }
3846 if since :
39- url = url .copy_add_param ("since" , str (since ))
40-
47+ params ["since" ] = str (since )
4148 if limit :
42- url = url .copy_add_param ("limit" , str (limit ))
49+ params ["limit" ] = str (limit )
50+
51+ url = f"{ self .base_url } /{ url_string .lstrip ('/' )} "
52+ headers = {
53+ "Authorization" : f"Bearer { self .token } " ,
54+ "OCS-APIRequest" : "true" ,
55+ "Accept" : "application/json" ,
56+ }
57+ response = await self .client .get (
58+ url ,
59+ params = params ,
60+ headers = headers ,
61+ )
4362
44- response = self .client .request ("GET" , url )
4563 if response .status_code != 200 :
46- logger .error (f"OCS activities request failed: status={ response .status_code } , url={ url } " )
64+ logger .error (f"OCS activities request failed: status={ response .status_code } , url={ url_string } " )
4765 raise ExternalServiceError ("OCS" , f"Failed to fetch activities (status { response .status_code } )" )
4866
4967 results = response .json ().get ("ocs" , []).get ("data" , [])
@@ -52,10 +70,21 @@ def get_activities(
5270
5371 return notes
5472
55- def search_files (self , term : str , path : str = "ocs/v2.php/search/providers/files/search" ) -> list [SearchResults ]:
56- url = httpx .URL (f"{ self .base_url } /{ path } " , params = {"term" : term })
73+ async def search_files (
74+ self , term : str , path : str = "ocs/v2.php/search/providers/files/search"
75+ ) -> list [SearchResults ]:
76+ url = f"{ self .base_url } /{ path .lstrip ('/' )} "
77+ headers = {
78+ "Authorization" : f"Bearer { self .token } " ,
79+ "OCS-APIRequest" : "true" ,
80+ "Accept" : "application/json" ,
81+ }
82+ response = await self .client .get (
83+ url ,
84+ params = {"term" : term },
85+ headers = headers ,
86+ )
5787
58- response = self .client .request ("GET" , url )
5988 if response .status_code != 200 :
6089 logger .error (f"OCS file search failed: status={ response .status_code } , url={ url } " )
6190 raise ExternalServiceError ("OCS" , f"Failed to search files (status { response .status_code } )" )
@@ -66,12 +95,20 @@ def search_files(self, term: str, path: str = "ocs/v2.php/search/providers/files
6695 validated = TypeAdapter (list [FileSearchResult ]).validate_python (results )
6796 return cast (list [SearchResults ], validated )
6897
69- def search_calendar (
98+ async def search_calendar (
7099 self , term : str , path : str = "ocs/v2.php/search/providers/calendar/search"
71100 ) -> list [SearchResults ]:
72- url = httpx .URL (f"{ self .base_url } /{ path } " , params = {"term" : term })
73-
74- response = self .client .request ("GET" , url )
101+ url = f"{ self .base_url } /{ path .lstrip ('/' )} "
102+ headers = {
103+ "Authorization" : f"Bearer { self .token } " ,
104+ "OCS-APIRequest" : "true" ,
105+ "Accept" : "application/json" ,
106+ }
107+ response = await self .client .get (
108+ url ,
109+ params = {"term" : term },
110+ headers = headers ,
111+ )
75112
76113 if response .status_code != 200 :
77114 logger .error (f"OCS calendar search failed: status={ response .status_code } , url={ url } " )
@@ -83,10 +120,21 @@ def search_calendar(
83120 validated = TypeAdapter (list [FileSearchResult ]).validate_python (results )
84121 return cast (list [SearchResults ], validated )
85122
86- def search_tasks (self , term : str , path : str = "ocs/v2.php/search/providers/tasks/search" ) -> list [SearchResults ]:
87- url = httpx .URL (f"{ self .base_url } /{ path } " , params = {"term" : term })
123+ async def search_tasks (
124+ self , term : str , path : str = "ocs/v2.php/search/providers/tasks/search"
125+ ) -> list [SearchResults ]:
126+ url = f"{ self .base_url } /{ path .lstrip ('/' )} "
127+ headers = {
128+ "Authorization" : f"Bearer { self .token } " ,
129+ "OCS-APIRequest" : "true" ,
130+ "Accept" : "application/json" ,
131+ }
132+ response = await self .client .get (
133+ url ,
134+ params = {"term" : term },
135+ headers = headers ,
136+ )
88137
89- response = self .client .request ("GET" , url )
90138 if response .status_code != 200 :
91139 logger .error (f"OCS task search failed: status={ response .status_code } , url={ url } " )
92140 raise ExternalServiceError ("OCS" , f"Failed to search tasks (status { response .status_code } )" )
0 commit comments