Repository: Nerzal/gocloak
Pull request #436 (2023-07-13 19:19:00)

Added params for getting sessions associated with client
Added params GetClientUserSessionsParams for GetClientUserSessions and GetClientOfflineSessions to match Keycloak API 


mopo3ula: @Nerzal made variadic functions and added tests to compare result with and without params
codecov[bot]: ## [Codecov](https://app.codecov.io/gh/Nerzal/gocloak/pull/436?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nerzal) Report
> Merging [#436](https://app.codecov.io/gh/Nerzal/gocloak/pull/436?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nerzal) (e32f4b7) into [main](https://app.codecov.io/gh/Nerzal/gocloak/commit/166f4421c779f1ff62256fcbbc0f6cea2c4a169b?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nerzal) (166f442) will **increase** coverage by `0.01%`.
> The diff coverage is `77.77%`.

```diff
@@            Coverage Diff             @@
##             main     #436      +/-   ##
==========================================
+ Coverage   77.25%   77.26%   +0.01%     
==========================================
  Files           4        4              
  Lines        2198     2261      +63     
==========================================
+ Hits         1698     1747      +49     
- Misses        338      345       +7     
- Partials      162      169       +7     
```


| [Impacted Files](https://app.codecov.io/gh/Nerzal/gocloak/pull/436?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nerzal) | Coverage Δ | |
|---|---|---|
| [client.go](https://app.codecov.io/gh/Nerzal/gocloak/pull/436?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nerzal#diff-Y2xpZW50Lmdv) | `75.82% <77.41%> (+0.04%)` | :arrow_up: |
| [models.go](https://app.codecov.io/gh/Nerzal/gocloak/pull/436?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nerzal#diff-bW9kZWxzLmdv) | `90.38% <100.00%> (+0.06%)` | :arrow_up: |

:mega: We’re building smart automated test selection to slash your CI/CD build times. [Learn more](https://about.codecov.io/iterative-testing/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nerzal)


Patch:
diff --git a/README.md b/README.md
index 9ab5ee2..6f4d7c0 100644
--- a/README.md
+++ b/README.md
@@ -280,8 +280,8 @@ type GoCloak interface {
  ClearUserCache(ctx context.Context, token, realm string) error
  ClearKeysCache(ctx context.Context, token, realm string) error
 
- GetClientUserSessions(ctx context.Context, token, realm, idOfClient string) ([]*UserSessionRepresentation, error)
- GetClientOfflineSessions(ctx context.Context, token, realm, idOfClient string) ([]*UserSessionRepresentation, error)
+GetClientUserSessions(ctx context.Context, token, realm, idOfClient string, params ...GetClientUserSessionsParams) ([]*UserSessionRepresentation, error)
+GetClientOfflineSessions(ctx context.Context, token, realm, idOfClient string, params ...GetClientUserSessionsParams) ([]*UserSessionRepresentation, error)
  GetUserSessions(ctx context.Context, token, realm, userID string) ([]*UserSessionRepresentation, error)
  GetUserOfflineSessionsForClient(ctx context.Context, token, realm, userID, idOfClient string) ([]*UserSessionRepresentation, error)
 
diff --git a/client.go b/client.go
index c1853ed..9f06b21 100644
--- a/client.go
+++ b/client.go
@@ -1451,12 +1451,23 @@ func (g *GoCloak) RegenerateClientSecret(ctx context.Context, token, realm, idOf
 }
 
 // GetClientOfflineSessions returns offline sessions associated with the client
-func (g *GoCloak) GetClientOfflineSessions(ctx context.Context, token, realm, idOfClient string) ([]*UserSessionRepresentation, error) {
+func (g *GoCloak) GetClientOfflineSessions(ctx context.Context, token, realm, idOfClient string, params ...GetClientUserSessionsParams) ([]*UserSessionRepresentation, error) {
 	const errMessage = "could not get client offline sessions"
-
 	var res []*UserSessionRepresentation
+
+	queryParams := map[string]string{}
+	if params != nil && len(params) > 0 {
+		var err error
+
+		queryParams, err = GetQueryParams(params[0])
+		if err != nil {
+			return nil, errors.Wrap(err, errMessage)
+		}
+	}
+
 	resp, err := g.GetRequestWithBearerAuth(ctx, token).
 		SetResult(&res).
+		SetQueryParams(queryParams).
 		Get(g.getAdminRealmURL(realm, "clients", idOfClient, "offline-sessions"))
 
 	if err := checkForError(resp, err, errMessage); err != nil {
@@ -1467,12 +1478,23 @@ func (g *GoCloak) GetClientOfflineSessions(ctx context.Context, token, realm, id
 }
 
 // GetClientUserSessions returns user sessions associated with the client
-func (g *GoCloak) GetClientUserSessions(ctx context.Context, token, realm, idOfClient string) ([]*UserSessionRepresentation, error) {
+func (g *GoCloak) GetClientUserSessions(ctx context.Context, token, realm, idOfClient string, params ...GetClientUserSessionsParams) ([]*UserSessionRepresentation, error) {
 	const errMessage = "could not get client user sessions"
-
 	var res []*UserSessionRepresentation
+
+	queryParams := map[string]string{}
+	if params != nil && len(params) > 0 {
+		var err error
+
+		queryParams, err = GetQueryParams(params[0])
+		if err != nil {
+			return nil, errors.Wrap(err, errMessage)
+		}
+	}
+
 	resp, err := g.GetRequestWithBearerAuth(ctx, token).
 		SetResult(&res).
+		SetQueryParams(queryParams).
 		Get(g.getAdminRealmURL(realm, "clients", idOfClient, "user-sessions"))
 
 	if err := checkForError(resp, err, errMessage); err != nil {
diff --git a/models.go b/models.go
index afd2e65..ee05121 100644
--- a/models.go
+++ b/models.go
@@ -1416,6 +1416,12 @@ type ManagementPermissionRepresentation struct {
 	ScopePermissions *map[string]string `json:"scopePermissions,omitempty"`
 }
 
+// GetClientUserSessionsParams represents the optional parameters for getting user sessions associated with the client
+type GetClientUserSessionsParams struct {
+	First *int `json:"first,string,omitempty"`
+	Max   *int `json:"max,string,omitempty"`
+}
+
 // prettyStringStruct returns struct formatted into pretty string
 func prettyStringStruct(t interface{}) string {
 	json, err := json.MarshalIndent(t, "", "\t")
@@ -1509,3 +1515,4 @@ func (v *GetResourcePoliciesParams) String() string                 { return pre
 func (v *CredentialRepresentation) String() string                  { return prettyStringStruct(v) }
 func (v *RequiredActionProviderRepresentation) String() string      { return prettyStringStruct(v) }
 func (v *BruteForceStatus) String() string                          { return prettyStringStruct(v) }
+func (v *GetClientUserSessionsParams) String() string               { return prettyStringStruct(v) }


Test patch:
diff --git a/client_test.go b/client_test.go
index 3693cf7..9ceebea 100644
--- a/client_test.go
+++ b/client_test.go
@@ -3719,14 +3719,52 @@ func Test_GetClientUserSessions(t *testing.T) {
 	)
 	require.NoError(t, err, "Login failed")
 	token := GetAdminToken(t, client)
+	allSessionsWithoutParams, err := client.GetClientUserSessions(
+		context.Background(),
+		token.AccessToken,
+		cfg.GoCloak.Realm,
+		gocloakClientID,
+	)
+	require.NoError(t, err, "GetClientUserSessions failed")
+	require.NotEmpty(t, allSessionsWithoutParams, "GetClientUserSessions returned an empty list")
+
+	allSessions, err := client.GetClientUserSessions(
+		context.Background(),
+		token.AccessToken,
+		cfg.GoCloak.Realm,
+		gocloakClientID,
+		gocloak.GetClientUserSessionsParams{},
+	)
+	require.NoError(t, err, "GetClientUserSessions failed")
+	require.NotEmpty(t, allSessions, "GetClientUserSessions returned an empty list")
+	require.Equal(t, allSessionsWithoutParams, allSessions,
+		"GetClientUserSessions with and without params are not the same")
+
 	sessions, err := client.GetClientUserSessions(
 		context.Background(),
 		token.AccessToken,
 		cfg.GoCloak.Realm,
 		gocloakClientID,
+		gocloak.GetClientUserSessionsParams{
+			Max: gocloak.IntP(1),
+		},
 	)
 	require.NoError(t, err, "GetClientUserSessions failed")
-	require.NotEmpty(t, sessions, "GetClientUserSessions returned an empty list")
+	require.Len(t, sessions, 1)
+
+	sessions, err = client.GetClientUserSessions(
+		context.Background(),
+		token.AccessToken,
+		cfg.GoCloak.Realm,
+		gocloakClientID,
+		gocloak.GetClientUserSessionsParams{
+			Max:   gocloak.IntP(1),
+			First: gocloak.IntP(1),
+		},
+	)
+	require.NoError(t, err, "GetClientUserSessions failed")
+	require.Len(t, sessions, 1)
+	require.Equal(t, *allSessions[1].ID, *sessions[0].ID)
 }
 
 func findProtocolMapperByID(t *testing.T, client *gocloak.Client, id string) *gocloak.ProtocolMapperRepresentation {
@@ -3865,9 +3903,21 @@ func Test_GetClientOfflineSessions(t *testing.T) {
 		token.AccessToken,
 		cfg.GoCloak.Realm,
 		gocloakClientID,
+		gocloak.GetClientUserSessionsParams{},
+	)
+	require.NoError(t, err, "GetClientOfflineSessions failed")
+	require.NotEmpty(t, sessions, "GetClientOfflineSessions returned an empty list")
+
+	sessionsWithoutParams, err := client.GetClientOfflineSessions(
+		context.Background(),
+		token.AccessToken,
+		cfg.GoCloak.Realm,
+		gocloakClientID,
 	)
 	require.NoError(t, err, "GetClientOfflineSessions failed")
 	require.NotEmpty(t, sessions, "GetClientOfflineSessions returned an empty list")
+	require.Equal(t, sessions, sessionsWithoutParams,
+		"GetClientOfflineSessions with and without params are not the same")
 }
 
 func Test_ClientSecret(t *testing.T) {
diff --git a/model_test.go b/model_test.go
index ad069f2..d14acf6 100644
--- a/model_test.go
+++ b/model_test.go
@@ -335,6 +335,7 @@ func TestStringerOmitEmpty(t *testing.T) {
 		&gocloak.GetClientsParams{},
 		&gocloak.RequestingPartyTokenOptions{},
 		&gocloak.RequestingPartyPermission{},
+		&gocloak.GetClientUserSessionsParams{},
 	}
 
 	for _, custom := range customs {