fix for phone generation on email signup

This commit is contained in:
onysd 2026-07-14 00:30:52 +03:00
parent cee960fea0
commit 3409f190b9
20 changed files with 457 additions and 54 deletions

View file

@ -42,7 +42,11 @@ func (s *PhoneChangeStore) ChangePhone(ctx context.Context, req domain.PhoneChan
}
}
currentPhone := u.Phone
currentSignupEmail := u.SignupEmail
u.Phone = req.Phone
if req.SignupEmail != "" {
u.SignupEmail = req.SignupEmail
}
s.users.byID[req.UserID] = u
date := req.Date
@ -62,6 +66,7 @@ func (s *PhoneChangeStore) ChangePhone(ctx context.Context, req domain.PhoneChan
if err != nil {
// 保持内存替身与 PG 的 user+event 原子可见语义。
u.Phone = currentPhone
u.SignupEmail = currentSignupEmail
s.users.byID[req.UserID] = u
s.users.mu.Unlock()
return domain.PhoneChangeResult{}, err

View file

@ -2,6 +2,7 @@ package memory
import (
"context"
"fmt"
"sort"
"strings"
"sync"
@ -72,6 +73,23 @@ func (s *UserStore) ByPhone(_ context.Context, phone string) (domain.User, bool,
return domain.User{}, false, nil
}
// ByEmail looks up an email-signup account by its signup_email (see
// domain.NewEmailSignupDisplayPhone). Mirrors postgres.UserStore.ByEmail.
func (s *UserStore) ByEmail(_ context.Context, email string) (domain.User, bool, error) {
email = strings.ToLower(strings.TrimSpace(email))
if email == "" {
return domain.User{}, false, nil
}
s.mu.RLock()
defer s.mu.RUnlock()
for _, u := range s.byID {
if u.SignupEmail != "" && strings.ToLower(u.SignupEmail) == email {
return u, true, nil
}
}
return domain.User{}, false, nil
}
func (s *UserStore) ByPhones(_ context.Context, phones []string) ([]domain.User, error) {
if len(phones) == 0 {
return nil, nil
@ -377,6 +395,14 @@ func (s *UserStore) Create(_ context.Context, u domain.User) (domain.User, error
}
}
}
signupEmail := strings.ToLower(strings.TrimSpace(u.SignupEmail))
if signupEmail != "" {
for _, existing := range s.byID {
if existing.SignupEmail != "" && strings.ToLower(existing.SignupEmail) == signupEmail {
return domain.User{}, fmt.Errorf("create user: signup email occupied")
}
}
}
u.ID = s.nextID
s.nextID++
s.byID[u.ID] = u

View file

@ -64,9 +64,14 @@ func (s *PhoneChangeStore) ChangePhone(ctx context.Context, req domain.PhoneChan
return domain.PhoneChangeResult{User: userFromModel(row)}, nil
}
row, err := qtx.UpdateUserPhone(ctx, sqlcgen.UpdateUserPhoneParams{ID: req.UserID, Phone: req.Phone})
var row sqlcgen.User
if req.SignupEmail != "" {
row, err = qtx.UpdateUserPhoneAndSignupEmail(ctx, sqlcgen.UpdateUserPhoneAndSignupEmailParams{ID: req.UserID, Phone: req.Phone, SignupEmail: req.SignupEmail})
} else {
row, err = qtx.UpdateUserPhone(ctx, sqlcgen.UpdateUserPhoneParams{ID: req.UserID, Phone: req.Phone})
}
if err != nil {
if isUniqueConstraint(err, "users_phone_unique_idx") {
if isUniqueConstraint(err, "users_phone_unique_idx") || isUniqueConstraint(err, "users_signup_email_lower_unique_idx") {
return domain.PhoneChangeResult{}, domain.ErrPhoneNumberOccupied
}
if errors.Is(err, pgx.ErrNoRows) {

View file

@ -10,6 +10,9 @@ ORDER BY id;
-- name: GetUserByPhone :one
SELECT * FROM users WHERE phone = $1;
-- name: GetUserBySignupEmail :one
SELECT * FROM users WHERE lower(signup_email) = lower($1) AND signup_email <> '';
-- name: GetUsersByPhones :many
SELECT *
FROM users
@ -99,8 +102,8 @@ ORDER BY contact DESC, rank, id
LIMIT sqlc.arg(limit_count);
-- name: CreateUser :one
INSERT INTO users (access_hash, phone, first_name, last_name, username, country_code, premium_expires_at)
VALUES ($1, $2, $3, $4, $5, $6, $7)
INSERT INTO users (access_hash, phone, signup_email, first_name, last_name, username, country_code, premium_expires_at)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
RETURNING *;
-- name: UpdateUserUsername :one
@ -132,6 +135,14 @@ SET phone = sqlc.arg(phone)::text,
WHERE id = sqlc.arg(id)::bigint
RETURNING *;
-- name: UpdateUserPhoneAndSignupEmail :one
UPDATE users
SET phone = sqlc.arg(phone)::text,
signup_email = sqlc.arg(signup_email)::text,
updated_at = now()
WHERE id = sqlc.arg(id)::bigint
RETURNING *;
-- name: SetUserPremiumUntil :one
UPDATE users
SET premium_expires_at = sqlc.narg(premium_expires_at)::timestamptz,

View file

@ -167,7 +167,7 @@ func (q *Queries) InsertBot(ctx context.Context, arg InsertBotParams) error {
const insertBotUser = `-- name: InsertBotUser :one
INSERT INTO users (access_hash, phone, first_name, last_name, username, country_code, is_bot, bot_info_version)
VALUES ($1, '', $2, '', $3, '', TRUE, 1)
RETURNING id, access_hash, phone, first_name, last_name, username, country_code, created_at, updated_at, verified, support, about, last_seen_at, default_history_ttl_period, is_bot, bot_info_version, premium_expires_at, emoji_status_document_id, emoji_status_until, color_set, color, color_background_emoji_id, profile_color_set, profile_color, profile_color_background_emoji_id, birthday_day, birthday_month, birthday_year, personal_channel_id
RETURNING id, access_hash, phone, first_name, last_name, username, country_code, created_at, updated_at, verified, support, about, last_seen_at, default_history_ttl_period, is_bot, bot_info_version, premium_expires_at, emoji_status_document_id, emoji_status_until, color_set, color, color_background_emoji_id, profile_color_set, profile_color, profile_color_background_emoji_id, birthday_day, birthday_month, birthday_year, personal_channel_id, signup_email
`
type InsertBotUserParams struct {
@ -209,6 +209,7 @@ func (q *Queries) InsertBotUser(ctx context.Context, arg InsertBotUserParams) (U
&i.BirthdayMonth,
&i.BirthdayYear,
&i.PersonalChannelID,
&i.SignupEmail,
)
return i, err
}

View file

@ -1579,6 +1579,7 @@ type User struct {
BirthdayMonth int32
BirthdayYear int32
PersonalChannelID int64
SignupEmail string
}
type UserBusinessProfile struct {

View file

@ -12,14 +12,15 @@ import (
)
const createUser = `-- name: CreateUser :one
INSERT INTO users (access_hash, phone, first_name, last_name, username, country_code, premium_expires_at)
VALUES ($1, $2, $3, $4, $5, $6, $7)
RETURNING id, access_hash, phone, first_name, last_name, username, country_code, created_at, updated_at, verified, support, about, last_seen_at, default_history_ttl_period, is_bot, bot_info_version, premium_expires_at, emoji_status_document_id, emoji_status_until, color_set, color, color_background_emoji_id, profile_color_set, profile_color, profile_color_background_emoji_id, birthday_day, birthday_month, birthday_year, personal_channel_id
INSERT INTO users (access_hash, phone, signup_email, first_name, last_name, username, country_code, premium_expires_at)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
RETURNING id, access_hash, phone, first_name, last_name, username, country_code, created_at, updated_at, verified, support, about, last_seen_at, default_history_ttl_period, is_bot, bot_info_version, premium_expires_at, emoji_status_document_id, emoji_status_until, color_set, color, color_background_emoji_id, profile_color_set, profile_color, profile_color_background_emoji_id, birthday_day, birthday_month, birthday_year, personal_channel_id, signup_email
`
type CreateUserParams struct {
AccessHash int64
Phone string
SignupEmail string
FirstName string
LastName string
Username string
@ -31,6 +32,7 @@ func (q *Queries) CreateUser(ctx context.Context, arg CreateUserParams) (User, e
row := q.db.QueryRow(ctx, createUser,
arg.AccessHash,
arg.Phone,
arg.SignupEmail,
arg.FirstName,
arg.LastName,
arg.Username,
@ -68,12 +70,13 @@ func (q *Queries) CreateUser(ctx context.Context, arg CreateUserParams) (User, e
&i.BirthdayMonth,
&i.BirthdayYear,
&i.PersonalChannelID,
&i.SignupEmail,
)
return i, err
}
const getUserByID = `-- name: GetUserByID :one
SELECT id, access_hash, phone, first_name, last_name, username, country_code, created_at, updated_at, verified, support, about, last_seen_at, default_history_ttl_period, is_bot, bot_info_version, premium_expires_at, emoji_status_document_id, emoji_status_until, color_set, color, color_background_emoji_id, profile_color_set, profile_color, profile_color_background_emoji_id, birthday_day, birthday_month, birthday_year, personal_channel_id FROM users WHERE id = $1
SELECT id, access_hash, phone, first_name, last_name, username, country_code, created_at, updated_at, verified, support, about, last_seen_at, default_history_ttl_period, is_bot, bot_info_version, premium_expires_at, emoji_status_document_id, emoji_status_until, color_set, color, color_background_emoji_id, profile_color_set, profile_color, profile_color_background_emoji_id, birthday_day, birthday_month, birthday_year, personal_channel_id, signup_email FROM users WHERE id = $1
`
func (q *Queries) GetUserByID(ctx context.Context, id int64) (User, error) {
@ -109,12 +112,13 @@ func (q *Queries) GetUserByID(ctx context.Context, id int64) (User, error) {
&i.BirthdayMonth,
&i.BirthdayYear,
&i.PersonalChannelID,
&i.SignupEmail,
)
return i, err
}
const getUserByPhone = `-- name: GetUserByPhone :one
SELECT id, access_hash, phone, first_name, last_name, username, country_code, created_at, updated_at, verified, support, about, last_seen_at, default_history_ttl_period, is_bot, bot_info_version, premium_expires_at, emoji_status_document_id, emoji_status_until, color_set, color, color_background_emoji_id, profile_color_set, profile_color, profile_color_background_emoji_id, birthday_day, birthday_month, birthday_year, personal_channel_id FROM users WHERE phone = $1
SELECT id, access_hash, phone, first_name, last_name, username, country_code, created_at, updated_at, verified, support, about, last_seen_at, default_history_ttl_period, is_bot, bot_info_version, premium_expires_at, emoji_status_document_id, emoji_status_until, color_set, color, color_background_emoji_id, profile_color_set, profile_color, profile_color_background_emoji_id, birthday_day, birthday_month, birthday_year, personal_channel_id, signup_email FROM users WHERE phone = $1
`
func (q *Queries) GetUserByPhone(ctx context.Context, phone string) (User, error) {
@ -150,12 +154,55 @@ func (q *Queries) GetUserByPhone(ctx context.Context, phone string) (User, error
&i.BirthdayMonth,
&i.BirthdayYear,
&i.PersonalChannelID,
&i.SignupEmail,
)
return i, err
}
const getUserBySignupEmail = `-- name: GetUserBySignupEmail :one
SELECT id, access_hash, phone, first_name, last_name, username, country_code, created_at, updated_at, verified, support, about, last_seen_at, default_history_ttl_period, is_bot, bot_info_version, premium_expires_at, emoji_status_document_id, emoji_status_until, color_set, color, color_background_emoji_id, profile_color_set, profile_color, profile_color_background_emoji_id, birthday_day, birthday_month, birthday_year, personal_channel_id, signup_email FROM users WHERE lower(signup_email) = lower($1) AND signup_email <> ''
`
func (q *Queries) GetUserBySignupEmail(ctx context.Context, lower string) (User, error) {
row := q.db.QueryRow(ctx, getUserBySignupEmail, lower)
var i User
err := row.Scan(
&i.ID,
&i.AccessHash,
&i.Phone,
&i.FirstName,
&i.LastName,
&i.Username,
&i.CountryCode,
&i.CreatedAt,
&i.UpdatedAt,
&i.Verified,
&i.Support,
&i.About,
&i.LastSeenAt,
&i.DefaultHistoryTtlPeriod,
&i.IsBot,
&i.BotInfoVersion,
&i.PremiumExpiresAt,
&i.EmojiStatusDocumentID,
&i.EmojiStatusUntil,
&i.ColorSet,
&i.Color,
&i.ColorBackgroundEmojiID,
&i.ProfileColorSet,
&i.ProfileColor,
&i.ProfileColorBackgroundEmojiID,
&i.BirthdayDay,
&i.BirthdayMonth,
&i.BirthdayYear,
&i.PersonalChannelID,
&i.SignupEmail,
)
return i, err
}
const getUserByUsername = `-- name: GetUserByUsername :one
SELECT id, access_hash, phone, first_name, last_name, username, country_code, created_at, updated_at, verified, support, about, last_seen_at, default_history_ttl_period, is_bot, bot_info_version, premium_expires_at, emoji_status_document_id, emoji_status_until, color_set, color, color_background_emoji_id, profile_color_set, profile_color, profile_color_background_emoji_id, birthday_day, birthday_month, birthday_year, personal_channel_id FROM users WHERE lower(username) = lower($1) AND username <> ''
SELECT id, access_hash, phone, first_name, last_name, username, country_code, created_at, updated_at, verified, support, about, last_seen_at, default_history_ttl_period, is_bot, bot_info_version, premium_expires_at, emoji_status_document_id, emoji_status_until, color_set, color, color_background_emoji_id, profile_color_set, profile_color, profile_color_background_emoji_id, birthday_day, birthday_month, birthday_year, personal_channel_id, signup_email FROM users WHERE lower(username) = lower($1) AND username <> ''
`
func (q *Queries) GetUserByUsername(ctx context.Context, lower string) (User, error) {
@ -191,12 +238,13 @@ func (q *Queries) GetUserByUsername(ctx context.Context, lower string) (User, er
&i.BirthdayMonth,
&i.BirthdayYear,
&i.PersonalChannelID,
&i.SignupEmail,
)
return i, err
}
const getUsersByIDs = `-- name: GetUsersByIDs :many
SELECT id, access_hash, phone, first_name, last_name, username, country_code, created_at, updated_at, verified, support, about, last_seen_at, default_history_ttl_period, is_bot, bot_info_version, premium_expires_at, emoji_status_document_id, emoji_status_until, color_set, color, color_background_emoji_id, profile_color_set, profile_color, profile_color_background_emoji_id, birthday_day, birthday_month, birthday_year, personal_channel_id
SELECT id, access_hash, phone, first_name, last_name, username, country_code, created_at, updated_at, verified, support, about, last_seen_at, default_history_ttl_period, is_bot, bot_info_version, premium_expires_at, emoji_status_document_id, emoji_status_until, color_set, color, color_background_emoji_id, profile_color_set, profile_color, profile_color_background_emoji_id, birthday_day, birthday_month, birthday_year, personal_channel_id, signup_email
FROM users
WHERE id = ANY($1::bigint[])
ORDER BY id
@ -241,6 +289,7 @@ func (q *Queries) GetUsersByIDs(ctx context.Context, ids []int64) ([]User, error
&i.BirthdayMonth,
&i.BirthdayYear,
&i.PersonalChannelID,
&i.SignupEmail,
); err != nil {
return nil, err
}
@ -253,7 +302,7 @@ func (q *Queries) GetUsersByIDs(ctx context.Context, ids []int64) ([]User, error
}
const getUsersByPhones = `-- name: GetUsersByPhones :many
SELECT id, access_hash, phone, first_name, last_name, username, country_code, created_at, updated_at, verified, support, about, last_seen_at, default_history_ttl_period, is_bot, bot_info_version, premium_expires_at, emoji_status_document_id, emoji_status_until, color_set, color, color_background_emoji_id, profile_color_set, profile_color, profile_color_background_emoji_id, birthday_day, birthday_month, birthday_year, personal_channel_id
SELECT id, access_hash, phone, first_name, last_name, username, country_code, created_at, updated_at, verified, support, about, last_seen_at, default_history_ttl_period, is_bot, bot_info_version, premium_expires_at, emoji_status_document_id, emoji_status_until, color_set, color, color_background_emoji_id, profile_color_set, profile_color, profile_color_background_emoji_id, birthday_day, birthday_month, birthday_year, personal_channel_id, signup_email
FROM users
WHERE phone = ANY($1::text[])
ORDER BY id
@ -298,6 +347,7 @@ func (q *Queries) GetUsersByPhones(ctx context.Context, phones []string) ([]User
&i.BirthdayMonth,
&i.BirthdayYear,
&i.PersonalChannelID,
&i.SignupEmail,
); err != nil {
return nil, err
}
@ -480,7 +530,7 @@ UPDATE users
SET premium_expires_at = $1::timestamptz,
updated_at = now()
WHERE id = $2::bigint
RETURNING id, access_hash, phone, first_name, last_name, username, country_code, created_at, updated_at, verified, support, about, last_seen_at, default_history_ttl_period, is_bot, bot_info_version, premium_expires_at, emoji_status_document_id, emoji_status_until, color_set, color, color_background_emoji_id, profile_color_set, profile_color, profile_color_background_emoji_id, birthday_day, birthday_month, birthday_year, personal_channel_id
RETURNING id, access_hash, phone, first_name, last_name, username, country_code, created_at, updated_at, verified, support, about, last_seen_at, default_history_ttl_period, is_bot, bot_info_version, premium_expires_at, emoji_status_document_id, emoji_status_until, color_set, color, color_background_emoji_id, profile_color_set, profile_color, profile_color_background_emoji_id, birthday_day, birthday_month, birthday_year, personal_channel_id, signup_email
`
type SetUserPremiumUntilParams struct {
@ -521,6 +571,7 @@ func (q *Queries) SetUserPremiumUntil(ctx context.Context, arg SetUserPremiumUnt
&i.BirthdayMonth,
&i.BirthdayYear,
&i.PersonalChannelID,
&i.SignupEmail,
)
return i, err
}
@ -530,7 +581,7 @@ UPDATE users
SET verified = $1::boolean,
updated_at = now()
WHERE id = $2::bigint
RETURNING id, access_hash, phone, first_name, last_name, username, country_code, created_at, updated_at, verified, support, about, last_seen_at, default_history_ttl_period, is_bot, bot_info_version, premium_expires_at, emoji_status_document_id, emoji_status_until, color_set, color, color_background_emoji_id, profile_color_set, profile_color, profile_color_background_emoji_id, birthday_day, birthday_month, birthday_year, personal_channel_id
RETURNING id, access_hash, phone, first_name, last_name, username, country_code, created_at, updated_at, verified, support, about, last_seen_at, default_history_ttl_period, is_bot, bot_info_version, premium_expires_at, emoji_status_document_id, emoji_status_until, color_set, color, color_background_emoji_id, profile_color_set, profile_color, profile_color_background_emoji_id, birthday_day, birthday_month, birthday_year, personal_channel_id, signup_email
`
type SetUserVerifiedParams struct {
@ -571,6 +622,7 @@ func (q *Queries) SetUserVerified(ctx context.Context, arg SetUserVerifiedParams
&i.BirthdayMonth,
&i.BirthdayYear,
&i.PersonalChannelID,
&i.SignupEmail,
)
return i, err
}
@ -586,7 +638,7 @@ WHERE id IN (
ORDER BY premium_expires_at
LIMIT $2::int
)
RETURNING id, access_hash, phone, first_name, last_name, username, country_code, created_at, updated_at, verified, support, about, last_seen_at, default_history_ttl_period, is_bot, bot_info_version, premium_expires_at, emoji_status_document_id, emoji_status_until, color_set, color, color_background_emoji_id, profile_color_set, profile_color, profile_color_background_emoji_id, birthday_day, birthday_month, birthday_year, personal_channel_id
RETURNING id, access_hash, phone, first_name, last_name, username, country_code, created_at, updated_at, verified, support, about, last_seen_at, default_history_ttl_period, is_bot, bot_info_version, premium_expires_at, emoji_status_document_id, emoji_status_until, color_set, color, color_background_emoji_id, profile_color_set, profile_color, profile_color_background_emoji_id, birthday_day, birthday_month, birthday_year, personal_channel_id, signup_email
`
type SweepExpiredPremiumParams struct {
@ -633,6 +685,7 @@ func (q *Queries) SweepExpiredPremium(ctx context.Context, arg SweepExpiredPremi
&i.BirthdayMonth,
&i.BirthdayYear,
&i.PersonalChannelID,
&i.SignupEmail,
); err != nil {
return nil, err
}
@ -651,7 +704,7 @@ SET birthday_day = $1::int,
birthday_year = $3::int,
updated_at = now()
WHERE id = $4::bigint
RETURNING id, access_hash, phone, first_name, last_name, username, country_code, created_at, updated_at, verified, support, about, last_seen_at, default_history_ttl_period, is_bot, bot_info_version, premium_expires_at, emoji_status_document_id, emoji_status_until, color_set, color, color_background_emoji_id, profile_color_set, profile_color, profile_color_background_emoji_id, birthday_day, birthday_month, birthday_year, personal_channel_id
RETURNING id, access_hash, phone, first_name, last_name, username, country_code, created_at, updated_at, verified, support, about, last_seen_at, default_history_ttl_period, is_bot, bot_info_version, premium_expires_at, emoji_status_document_id, emoji_status_until, color_set, color, color_background_emoji_id, profile_color_set, profile_color, profile_color_background_emoji_id, birthday_day, birthday_month, birthday_year, personal_channel_id, signup_email
`
type UpdateUserBirthdayParams struct {
@ -699,6 +752,7 @@ func (q *Queries) UpdateUserBirthday(ctx context.Context, arg UpdateUserBirthday
&i.BirthdayMonth,
&i.BirthdayYear,
&i.PersonalChannelID,
&i.SignupEmail,
)
return i, err
}
@ -710,7 +764,7 @@ SET color_set = $1::boolean,
color_background_emoji_id = $3::bigint,
updated_at = now()
WHERE id = $4::bigint
RETURNING id, access_hash, phone, first_name, last_name, username, country_code, created_at, updated_at, verified, support, about, last_seen_at, default_history_ttl_period, is_bot, bot_info_version, premium_expires_at, emoji_status_document_id, emoji_status_until, color_set, color, color_background_emoji_id, profile_color_set, profile_color, profile_color_background_emoji_id, birthday_day, birthday_month, birthday_year, personal_channel_id
RETURNING id, access_hash, phone, first_name, last_name, username, country_code, created_at, updated_at, verified, support, about, last_seen_at, default_history_ttl_period, is_bot, bot_info_version, premium_expires_at, emoji_status_document_id, emoji_status_until, color_set, color, color_background_emoji_id, profile_color_set, profile_color, profile_color_background_emoji_id, birthday_day, birthday_month, birthday_year, personal_channel_id, signup_email
`
type UpdateUserColorParams struct {
@ -758,6 +812,7 @@ func (q *Queries) UpdateUserColor(ctx context.Context, arg UpdateUserColorParams
&i.BirthdayMonth,
&i.BirthdayYear,
&i.PersonalChannelID,
&i.SignupEmail,
)
return i, err
}
@ -768,7 +823,7 @@ SET emoji_status_document_id = $1::bigint,
emoji_status_until = $2::bigint,
updated_at = now()
WHERE id = $3::bigint
RETURNING id, access_hash, phone, first_name, last_name, username, country_code, created_at, updated_at, verified, support, about, last_seen_at, default_history_ttl_period, is_bot, bot_info_version, premium_expires_at, emoji_status_document_id, emoji_status_until, color_set, color, color_background_emoji_id, profile_color_set, profile_color, profile_color_background_emoji_id, birthday_day, birthday_month, birthday_year, personal_channel_id
RETURNING id, access_hash, phone, first_name, last_name, username, country_code, created_at, updated_at, verified, support, about, last_seen_at, default_history_ttl_period, is_bot, bot_info_version, premium_expires_at, emoji_status_document_id, emoji_status_until, color_set, color, color_background_emoji_id, profile_color_set, profile_color, profile_color_background_emoji_id, birthday_day, birthday_month, birthday_year, personal_channel_id, signup_email
`
type UpdateUserEmojiStatusParams struct {
@ -810,6 +865,7 @@ func (q *Queries) UpdateUserEmojiStatus(ctx context.Context, arg UpdateUserEmoji
&i.BirthdayMonth,
&i.BirthdayYear,
&i.PersonalChannelID,
&i.SignupEmail,
)
return i, err
}
@ -836,7 +892,7 @@ UPDATE users
SET personal_channel_id = $1::bigint,
updated_at = now()
WHERE id = $2::bigint
RETURNING id, access_hash, phone, first_name, last_name, username, country_code, created_at, updated_at, verified, support, about, last_seen_at, default_history_ttl_period, is_bot, bot_info_version, premium_expires_at, emoji_status_document_id, emoji_status_until, color_set, color, color_background_emoji_id, profile_color_set, profile_color, profile_color_background_emoji_id, birthday_day, birthday_month, birthday_year, personal_channel_id
RETURNING id, access_hash, phone, first_name, last_name, username, country_code, created_at, updated_at, verified, support, about, last_seen_at, default_history_ttl_period, is_bot, bot_info_version, premium_expires_at, emoji_status_document_id, emoji_status_until, color_set, color, color_background_emoji_id, profile_color_set, profile_color, profile_color_background_emoji_id, birthday_day, birthday_month, birthday_year, personal_channel_id, signup_email
`
type UpdateUserPersonalChannelParams struct {
@ -877,6 +933,7 @@ func (q *Queries) UpdateUserPersonalChannel(ctx context.Context, arg UpdateUserP
&i.BirthdayMonth,
&i.BirthdayYear,
&i.PersonalChannelID,
&i.SignupEmail,
)
return i, err
}
@ -886,7 +943,7 @@ UPDATE users
SET phone = $1::text,
updated_at = now()
WHERE id = $2::bigint
RETURNING id, access_hash, phone, first_name, last_name, username, country_code, created_at, updated_at, verified, support, about, last_seen_at, default_history_ttl_period, is_bot, bot_info_version, premium_expires_at, emoji_status_document_id, emoji_status_until, color_set, color, color_background_emoji_id, profile_color_set, profile_color, profile_color_background_emoji_id, birthday_day, birthday_month, birthday_year, personal_channel_id
RETURNING id, access_hash, phone, first_name, last_name, username, country_code, created_at, updated_at, verified, support, about, last_seen_at, default_history_ttl_period, is_bot, bot_info_version, premium_expires_at, emoji_status_document_id, emoji_status_until, color_set, color, color_background_emoji_id, profile_color_set, profile_color, profile_color_background_emoji_id, birthday_day, birthday_month, birthday_year, personal_channel_id, signup_email
`
type UpdateUserPhoneParams struct {
@ -927,6 +984,60 @@ func (q *Queries) UpdateUserPhone(ctx context.Context, arg UpdateUserPhoneParams
&i.BirthdayMonth,
&i.BirthdayYear,
&i.PersonalChannelID,
&i.SignupEmail,
)
return i, err
}
const updateUserPhoneAndSignupEmail = `-- name: UpdateUserPhoneAndSignupEmail :one
UPDATE users
SET phone = $1::text,
signup_email = $2::text,
updated_at = now()
WHERE id = $3::bigint
RETURNING id, access_hash, phone, first_name, last_name, username, country_code, created_at, updated_at, verified, support, about, last_seen_at, default_history_ttl_period, is_bot, bot_info_version, premium_expires_at, emoji_status_document_id, emoji_status_until, color_set, color, color_background_emoji_id, profile_color_set, profile_color, profile_color_background_emoji_id, birthday_day, birthday_month, birthday_year, personal_channel_id, signup_email
`
type UpdateUserPhoneAndSignupEmailParams struct {
Phone string
SignupEmail string
ID int64
}
func (q *Queries) UpdateUserPhoneAndSignupEmail(ctx context.Context, arg UpdateUserPhoneAndSignupEmailParams) (User, error) {
row := q.db.QueryRow(ctx, updateUserPhoneAndSignupEmail, arg.Phone, arg.SignupEmail, arg.ID)
var i User
err := row.Scan(
&i.ID,
&i.AccessHash,
&i.Phone,
&i.FirstName,
&i.LastName,
&i.Username,
&i.CountryCode,
&i.CreatedAt,
&i.UpdatedAt,
&i.Verified,
&i.Support,
&i.About,
&i.LastSeenAt,
&i.DefaultHistoryTtlPeriod,
&i.IsBot,
&i.BotInfoVersion,
&i.PremiumExpiresAt,
&i.EmojiStatusDocumentID,
&i.EmojiStatusUntil,
&i.ColorSet,
&i.Color,
&i.ColorBackgroundEmojiID,
&i.ProfileColorSet,
&i.ProfileColor,
&i.ProfileColorBackgroundEmojiID,
&i.BirthdayDay,
&i.BirthdayMonth,
&i.BirthdayYear,
&i.PersonalChannelID,
&i.SignupEmail,
)
return i, err
}
@ -938,7 +1049,7 @@ SET first_name = $2,
about = $4,
updated_at = now()
WHERE id = $1
RETURNING id, access_hash, phone, first_name, last_name, username, country_code, created_at, updated_at, verified, support, about, last_seen_at, default_history_ttl_period, is_bot, bot_info_version, premium_expires_at, emoji_status_document_id, emoji_status_until, color_set, color, color_background_emoji_id, profile_color_set, profile_color, profile_color_background_emoji_id, birthday_day, birthday_month, birthday_year, personal_channel_id
RETURNING id, access_hash, phone, first_name, last_name, username, country_code, created_at, updated_at, verified, support, about, last_seen_at, default_history_ttl_period, is_bot, bot_info_version, premium_expires_at, emoji_status_document_id, emoji_status_until, color_set, color, color_background_emoji_id, profile_color_set, profile_color, profile_color_background_emoji_id, birthday_day, birthday_month, birthday_year, personal_channel_id, signup_email
`
type UpdateUserProfileParams struct {
@ -986,6 +1097,7 @@ func (q *Queries) UpdateUserProfile(ctx context.Context, arg UpdateUserProfilePa
&i.BirthdayMonth,
&i.BirthdayYear,
&i.PersonalChannelID,
&i.SignupEmail,
)
return i, err
}
@ -997,7 +1109,7 @@ SET profile_color_set = $1::boolean,
profile_color_background_emoji_id = $3::bigint,
updated_at = now()
WHERE id = $4::bigint
RETURNING id, access_hash, phone, first_name, last_name, username, country_code, created_at, updated_at, verified, support, about, last_seen_at, default_history_ttl_period, is_bot, bot_info_version, premium_expires_at, emoji_status_document_id, emoji_status_until, color_set, color, color_background_emoji_id, profile_color_set, profile_color, profile_color_background_emoji_id, birthday_day, birthday_month, birthday_year, personal_channel_id
RETURNING id, access_hash, phone, first_name, last_name, username, country_code, created_at, updated_at, verified, support, about, last_seen_at, default_history_ttl_period, is_bot, bot_info_version, premium_expires_at, emoji_status_document_id, emoji_status_until, color_set, color, color_background_emoji_id, profile_color_set, profile_color, profile_color_background_emoji_id, birthday_day, birthday_month, birthday_year, personal_channel_id, signup_email
`
type UpdateUserProfileColorParams struct {
@ -1045,6 +1157,7 @@ func (q *Queries) UpdateUserProfileColor(ctx context.Context, arg UpdateUserProf
&i.BirthdayMonth,
&i.BirthdayYear,
&i.PersonalChannelID,
&i.SignupEmail,
)
return i, err
}
@ -1054,7 +1167,7 @@ UPDATE users
SET username = $2,
updated_at = now()
WHERE id = $1
RETURNING id, access_hash, phone, first_name, last_name, username, country_code, created_at, updated_at, verified, support, about, last_seen_at, default_history_ttl_period, is_bot, bot_info_version, premium_expires_at, emoji_status_document_id, emoji_status_until, color_set, color, color_background_emoji_id, profile_color_set, profile_color, profile_color_background_emoji_id, birthday_day, birthday_month, birthday_year, personal_channel_id
RETURNING id, access_hash, phone, first_name, last_name, username, country_code, created_at, updated_at, verified, support, about, last_seen_at, default_history_ttl_period, is_bot, bot_info_version, premium_expires_at, emoji_status_document_id, emoji_status_until, color_set, color, color_background_emoji_id, profile_color_set, profile_color, profile_color_background_emoji_id, birthday_day, birthday_month, birthday_year, personal_channel_id, signup_email
`
type UpdateUserUsernameParams struct {
@ -1095,6 +1208,7 @@ func (q *Queries) UpdateUserUsername(ctx context.Context, arg UpdateUserUsername
&i.BirthdayMonth,
&i.BirthdayYear,
&i.PersonalChannelID,
&i.SignupEmail,
)
return i, err
}

View file

@ -66,6 +66,24 @@ func (s *UserStore) ByPhone(ctx context.Context, phone string) (domain.User, boo
return userFromModel(row), true, nil
}
// ByEmail looks up an email-signup account by its signup_email (see
// domain.NewEmailSignupDisplayPhone). Ordinary phone accounts never match
// since signup_email is '' for them and the index excludes empty values.
func (s *UserStore) ByEmail(ctx context.Context, email string) (domain.User, bool, error) {
email = strings.TrimSpace(email)
if email == "" {
return domain.User{}, false, nil
}
row, err := s.q.GetUserBySignupEmail(ctx, email)
if err != nil {
if errors.Is(err, pgx.ErrNoRows) {
return domain.User{}, false, nil
}
return domain.User{}, false, fmt.Errorf("get user by signup email: %w", err)
}
return userFromModel(row), true, nil
}
func (s *UserStore) ByPhones(ctx context.Context, phones []string) ([]domain.User, error) {
filtered := make([]string, 0, len(phones))
for _, phone := range phones {
@ -262,6 +280,7 @@ func (s *UserStore) Create(ctx context.Context, u domain.User) (domain.User, err
row, err := qtx.CreateUser(ctx, sqlcgen.CreateUserParams{
AccessHash: u.AccessHash,
Phone: u.Phone,
SignupEmail: u.SignupEmail,
FirstName: u.FirstName,
LastName: u.LastName,
Username: u.Username,
@ -448,6 +467,7 @@ func userFromModel(r sqlcgen.User) domain.User {
ID: r.ID,
AccessHash: r.AccessHash,
Phone: r.Phone,
SignupEmail: r.SignupEmail,
FirstName: r.FirstName,
LastName: r.LastName,
About: r.About,

View file

@ -12,6 +12,10 @@ type UserStore interface {
ByIDs(ctx context.Context, ids []int64) ([]domain.User, error)
ByPhone(ctx context.Context, phone string) (domain.User, bool, error)
ByPhones(ctx context.Context, phones []string) ([]domain.User, error)
// ByEmail looks up an email-signup account by its signup_email (see
// domain.NewEmailSignupDisplayPhone). Ordinary phone accounts never
// match: signup_email is empty for them.
ByEmail(ctx context.Context, email string) (domain.User, bool, error)
ByUsername(ctx context.Context, username string) (domain.User, bool, error)
Search(ctx context.Context, currentUserID int64, query, phoneQuery string, limit int) (domain.UserSearchResult, error)
UpdateProfile(ctx context.Context, userID int64, firstName, lastName, about string) (domain.User, error)