1+ <?php
2+
3+ namespace App \Services ;
4+
5+ use App \Models \User ;
6+ use Illuminate \Http \Client \Response ;
7+ use Illuminate \Support \Facades \Cache ;
8+ use Illuminate \Support \Facades \Http ;
9+ use Illuminate \Support \Facades \Log ;
10+
11+ class RegistrationApiService
12+ {
13+ private string $ baseUrl ;
14+
15+ public function __construct ()
16+ {
17+ $ this ->baseUrl = rtrim (config ('services.attsrv.url ' ), '/ ' );
18+ }
19+
20+ /**
21+ * Get the status of a single attendee
22+ */
23+ public function getAttendeeStatus (int $ attendeeId ): ?string
24+ {
25+ $ cacheKey = "attendee_status_ {$ attendeeId }" ;
26+
27+ // Cache results for 5 minutes to avoid hammering the API
28+ return Cache::remember ($ cacheKey , 300 , function () use ($ attendeeId ) {
29+ try {
30+ $ token = $ this ->getValidBearerToken ();
31+
32+ if (!$ token ) {
33+ throw new \Exception ('No valid bearer token available ' );
34+ }
35+
36+ $ response = Http::withHeaders ([
37+ 'Authorization ' => "Bearer {$ token }" ,
38+ 'Accept ' => 'application/json ' ,
39+ 'Content-Type ' => 'application/json '
40+ ])
41+ ->timeout (30 )
42+ ->get ("{$ this ->baseUrl }/attendees/ {$ attendeeId }/status " );
43+
44+ if ($ response ->successful ()) {
45+ $ data = $ response ->json ();
46+ return $ data ['status ' ] ?? null ;
47+ }
48+
49+ if ($ response ->status () === 404 ) {
50+ return null ; // Attendee not found
51+ }
52+
53+ Log::warning ("Registration API error for attendee {$ attendeeId }" , [
54+ 'status ' => $ response ->status (),
55+ 'body ' => $ response ->body ()
56+ ]);
57+
58+ return null ;
59+ } catch (\Exception $ e ) {
60+ Log::error ("Failed to check attendee {$ attendeeId } status " , [
61+ 'error ' => $ e ->getMessage ()
62+ ]);
63+ throw $ e ;
64+ }
65+ });
66+ }
67+
68+ /**
69+ * Search for attendees by criteria and get their statuses
70+ */
71+ public function searchAttendees (array $ criteria ): array
72+ {
73+ try {
74+ $ token = $ this ->getValidBearerToken ();
75+
76+ if (!$ token ) {
77+ throw new \Exception ('No valid bearer token available ' );
78+ }
79+
80+ $ response = Http::withHeaders ([
81+ 'Authorization ' => "Bearer {$ token }" ,
82+ 'Accept ' => 'application/json ' ,
83+ 'Content-Type ' => 'application/json '
84+ ])
85+ ->timeout (60 ) // Longer timeout for search
86+ ->post ("{$ this ->baseUrl }/attendees/find " , [
87+ 'match_any ' => $ criteria ,
88+ 'fill_fields ' => ['id ' , 'status ' ]
89+ ]);
90+
91+ if ($ response ->successful ()) {
92+ $ data = $ response ->json ();
93+ return $ data ['attendees ' ] ?? [];
94+ }
95+
96+ Log::warning ("Registration API search error " , [
97+ 'status ' => $ response ->status (),
98+ 'body ' => $ response ->body (),
99+ 'criteria ' => $ criteria
100+ ]);
101+
102+ return [];
103+ } catch (\Exception $ e ) {
104+ Log::error ("Failed to search attendees " , [
105+ 'error ' => $ e ->getMessage (),
106+ 'criteria ' => $ criteria
107+ ]);
108+ throw $ e ;
109+ }
110+ }
111+
112+ /**
113+ * Bulk get attendee statuses by IDs
114+ */
115+ public function getAttendeeStatuses (array $ attendeeIds ): array
116+ {
117+ $ batchSize = 50 ; // API limit or reasonable batch size
118+ $ results = [];
119+
120+ $ batches = array_chunk ($ attendeeIds , $ batchSize );
121+
122+ foreach ($ batches as $ batch ) {
123+ try {
124+ $ batchResults = $ this ->searchAttendees ([
125+ [
126+ 'ids ' => $ batch
127+ ]
128+ ]);
129+
130+ foreach ($ batchResults as $ attendee ) {
131+ $ results [$ attendee ['id ' ]] = $ attendee ['status ' ] ?? 'unknown ' ;
132+ }
133+ } catch (\Exception $ e ) {
134+ Log::error ("Failed to get batch attendee statuses " , [
135+ 'error ' => $ e ->getMessage (),
136+ 'batch ' => $ batch
137+ ]);
138+
139+ // Mark all in this batch as error
140+ foreach ($ batch as $ attendeeId ) {
141+ $ results [$ attendeeId ] = 'api_error ' ;
142+ }
143+ }
144+ }
145+
146+ return $ results ;
147+ }
148+
149+ /**
150+ * Get a valid bearer token from any user
151+ * We need admin permissions to search attendees
152+ */
153+ private function getValidBearerToken (): ?string
154+ {
155+ // Try to find a user with admin permissions and valid token
156+ // This assumes admin users have been properly set up with tokens
157+ $ adminUsers = User::whereNotNull ('token ' )
158+ ->whereNotNull ('refresh_token ' )
159+ ->where (function ($ query ) {
160+ $ query ->where ('token_expires_at ' , '> ' , now ())
161+ ->orWhereNull ('token_expires_at ' );
162+ })
163+ ->get ();
164+
165+ foreach ($ adminUsers as $ user ) {
166+ try {
167+ $ tokenService = new TokenRefreshService ($ user );
168+ $ token = $ tokenService ->getValidAccessToken ();
169+
170+ if ($ token ) {
171+ // Test if this token has admin permissions by trying a simple API call
172+ if ($ this ->testTokenPermissions ($ token )) {
173+ return $ token ;
174+ }
175+ }
176+ } catch (\Exception $ e ) {
177+ Log::warning ("Failed to get valid token for user {$ user ->id }: " . $ e ->getMessage ());
178+ continue ;
179+ }
180+ }
181+
182+ return null ;
183+ }
184+
185+ /**
186+ * Test if a token has the required permissions for attendee searches
187+ */
188+ private function testTokenPermissions (string $ token ): bool
189+ {
190+ try {
191+ $ response = Http::withHeaders ([
192+ 'Authorization ' => "Bearer {$ token }" ,
193+ 'Accept ' => 'application/json '
194+ ])
195+ ->timeout (10 )
196+ ->get ("{$ this ->baseUrl }/countdown " );
197+
198+ return $ response ->successful ();
199+ } catch (\Exception $ e ) {
200+ return false ;
201+ }
202+ }
203+ }
0 commit comments