Close profile identity and avatar loop

This commit is contained in:
IanShaw027
2026-04-21 00:11:03 +08:00
parent f73117f9b1
commit 9204145746
14 changed files with 801 additions and 35 deletions

View File

@@ -152,6 +152,11 @@ func TestExchangePendingOAuthCompletionPreviewThenFinalizeAppliesAdoptionDecisio
require.Equal(t, "Alice Example", identity.Metadata["display_name"])
require.Equal(t, "https://cdn.example/alice.png", identity.Metadata["avatar_url"])
avatar := loadUserAvatarRecord(t, client, userEntity.ID)
require.NotNil(t, avatar)
require.Equal(t, "remote_url", avatar.StorageProvider)
require.Equal(t, "https://cdn.example/alice.png", avatar.URL)
decision, err := client.IdentityAdoptionDecision.Query().
Where(identityadoptiondecision.PendingAuthSessionIDEQ(session.ID)).
Only(ctx)
@@ -1242,6 +1247,18 @@ CREATE TABLE IF NOT EXISTS user_provider_default_grants (
UNIQUE(user_id, provider_type, grant_reason)
)`)
require.NoError(t, err)
_, err = db.Exec(`
CREATE TABLE IF NOT EXISTS user_avatars (
user_id INTEGER PRIMARY KEY,
storage_provider TEXT NOT NULL,
storage_key TEXT NOT NULL DEFAULT '',
url TEXT NOT NULL,
content_type TEXT NOT NULL DEFAULT '',
byte_size INTEGER NOT NULL DEFAULT 0,
sha256 TEXT NOT NULL DEFAULT '',
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
)`)
require.NoError(t, err)
drv := entsql.OpenDB(dialect.SQLite, db)
client := enttest.NewClient(t, enttest.WithOptions(dbent.Driver(drv)))
@@ -1492,6 +1509,35 @@ func decodeJSONBody(t *testing.T, recorder *httptest.ResponseRecorder) map[strin
return payload
}
type oauthPendingFlowAvatarRecord struct {
StorageProvider string
URL string
}
func loadUserAvatarRecord(t *testing.T, client *dbent.Client, userID int64) *oauthPendingFlowAvatarRecord {
t.Helper()
var rows entsql.Rows
err := client.Driver().Query(
context.Background(),
`SELECT storage_provider, url FROM user_avatars WHERE user_id = ?`,
[]any{userID},
&rows,
)
require.NoError(t, err)
defer rows.Close()
if !rows.Next() {
require.NoError(t, rows.Err())
return nil
}
var record oauthPendingFlowAvatarRecord
require.NoError(t, rows.Scan(&record.StorageProvider, &record.URL))
require.NoError(t, rows.Err())
return &record
}
func countProviderGrantRecords(
t *testing.T,
client *dbent.Client,
@@ -1604,16 +1650,95 @@ func (r *oauthPendingFlowUserRepo) Delete(ctx context.Context, id int64) error {
return r.client.User.DeleteOneID(id).Exec(ctx)
}
func (r *oauthPendingFlowUserRepo) GetUserAvatar(context.Context, int64) (*service.UserAvatar, error) {
return nil, nil
func (r *oauthPendingFlowUserRepo) GetUserAvatar(ctx context.Context, userID int64) (*service.UserAvatar, error) {
driver := r.client.Driver()
if tx := dbent.TxFromContext(ctx); tx != nil {
driver = tx.Client().Driver()
}
var rows entsql.Rows
if err := driver.Query(
ctx,
`SELECT storage_provider, storage_key, url, content_type, byte_size, sha256 FROM user_avatars WHERE user_id = ?`,
[]any{userID},
&rows,
); err != nil {
return nil, err
}
defer rows.Close()
if !rows.Next() {
return nil, rows.Err()
}
var avatar service.UserAvatar
if err := rows.Scan(
&avatar.StorageProvider,
&avatar.StorageKey,
&avatar.URL,
&avatar.ContentType,
&avatar.ByteSize,
&avatar.SHA256,
); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return &avatar, nil
}
func (r *oauthPendingFlowUserRepo) UpsertUserAvatar(context.Context, int64, service.UpsertUserAvatarInput) (*service.UserAvatar, error) {
panic("unexpected UpsertUserAvatar call")
func (r *oauthPendingFlowUserRepo) UpsertUserAvatar(ctx context.Context, userID int64, input service.UpsertUserAvatarInput) (*service.UserAvatar, error) {
driver := r.client.Driver()
if tx := dbent.TxFromContext(ctx); tx != nil {
driver = tx.Client().Driver()
}
var result entsql.Result
if err := driver.Exec(
ctx,
`INSERT INTO user_avatars (user_id, storage_provider, storage_key, url, content_type, byte_size, sha256, updated_at)
VALUES (?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP)
ON CONFLICT(user_id) DO UPDATE SET
storage_provider = excluded.storage_provider,
storage_key = excluded.storage_key,
url = excluded.url,
content_type = excluded.content_type,
byte_size = excluded.byte_size,
sha256 = excluded.sha256,
updated_at = CURRENT_TIMESTAMP`,
[]any{
userID,
input.StorageProvider,
input.StorageKey,
input.URL,
input.ContentType,
input.ByteSize,
input.SHA256,
},
&result,
); err != nil {
return nil, err
}
return &service.UserAvatar{
StorageProvider: input.StorageProvider,
StorageKey: input.StorageKey,
URL: input.URL,
ContentType: input.ContentType,
ByteSize: input.ByteSize,
SHA256: input.SHA256,
}, nil
}
func (r *oauthPendingFlowUserRepo) DeleteUserAvatar(context.Context, int64) error {
return nil
func (r *oauthPendingFlowUserRepo) DeleteUserAvatar(ctx context.Context, userID int64) error {
driver := r.client.Driver()
if tx := dbent.TxFromContext(ctx); tx != nil {
driver = tx.Client().Driver()
}
var result entsql.Result
return driver.Exec(ctx, `DELETE FROM user_avatars WHERE user_id = ?`, []any{userID}, &result)
}
func (r *oauthPendingFlowUserRepo) List(context.Context, pagination.PaginationParams) ([]service.User, *pagination.PaginationResult, error) {
@@ -1636,6 +1761,14 @@ func (r *oauthPendingFlowUserRepo) UpdateConcurrency(context.Context, int64, int
panic("unexpected UpdateConcurrency call")
}
func (r *oauthPendingFlowUserRepo) GetLatestUsedAtByUserIDs(context.Context, []int64) (map[int64]*time.Time, error) {
return map[int64]*time.Time{}, nil
}
func (r *oauthPendingFlowUserRepo) GetLatestUsedAtByUserID(context.Context, int64) (*time.Time, error) {
return nil, nil
}
func (r *oauthPendingFlowUserRepo) ExistsByEmail(ctx context.Context, email string) (bool, error) {
count, err := r.client.User.Query().Where(dbuser.EmailEQ(email)).Count(ctx)
return count > 0, err