feat: add description field to oidc clients (#1547)

Co-authored-by: Elias Schneider <login@eliasschneider.com>
This commit is contained in:
Sean McKenzie
2026-07-08 05:41:51 -06:00
committed by GitHub
parent c85a4e63da
commit 6734585712
16 changed files with 149 additions and 9 deletions

View File

@@ -5,6 +5,7 @@ import datatype "github.com/pocket-id/pocket-id/backend/internal/model/types"
type OidcClientMetaDataDto struct {
ID string `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
HasLogo bool `json:"hasLogo"`
HasDarkLogo bool `json:"hasDarkLogo"`
LaunchURL *string `json:"launchURL"`
@@ -36,6 +37,7 @@ type OidcClientWithAllowedGroupsCountDto struct {
type OidcClientUpdateDto struct {
Name string `json:"name" binding:"required,max=50" unorm:"nfc"`
Description string `json:"description" binding:"omitempty,max=150" unorm:"nfc"`
CallbackURLs []string `json:"callbackURLs" binding:"omitempty,dive,callback_url_pattern"`
LogoutCallbackURLs []string `json:"logoutCallbackURLs" binding:"omitempty,dive,callback_url_pattern"`
IsPublic bool `json:"isPublic"`

View File

@@ -23,6 +23,7 @@ type OidcClient struct {
Base
Name string `sortable:"true"`
Description string
Secret string
CallbackURLs UrlList
LogoutCallbackURLs UrlList

View File

@@ -187,6 +187,7 @@ func (s *TestService) SeedDatabase(baseURL string) error {
ID: "3654a746-35d4-4321-ac61-0bdcff2b4055",
},
Name: "Nextcloud",
Description: "This is an example description for Nextcloud",
LaunchURL: new("https://nextcloud.local"),
Secret: "$2a$10$9dypwot8nGuCjT6wQWWpJOckZfRprhe2EkwpKizxS/fpVHrOLEJHC", // w2mUeZISmEvIDMEDvpY0PnxQIpj1m3zY
CallbackURLs: model.UrlList{"http://nextcloud.localhost/auth/callback"},

View File

@@ -213,6 +213,7 @@ func (s *OidcService) UpdateClient(ctx context.Context, clientID string, input d
func updateOIDCClientModelFromDto(client *model.OidcClient, input *dto.OidcClientUpdateDto) {
// Base fields
client.Name = input.Name
client.Description = input.Description
client.CallbackURLs = input.CallbackURLs
client.LogoutCallbackURLs = input.LogoutCallbackURLs
client.IsPublic = input.IsPublic
@@ -594,16 +595,16 @@ func (s *OidcService) ListAccessibleOidcClients(ctx context.Context, userID stri
// If user has no groups, only return clients with no allowed user groups
if len(userGroupIDs) == 0 {
query = query.Where(`NOT EXISTS (
SELECT 1 FROM oidc_clients_allowed_user_groups
SELECT 1 FROM oidc_clients_allowed_user_groups
WHERE oidc_clients_allowed_user_groups.oidc_client_id = oidc_clients.id)`)
} else {
query = query.Where(`
NOT EXISTS (
SELECT 1 FROM oidc_clients_allowed_user_groups
SELECT 1 FROM oidc_clients_allowed_user_groups
WHERE oidc_clients_allowed_user_groups.oidc_client_id = oidc_clients.id
) OR EXISTS (
SELECT 1 FROM oidc_clients_allowed_user_groups
WHERE oidc_clients_allowed_user_groups.oidc_client_id = oidc_clients.id
SELECT 1 FROM oidc_clients_allowed_user_groups
WHERE oidc_clients_allowed_user_groups.oidc_client_id = oidc_clients.id
AND oidc_clients_allowed_user_groups.user_group_id IN (?))`, userGroupIDs)
}
@@ -632,6 +633,7 @@ func (s *OidcService) ListAccessibleOidcClients(ctx context.Context, userID stri
OidcClientMetaDataDto: dto.OidcClientMetaDataDto{
ID: client.ID,
Name: client.Name,
Description: client.Description,
LaunchURL: client.LaunchURL,
HasLogo: client.HasLogo(),
HasDarkLogo: client.HasDarkLogo(),

View File

@@ -11,6 +11,7 @@ import (
"github.com/stretchr/testify/require"
"github.com/pocket-id/pocket-id/backend/internal/common"
"github.com/pocket-id/pocket-id/backend/internal/dto"
"github.com/pocket-id/pocket-id/backend/internal/model"
"github.com/pocket-id/pocket-id/backend/internal/storage"
testutils "github.com/pocket-id/pocket-id/backend/internal/utils/testing"
@@ -449,3 +450,91 @@ func TestOidcService_downloadAndSaveLogoFromURL(t *testing.T) {
require.ErrorContains(t, err, "failed to look up client")
})
}
func TestOidcService_CreateClient_withDescription(t *testing.T) {
db := testutils.NewDatabaseForTest(t)
s, err := NewOidcService(db, nil, nil, nil, nil, nil, nil)
require.NoError(t, err)
description := "A test client description"
input := dto.OidcClientCreateDto{
OidcClientUpdateDto: dto.OidcClientUpdateDto{
Name: "Test Client",
Description: description,
CallbackURLs: []string{"https://example.com/callback"},
},
}
client, err := s.CreateClient(t.Context(), input, "user-id")
require.NoError(t, err)
var fetched model.OidcClient
err = db.First(&fetched, "id = ?", client.ID).Error
require.NoError(t, err)
require.NotEmpty(t, fetched.Description)
assert.Equal(t, description, fetched.Description)
}
func TestOidcService_CreateClient_withoutDescription(t *testing.T) {
db := testutils.NewDatabaseForTest(t)
s, err := NewOidcService(db, nil, nil, nil, nil, nil, nil)
require.NoError(t, err)
input := dto.OidcClientCreateDto{
OidcClientUpdateDto: dto.OidcClientUpdateDto{
Name: "Test Client",
CallbackURLs: []string{"https://example.com/callback"},
},
}
client, err := s.CreateClient(t.Context(), input, "user-id")
require.NoError(t, err)
var fetched model.OidcClient
err = db.First(&fetched, "id = ?", client.ID).Error
require.NoError(t, err)
assert.Empty(t, fetched.Description)
}
func TestOidcService_UpdateClient_description(t *testing.T) {
db := testutils.NewDatabaseForTest(t)
s, err := NewOidcService(db, nil, nil, nil, nil, nil, nil)
require.NoError(t, err)
// Create a client without a description
client := model.OidcClient{
Name: "Test Client",
CallbackURLs: model.UrlList{"https://example.com/callback"},
}
err = db.Create(&client).Error
require.NoError(t, err)
// Update with a description
description := "Updated description"
input := dto.OidcClientUpdateDto{
Name: "Test Client",
Description: description,
CallbackURLs: []string{"https://example.com/callback"},
}
_, err = s.UpdateClient(t.Context(), client.ID, input)
require.NoError(t, err)
var fetched model.OidcClient
err = db.First(&fetched, "id = ?", client.ID).Error
require.NoError(t, err)
require.NotEmpty(t, fetched.Description)
assert.Equal(t, description, fetched.Description)
// Update to clear the description
input.Description = ""
_, err = s.UpdateClient(t.Context(), client.ID, input)
require.NoError(t, err)
err = db.First(&fetched, "id = ?", client.ID).Error
require.NoError(t, err)
assert.Empty(t, fetched.Description)
}

View File

@@ -0,0 +1 @@
ALTER TABLE oidc_clients DROP COLUMN description;

View File

@@ -0,0 +1 @@
ALTER TABLE oidc_clients ADD COLUMN description TEXT NOT NULL DEFAULT '';

View File

@@ -0,0 +1,7 @@
PRAGMA foreign_keys=OFF;
BEGIN;
ALTER TABLE oidc_clients DROP COLUMN description;
COMMIT;
PRAGMA foreign_keys=ON;

View File

@@ -0,0 +1,7 @@
PRAGMA foreign_keys=OFF;
BEGIN;
ALTER TABLE oidc_clients ADD COLUMN description TEXT NOT NULL DEFAULT '';
COMMIT;
PRAGMA foreign_keys=ON;