Commit e9501524 authored by Andrei Mihu's avatar Andrei Mihu
Browse files

Fix optimistic email imports when linking social profiles.

parent a32c4975
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -4,7 +4,8 @@ All notable changes to this project are documented below.
The format is based on [keep a changelog](http://keepachangelog.com) and this project uses [semantic versioning](http://semver.org).

## [Unreleased]

### Fixed
- Fix optimistic email imports when linking social profiles.

## [3.8.0] - 2021-10-15
### Added
+49 −6
Original line number Diff line number Diff line
@@ -47,14 +47,14 @@ func LinkApple(ctx context.Context, logger *zap.Logger, db *sql.DB, config Confi

	res, err := db.ExecContext(ctx, `
UPDATE users AS u
SET apple_id = $2, email = NULLIF(COALESCE(NULLIF(u.email, ''), $3), ''), update_time = now()
SET apple_id = $2, update_time = now()
WHERE (id = $1)
AND (NOT EXISTS
    (SELECT id
     FROM users
     WHERE apple_id = $2 AND NOT id = $1))`,
		userID,
		profile.ID, profile.Email)
		profile.ID)

	if err != nil {
		logger.Error("Could not link Apple ID.", zap.Error(err), zap.Any("input", token))
@@ -63,6 +63,20 @@ AND (NOT EXISTS
		return status.Error(codes.AlreadyExists, "Apple ID is already in use.")
	}

	// Import email address, if it exists.
	if profile.Email != "" {
		_, err = db.ExecContext(ctx, "UPDATE users SET email = $1 WHERE id = $2", profile.Email, userID)
		if err != nil {
			var pgErr *pgconn.PgError
			if errors.As(err, &pgErr) && pgErr.Code == dbErrorUniqueViolation && strings.Contains(pgErr.Message, "users_email_key") {
				logger.Warn("Skipping apple account email import as it is already set in another user.", zap.Error(err), zap.String("appleID", profile.ID), zap.String("user_id", userID.String()))
			} else {
				logger.Error("Failed to import apple account email.", zap.Error(err), zap.String("appleID", profile.ID), zap.String("user_id", userID.String()))
				return status.Error(codes.Internal, "Error importing apple account email.")
			}
		}
	}

	return nil
}

@@ -206,14 +220,14 @@ func LinkFacebook(ctx context.Context, logger *zap.Logger, db *sql.DB, socialCli

	res, err := db.ExecContext(ctx, `
UPDATE users AS u
SET facebook_id = $2, display_name = COALESCE(NULLIF(u.display_name, ''), $3), email = NULLIF(COALESCE(NULLIF(u.email, ''), $4), ''), avatar_url = COALESCE(NULLIF(u.avatar_url, ''), $5), update_time = now()
SET facebook_id = $2, display_name = COALESCE(NULLIF(u.display_name, ''), $3), avatar_url = COALESCE(NULLIF(u.avatar_url, ''), $4), update_time = now()
WHERE (id = $1)
AND (NOT EXISTS
    (SELECT id
     FROM users
     WHERE facebook_id = $2 AND NOT id = $1))`,
		userID,
		facebookProfile.ID, facebookProfile.Name, facebookProfile.Email, facebookProfile.Picture.Data.Url)
		facebookProfile.ID, facebookProfile.Name, facebookProfile.Picture.Data.Url)

	if err != nil {
		logger.Error("Could not link Facebook ID.", zap.Error(err), zap.Any("input", token))
@@ -222,6 +236,20 @@ AND (NOT EXISTS
		return status.Error(codes.AlreadyExists, "Facebook ID is already in use.")
	}

	// Import email address, if it exists.
	if facebookProfile.Email != "" {
		_, err = db.ExecContext(ctx, "UPDATE users SET email = $1 WHERE id = $2", facebookProfile.Email, userID)
		if err != nil {
			var pgErr *pgconn.PgError
			if errors.As(err, &pgErr) && pgErr.Code == dbErrorUniqueViolation && strings.Contains(pgErr.Message, "users_email_key") {
				logger.Warn("Skipping facebook account email import as it is already set in another user.", zap.Error(err), zap.String("facebookID", facebookProfile.ID), zap.String("username", username), zap.String("user_id", userID.String()))
			} else {
				logger.Error("Failed to import facebook account email.", zap.Error(err), zap.String("facebookID", facebookProfile.ID), zap.String("username", username), zap.String("user_id", userID.String()))
				return status.Error(codes.Internal, "Error importing facebook account email.")
			}
		}
	}

	// Import friends if requested.
	if sync && importFriendsPossible {
		_ = importFacebookFriends(ctx, logger, db, router, socialClient, userID, username, token, false)
@@ -329,14 +357,14 @@ func LinkGoogle(ctx context.Context, logger *zap.Logger, db *sql.DB, socialClien

	res, err := db.ExecContext(ctx, `
UPDATE users AS u
SET google_id = $2, display_name = COALESCE(NULLIF(u.display_name, ''), $3), avatar_url = COALESCE(NULLIF(u.avatar_url, ''), $4), email = NULLIF(COALESCE(NULLIF(u.email, ''), $5), ''), update_time = now()
SET google_id = $2, display_name = COALESCE(NULLIF(u.display_name, ''), $3), avatar_url = COALESCE(NULLIF(u.avatar_url, ''), $4), update_time = now()
WHERE (id = $1)
AND (NOT EXISTS
    (SELECT id
     FROM users
     WHERE google_id = $2 AND NOT id = $1))`,
		userID,
		googleProfile.Sub, displayName, avatarURL, googleProfile.Email)
		googleProfile.Sub, displayName, avatarURL)

	if err != nil {
		logger.Error("Could not link Google ID.", zap.Error(err), zap.Any("input", token))
@@ -344,6 +372,21 @@ AND (NOT EXISTS
	} else if count, _ := res.RowsAffected(); count == 0 {
		return status.Error(codes.AlreadyExists, "Google ID is already in use.")
	}

	// Import email address, if it exists.
	if googleProfile.Email != "" {
		_, err = db.ExecContext(ctx, "UPDATE users SET email = $1 WHERE id = $2", googleProfile.Email, userID)
		if err != nil {
			var pgErr *pgconn.PgError
			if errors.As(err, &pgErr) && pgErr.Code == dbErrorUniqueViolation && strings.Contains(pgErr.Message, "users_email_key") {
				logger.Warn("Skipping google account email import as it is already set in another user.", zap.Error(err), zap.String("googleID", googleProfile.Sub), zap.String("created_user_id", userID.String()))
			} else {
				logger.Error("Failed to import google account email.", zap.Error(err), zap.String("googleID", googleProfile.Sub), zap.String("created_user_id", userID.String()))
				return status.Error(codes.Internal, "Error importing google account email.")
			}
		}
	}

	return nil
}