feat(profile): add round avatar with upload and cropping
- backend: user_avatar_objects binding (PG+SQLite), GC preserves avatar blobs, avatar service (EXIF-stripping WebP 128/512), public avatar read route - web: avatar upload/crop on profile, round avatar in header/members/comments/author - android: avatar upload/crop, round avatar on profile and albums header - openspec: add-user-avatar proposal/design/specs/tasks
This commit is contained in:
@@ -19,6 +19,9 @@ type Repository interface {
|
||||
AddIdentifier(ctx context.Context, userID, email, phone string) error
|
||||
DeleteUser(ctx context.Context, userID string) error
|
||||
UpdatePreferences(ctx context.Context, userID string, raw []byte) error
|
||||
// SetAvatarURL stores the stable URL of the user's avatar; an empty value
|
||||
// clears it.
|
||||
SetAvatarURL(ctx context.Context, userID, url string) error
|
||||
CreateRefreshToken(ctx context.Context, t *models.RefreshToken) error
|
||||
GetRefreshToken(ctx context.Context, hash string) (*models.RefreshToken, error)
|
||||
RevokeRefreshToken(ctx context.Context, id string) error
|
||||
|
||||
@@ -88,6 +88,13 @@ func (s *SQLiteStore) UpdatePreferences(ctx context.Context, userID string, raw
|
||||
`UPDATE users SET preferences = $2 WHERE id = $1`, userID, string(raw)))
|
||||
}
|
||||
|
||||
// SetAvatarURL stores the stable URL of the user's avatar. An empty value
|
||||
// clears the column.
|
||||
func (s *SQLiteStore) SetAvatarURL(ctx context.Context, userID, url string) error {
|
||||
return s.requireRow(s.db.ExecContext(ctx,
|
||||
`UPDATE users SET avatar_url = NULLIF($2, '') WHERE id = $1`, userID, url))
|
||||
}
|
||||
|
||||
func (s *SQLiteStore) requireRow(res sql.Result, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -105,6 +105,14 @@ func (s *Store) UpdatePreferences(ctx context.Context, userID string, raw []byte
|
||||
return requireRow(tag, err)
|
||||
}
|
||||
|
||||
// SetAvatarURL stores the stable URL of the user's avatar. An empty value
|
||||
// clears the column.
|
||||
func (s *Store) SetAvatarURL(ctx context.Context, userID, url string) error {
|
||||
tag, err := s.pool.Exec(ctx,
|
||||
`UPDATE users SET avatar_url = NULLIF($2, '') WHERE id = $1`, userID, url)
|
||||
return requireRow(tag, err)
|
||||
}
|
||||
|
||||
func (s *Store) CreateRefreshToken(ctx context.Context, t *models.RefreshToken) error {
|
||||
_, err := s.pool.Exec(ctx,
|
||||
`INSERT INTO refresh_tokens (id, user_id, token_hash, expires_at)
|
||||
|
||||
Reference in New Issue
Block a user