Refactor user profile update handler to support optional email field and dynamic query construction
This commit is contained in:
@@ -28,7 +28,6 @@ class _AccountSettingsDialogState extends State<AccountSettingsDialog> {
|
||||
|
||||
// Profile fields
|
||||
late TextEditingController _displayNameController;
|
||||
late TextEditingController _emailController;
|
||||
String? _avatarUrl;
|
||||
String? _blurHash;
|
||||
|
||||
@@ -43,7 +42,6 @@ class _AccountSettingsDialogState extends State<AccountSettingsDialog> {
|
||||
void initState() {
|
||||
super.initState();
|
||||
_displayNameController = TextEditingController();
|
||||
_emailController = TextEditingController();
|
||||
_currentPasswordController = TextEditingController();
|
||||
_newPasswordController = TextEditingController();
|
||||
_confirmPasswordController = TextEditingController();
|
||||
@@ -53,7 +51,6 @@ class _AccountSettingsDialogState extends State<AccountSettingsDialog> {
|
||||
@override
|
||||
void dispose() {
|
||||
_displayNameController.dispose();
|
||||
_emailController.dispose();
|
||||
_currentPasswordController.dispose();
|
||||
_newPasswordController.dispose();
|
||||
_confirmPasswordController.dispose();
|
||||
@@ -65,7 +62,6 @@ class _AccountSettingsDialogState extends State<AccountSettingsDialog> {
|
||||
if (authState is AuthAuthenticated) {
|
||||
_currentUser = authState.user;
|
||||
_displayNameController.text = _currentUser?.displayName ?? '';
|
||||
_emailController.text = _currentUser?.email ?? '';
|
||||
_avatarUrl = _currentUser?.avatarUrl;
|
||||
_blurHash = _currentUser?.blurHash;
|
||||
}
|
||||
@@ -135,7 +131,6 @@ class _AccountSettingsDialogState extends State<AccountSettingsDialog> {
|
||||
displayName: _displayNameController.text.isEmpty
|
||||
? null
|
||||
: _displayNameController.text,
|
||||
email: _emailController.text,
|
||||
avatarUrl: _avatarUrl,
|
||||
blurHash: _blurHash,
|
||||
);
|
||||
@@ -144,7 +139,6 @@ class _AccountSettingsDialogState extends State<AccountSettingsDialog> {
|
||||
displayName: _displayNameController.text.isEmpty
|
||||
? null
|
||||
: _displayNameController.text,
|
||||
email: _emailController.text,
|
||||
avatarUrl: _avatarUrl,
|
||||
blurHash: _blurHash,
|
||||
);
|
||||
@@ -340,6 +334,7 @@ class _AccountSettingsDialogState extends State<AccountSettingsDialog> {
|
||||
Center(
|
||||
child: Column(
|
||||
children: [
|
||||
SizedBox(height: 16),
|
||||
GestureDetector(
|
||||
onTap: _pickAndUploadAvatar,
|
||||
child: CircleAvatar(
|
||||
@@ -397,41 +392,27 @@ class _AccountSettingsDialogState extends State<AccountSettingsDialog> {
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// Email
|
||||
Text(
|
||||
'Email',
|
||||
style: TextStyle(
|
||||
color: AppTheme.primaryText,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
TextFormField(
|
||||
controller: _emailController,
|
||||
keyboardType: TextInputType.emailAddress,
|
||||
style: TextStyle(color: AppTheme.primaryText),
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Enter email',
|
||||
hintStyle: TextStyle(color: AppTheme.secondaryText),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
borderSide: BorderSide(color: AppTheme.secondaryText),
|
||||
),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
borderSide: BorderSide(color: AppTheme.secondaryText),
|
||||
// Save Button
|
||||
Center(
|
||||
child: SizedBox(
|
||||
width: 88,
|
||||
child: ModernGlassButton(
|
||||
onPressed: _updateProfile,
|
||||
child: const Text('Save Changes'),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// Save Button
|
||||
// Logout Button
|
||||
Center(
|
||||
child: ModernGlassButton(
|
||||
onPressed: _updateProfile,
|
||||
child: const Text('Save Changes'),
|
||||
child: IconButton(
|
||||
onPressed: _logout,
|
||||
icon: Icon(Icons.logout, color: AppTheme.errorColor),
|
||||
tooltip: 'Logout',
|
||||
iconSize: 28,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -530,19 +511,12 @@ class _AccountSettingsDialogState extends State<AccountSettingsDialog> {
|
||||
|
||||
// Change Password Button
|
||||
Center(
|
||||
child: ModernGlassButton(
|
||||
onPressed: _changePassword,
|
||||
child: const Text('Change Password'),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// Logout Button
|
||||
Center(
|
||||
child: TextButton(
|
||||
onPressed: _logout,
|
||||
style: TextButton.styleFrom(foregroundColor: AppTheme.errorColor),
|
||||
child: const Text('Logout'),
|
||||
child: SizedBox(
|
||||
width: 88,
|
||||
child: ModernGlassButton(
|
||||
onPressed: _changePassword,
|
||||
child: const Text('Change Password'),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
BIN
go_cloud/api
BIN
go_cloud/api
Binary file not shown.
@@ -3735,7 +3735,7 @@ func updateUserProfileHandler(w http.ResponseWriter, r *http.Request, db *databa
|
||||
|
||||
var req struct {
|
||||
DisplayName *string `json:"displayName"`
|
||||
Email string `json:"email"`
|
||||
Email *string `json:"email"`
|
||||
AvatarURL *string `json:"avatarUrl"`
|
||||
BlurHash *string `json:"blurHash"`
|
||||
}
|
||||
@@ -3745,11 +3745,44 @@ func updateUserProfileHandler(w http.ResponseWriter, r *http.Request, db *databa
|
||||
return
|
||||
}
|
||||
|
||||
// Update user
|
||||
_, err = db.ExecContext(r.Context(),
|
||||
`UPDATE users SET display_name = $1, email = $2, avatar_url = $3, blur_hash = $4, updated_at = NOW()
|
||||
WHERE id = $5`,
|
||||
req.DisplayName, req.Email, req.AvatarURL, req.BlurHash, userID)
|
||||
// Build dynamic update query
|
||||
var setParts []string
|
||||
var args []interface{}
|
||||
argIndex := 1
|
||||
|
||||
if req.DisplayName != nil {
|
||||
setParts = append(setParts, fmt.Sprintf("display_name = $%d", argIndex))
|
||||
args = append(args, *req.DisplayName)
|
||||
argIndex++
|
||||
}
|
||||
if req.Email != nil {
|
||||
setParts = append(setParts, fmt.Sprintf("email = $%d", argIndex))
|
||||
args = append(args, *req.Email)
|
||||
argIndex++
|
||||
}
|
||||
if req.AvatarURL != nil {
|
||||
setParts = append(setParts, fmt.Sprintf("avatar_url = $%d", argIndex))
|
||||
args = append(args, *req.AvatarURL)
|
||||
argIndex++
|
||||
}
|
||||
if req.BlurHash != nil {
|
||||
setParts = append(setParts, fmt.Sprintf("blur_hash = $%d", argIndex))
|
||||
args = append(args, *req.BlurHash)
|
||||
argIndex++
|
||||
}
|
||||
|
||||
if len(setParts) == 0 {
|
||||
// No fields to update
|
||||
w.WriteHeader(http.StatusOK)
|
||||
json.NewEncoder(w).Encode(map[string]string{"message": "No changes to update"})
|
||||
return
|
||||
}
|
||||
|
||||
setParts = append(setParts, "updated_at = NOW()")
|
||||
query := fmt.Sprintf("UPDATE users SET %s WHERE id = $%d", strings.Join(setParts, ", "), argIndex)
|
||||
args = append(args, userID)
|
||||
|
||||
_, err = db.ExecContext(r.Context(), query, args...)
|
||||
if err != nil {
|
||||
errors.LogError(r, err, "Failed to update user profile")
|
||||
errors.WriteError(w, errors.CodeInternal, "Server error", http.StatusInternalServerError)
|
||||
@@ -3757,14 +3790,25 @@ func updateUserProfileHandler(w http.ResponseWriter, r *http.Request, db *databa
|
||||
}
|
||||
|
||||
// Audit log
|
||||
metadata := make(map[string]interface{})
|
||||
if req.DisplayName != nil {
|
||||
metadata["displayName"] = *req.DisplayName
|
||||
}
|
||||
if req.Email != nil {
|
||||
metadata["email"] = *req.Email
|
||||
}
|
||||
if req.AvatarURL != nil {
|
||||
metadata["avatarUrl"] = *req.AvatarURL
|
||||
}
|
||||
if req.BlurHash != nil {
|
||||
metadata["blurHash"] = *req.BlurHash
|
||||
}
|
||||
|
||||
auditLogger.Log(r.Context(), audit.Entry{
|
||||
UserID: &userID,
|
||||
Action: "profile_update",
|
||||
Success: true,
|
||||
Metadata: map[string]interface{}{
|
||||
"displayName": req.DisplayName,
|
||||
"email": req.Email,
|
||||
},
|
||||
UserID: &userID,
|
||||
Action: "profile_update",
|
||||
Success: true,
|
||||
Metadata: metadata,
|
||||
})
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
|
||||
Reference in New Issue
Block a user