@@ -36,7 +36,10 @@ func NewClient(clientID string) *Client {
3636 dashboardURL = strings .TrimRight (v , "/" )
3737 }
3838 if dashboardURL == "" {
39- fmt .Fprintln (os .Stderr , "fatal: ALGOLIA_DASHBOARD_URL is not set and no default was compiled in" )
39+ fmt .Fprintln (
40+ os .Stderr ,
41+ "fatal: ALGOLIA_DASHBOARD_URL is not set and no default was compiled in" ,
42+ )
4043 os .Exit (1 )
4144 }
4245
@@ -54,7 +57,10 @@ func NewClient(clientID string) *Client {
5457 oauthScope = v
5558 }
5659 if oauthScope == "" {
57- fmt .Fprintln (os .Stderr , "fatal: ALGOLIA_OAUTH_SCOPE is not set and no default was compiled in" )
60+ fmt .Fprintln (
61+ os .Stderr ,
62+ "fatal: ALGOLIA_OAUTH_SCOPE is not set and no default was compiled in" ,
63+ )
5864 os .Exit (1 )
5965 }
6066
@@ -87,7 +93,10 @@ func (c *Client) SignupAuthorizeURL(codeChallenge, redirectURI string) string {
8793 return c .buildAuthorizeURL (codeChallenge , redirectURI , map [string ]string {"screen" : "signup" })
8894}
8995
90- func (c * Client ) buildAuthorizeURL (codeChallenge , redirectURI string , extra map [string ]string ) string {
96+ func (c * Client ) buildAuthorizeURL (
97+ codeChallenge , redirectURI string ,
98+ extra map [string ]string ,
99+ ) string {
91100 params := url.Values {
92101 "client_id" : {c .ClientID },
93102 "response_type" : {"code" },
@@ -104,7 +113,9 @@ func (c *Client) buildAuthorizeURL(codeChallenge, redirectURI string, extra map[
104113
105114// AuthorizationCodeGrant exchanges an authorization code + PKCE code_verifier
106115// for an access token. The redirectURI must match the one used in the authorize URL.
107- func (c * Client ) AuthorizationCodeGrant (code , codeVerifier , redirectURI string ) (* OAuthTokenResponse , error ) {
116+ func (c * Client ) AuthorizationCodeGrant (
117+ code , codeVerifier , redirectURI string ,
118+ ) (* OAuthTokenResponse , error ) {
108119 form := url.Values {
109120 "grant_type" : {"authorization_code" },
110121 "client_id" : {c .ClientID },
@@ -113,7 +124,11 @@ func (c *Client) AuthorizationCodeGrant(code, codeVerifier, redirectURI string)
113124 "redirect_uri" : {redirectURI },
114125 }
115126
116- req , err := http .NewRequest (http .MethodPost , c .DashboardURL + "/2/oauth/token" , strings .NewReader (form .Encode ()))
127+ req , err := http .NewRequest (
128+ http .MethodPost ,
129+ c .DashboardURL + "/2/oauth/token" ,
130+ strings .NewReader (form .Encode ()),
131+ )
117132 if err != nil {
118133 return nil , err
119134 }
@@ -146,7 +161,11 @@ func (c *Client) RefreshToken(refreshToken string) (*OAuthTokenResponse, error)
146161 "refresh_token" : {refreshToken },
147162 }
148163
149- req , err := http .NewRequest (http .MethodPost , c .DashboardURL + "/2/oauth/token" , strings .NewReader (form .Encode ()))
164+ req , err := http .NewRequest (
165+ http .MethodPost ,
166+ c .DashboardURL + "/2/oauth/token" ,
167+ strings .NewReader (form .Encode ()),
168+ )
150169 if err != nil {
151170 return nil , err
152171 }
@@ -178,7 +197,11 @@ func (c *Client) RevokeToken(token string) error {
178197 "token" : {token },
179198 }
180199
181- req , err := http .NewRequest (http .MethodPost , c .DashboardURL + "/2/oauth/revoke" , strings .NewReader (form .Encode ()))
200+ req , err := http .NewRequest (
201+ http .MethodPost ,
202+ c .DashboardURL + "/2/oauth/revoke" ,
203+ strings .NewReader (form .Encode ()),
204+ )
182205 if err != nil {
183206 return err
184207 }
@@ -246,7 +269,11 @@ func (c *Client) ListApplications(accessToken string) ([]Application, error) {
246269
247270// GetApplication returns a single application by its ID.
248271func (c * Client ) GetApplication (accessToken , appID string ) (* Application , error ) {
249- req , err := http .NewRequest (http .MethodGet , c .APIURL + "/1/application/" + url .PathEscape (appID ), nil )
272+ req , err := http .NewRequest (
273+ http .MethodGet ,
274+ c .APIURL + "/1/application/" + url .PathEscape (appID ),
275+ nil ,
276+ )
250277 if err != nil {
251278 return nil , err
252279 }
@@ -299,12 +326,20 @@ func (c *Client) CreateApplication(accessToken, region, name string) (*Applicati
299326 respBody , _ := io .ReadAll (resp .Body )
300327 respStr := string (respBody )
301328
302- if strings .Contains (strings .ToLower (respStr ), "cluster" ) && strings .Contains (strings .ToLower (respStr ), "not available" ) ||
329+ if strings .Contains (strings .ToLower (respStr ), "cluster" ) &&
330+ strings .Contains (strings .ToLower (respStr ), "not available" ) ||
303331 strings .Contains (strings .ToLower (respStr ), "no cluster" ) {
304- return nil , & ErrClusterUnavailable {Region : region , Message : fmt .Sprintf ("no cluster available in region %q" , region )}
332+ return nil , & ErrClusterUnavailable {
333+ Region : region ,
334+ Message : fmt .Sprintf ("no cluster available in region %q" , region ),
335+ }
305336 }
306337
307- return nil , fmt .Errorf ("create application failed with status %d: %s" , resp .StatusCode , respStr )
338+ return nil , fmt .Errorf (
339+ "create application failed with status %d: %s" ,
340+ resp .StatusCode ,
341+ respStr ,
342+ )
308343 }
309344
310345 var singleResp SingleApplicationResponse
@@ -316,6 +351,161 @@ func (c *Client) CreateApplication(accessToken, region, name string) (*Applicati
316351 return & app , nil
317352}
318353
354+ // UpdateApplication renames an existing application.
355+ func (c * Client ) UpdateApplication (accessToken , appID , name string ) (* Application , error ) {
356+ payload := UpdateApplicationRequest {Name : name }
357+ body , err := json .Marshal (payload )
358+ if err != nil {
359+ return nil , err
360+ }
361+
362+ endpoint := c .APIURL + "/1/applications/" + url .PathEscape (appID )
363+ req , err := http .NewRequest (http .MethodPatch , endpoint , bytes .NewReader (body ))
364+ if err != nil {
365+ return nil , err
366+ }
367+ c .setAPIHeaders (req , accessToken )
368+ req .Header .Set ("Content-Type" , "application/json" )
369+
370+ resp , err := c .client .Do (req )
371+ if err != nil {
372+ return nil , fmt .Errorf ("update application request failed: %w" , err )
373+ }
374+ defer resp .Body .Close ()
375+
376+ if resp .StatusCode == http .StatusUnauthorized {
377+ return nil , ErrSessionExpired
378+ }
379+
380+ if resp .StatusCode != http .StatusOK {
381+ respBody , _ := io .ReadAll (resp .Body )
382+ if resp .StatusCode == http .StatusNotFound {
383+ return nil , fmt .Errorf (
384+ "no existing application found; select one using 'algolia application select' or create a new one with 'algolia application create'" ,
385+ )
386+ }
387+ return nil , fmt .Errorf (
388+ "update application failed with status %d: %s" ,
389+ resp .StatusCode ,
390+ string (respBody ),
391+ )
392+ }
393+
394+ var singleResp SingleApplicationResponse
395+ if err := json .NewDecoder (resp .Body ).Decode (& singleResp ); err != nil {
396+ return nil , fmt .Errorf ("failed to parse application response: %w" , err )
397+ }
398+
399+ app := singleResp .Data .toApplication ()
400+ return & app , nil
401+ }
402+
403+ // GetSelfServePlans returns the available plans
404+ func (c * Client ) GetSelfServePlans (accessToken string ) ([]Plan , error ) {
405+ req , err := http .NewRequest (http .MethodGet , c .APIURL + "/1/plan-templates/self-serve" , nil )
406+ if err != nil {
407+ return nil , err
408+ }
409+ c .setAPIHeaders (req , accessToken )
410+
411+ resp , err := c .client .Do (req )
412+ if err != nil {
413+ return nil , fmt .Errorf ("Couldn't get the list of plans: %w" , err )
414+ }
415+ defer resp .Body .Close ()
416+
417+ if resp .StatusCode == http .StatusUnauthorized {
418+ return nil , ErrSessionExpired
419+ }
420+ if resp .StatusCode != http .StatusOK {
421+ return nil , fmt .Errorf ("Couldn't get the list of plans: %d" , resp .StatusCode )
422+ }
423+
424+ var plansResp PlanTemplatesResponse
425+ if err := json .NewDecoder (resp .Body ).Decode (& plansResp ); err != nil {
426+ return nil , fmt .Errorf ("Couldn't get the list of plans: %w" , err )
427+ }
428+
429+ plans := make ([]Plan , 0 , len (plansResp .Data ))
430+ for i := range plansResp .Data {
431+ plans = append (plans , plansResp .Data [i ].toPlan ())
432+ }
433+ return plans , nil
434+ }
435+
436+ // GetUser returns account-level information for the authenticated user
437+ func (c * Client ) GetUser (accessToken string ) (* DashboardUser , error ) {
438+ req , err := http .NewRequest (http .MethodGet , c .APIURL + "/1/user" , nil )
439+ if err != nil {
440+ return nil , err
441+ }
442+ c .setAPIHeaders (req , accessToken )
443+
444+ resp , err := c .client .Do (req )
445+ if err != nil {
446+ return nil , fmt .Errorf ("Couldn't get your account details: %w" , err )
447+ }
448+ defer resp .Body .Close ()
449+
450+ if resp .StatusCode == http .StatusUnauthorized {
451+ return nil , ErrSessionExpired
452+ }
453+ if resp .StatusCode != http .StatusOK {
454+ return nil , fmt .Errorf ("Couldn't get your account details: %d" , resp .StatusCode )
455+ }
456+
457+ var userResp userResponse
458+ if err := json .NewDecoder (resp .Body ).Decode (& userResp ); err != nil {
459+ return nil , fmt .Errorf ("Couldn't get your account details: %w" , err )
460+ }
461+
462+ user := userResp .toUser ()
463+ return & user , nil
464+ }
465+
466+ // ChangeApplicationPlan changes the plan of an application
467+ func (c * Client ) ChangeApplicationPlan (accessToken , appID , plan string ) (* Application , error ) {
468+ payload := ChangePlanRequest {Plan : plan }
469+ body , err := json .Marshal (payload )
470+ if err != nil {
471+ return nil , err
472+ }
473+
474+ endpoint := fmt .Sprintf (
475+ "%s/1/applications/%s/plan/self-serve" ,
476+ c .APIURL ,
477+ url .PathEscape (appID ),
478+ )
479+ req , err := http .NewRequest (http .MethodPatch , endpoint , bytes .NewReader (body ))
480+ if err != nil {
481+ return nil , err
482+ }
483+ c .setAPIHeaders (req , accessToken )
484+ req .Header .Set ("Content-Type" , "application/json" )
485+
486+ resp , err := c .client .Do (req )
487+ if err != nil {
488+ return nil , fmt .Errorf ("Couldn't change your application's plan: %w" , err )
489+ }
490+ defer resp .Body .Close ()
491+
492+ if resp .StatusCode == http .StatusUnauthorized {
493+ return nil , ErrSessionExpired
494+ }
495+ if resp .StatusCode < 200 || resp .StatusCode >= 300 {
496+ return nil , fmt .Errorf ("Couldn't change your application's plan: %d" , resp .StatusCode )
497+ }
498+
499+ respBody , _ := io .ReadAll (resp .Body )
500+ var singleResp SingleApplicationResponse
501+ if err := json .Unmarshal (respBody , & singleResp ); err == nil &&
502+ singleResp .Data .Attributes .ApplicationID != "" {
503+ app := singleResp .Data .toApplication ()
504+ return & app , nil
505+ }
506+ return & Application {ID : appID }, nil
507+ }
508+
319509// ListRegions returns the allowed hosting regions for application creation.
320510func (c * Client ) ListRegions (accessToken string ) ([]Region , error ) {
321511 req , err := http .NewRequest (http .MethodGet , c .APIURL + "/1/hosting/regions" , nil )
@@ -350,7 +540,11 @@ var WriteACL = []string{
350540}
351541
352542// CreateAPIKey creates a new API key with the given ACL for the specified application.
353- func (c * Client ) CreateAPIKey (accessToken , appID string , acl []string , description string ) (string , error ) {
543+ func (c * Client ) CreateAPIKey (
544+ accessToken , appID string ,
545+ acl []string ,
546+ description string ,
547+ ) (string , error ) {
354548 payload := CreateAPIKeyRequest {ACL : acl , Description : description }
355549 body , err := json .Marshal (payload )
356550 if err != nil {
@@ -377,17 +571,28 @@ func (c *Client) CreateAPIKey(accessToken, appID string, acl []string, descripti
377571 }
378572
379573 if resp .StatusCode != http .StatusOK && resp .StatusCode != http .StatusCreated {
380- return "" , fmt .Errorf ("create API key failed with status %d: %s" , resp .StatusCode , string (respBody ))
574+ return "" , fmt .Errorf (
575+ "create API key failed with status %d: %s" ,
576+ resp .StatusCode ,
577+ string (respBody ),
578+ )
381579 }
382580
383581 var keyResp CreateAPIKeyResponse
384582 if err := json .Unmarshal (respBody , & keyResp ); err != nil {
385- return "" , fmt .Errorf ("failed to parse API key response: %w (body: %s)" , err , string (respBody ))
583+ return "" , fmt .Errorf (
584+ "failed to parse API key response: %w (body: %s)" ,
585+ err ,
586+ string (respBody ),
587+ )
386588 }
387589
388590 key := keyResp .Data .Attributes .Value
389591 if key == "" {
390- return "" , fmt .Errorf ("API key creation succeeded but no key was returned in the response: %s" , string (respBody ))
592+ return "" , fmt .Errorf (
593+ "API key creation succeeded but no key was returned in the response: %s" ,
594+ string (respBody ),
595+ )
391596 }
392597
393598 return key , nil
0 commit comments