package db import ( "context" "time" "github.com/jackc/pgx/v5" ) type VPNUser struct { ID int64 TelegramID *int64 RemnawaveUUID string RemnawaveUsername string ExternalSquadUUID *string InternalSquadUUIDs []string ExpireAt *time.Time } func (d *DB) UpsertTelegramUser(ctx context.Context, telegramID int64, username, firstName string) error { _, err := d.pool.Exec(ctx, ` INSERT INTO telegram_users (telegram_id, username, first_name) VALUES ($1, $2, $3) ON CONFLICT (telegram_id) DO UPDATE SET username = EXCLUDED.username, first_name = EXCLUDED.first_name`, telegramID, nullStr(username), nullStr(firstName)) return err } func (d *DB) SaveVPNUser(ctx context.Context, u VPNUser) error { _, err := d.pool.Exec(ctx, ` INSERT INTO vpn_users ( telegram_id, remnawave_uuid, remnawave_username, external_squad_uuid, internal_squad_uuids, expire_at ) VALUES ($1, $2, $3, $4, $5, $6) ON CONFLICT (remnawave_uuid) DO UPDATE SET telegram_id = EXCLUDED.telegram_id, remnawave_username = EXCLUDED.remnawave_username, external_squad_uuid = EXCLUDED.external_squad_uuid, internal_squad_uuids = EXCLUDED.internal_squad_uuids, expire_at = EXCLUDED.expire_at, updated_at = NOW()`, u.TelegramID, u.RemnawaveUUID, u.RemnawaveUsername, u.ExternalSquadUUID, u.InternalSquadUUIDs, u.ExpireAt) return err } func (d *DB) GetVPNByTelegramID(ctx context.Context, telegramID int64) (*VPNUser, error) { row := d.pool.QueryRow(ctx, ` SELECT id, telegram_id, remnawave_uuid::text, remnawave_username, external_squad_uuid::text, internal_squad_uuids::text[], expire_at FROM vpn_users WHERE telegram_id = $1 ORDER BY expire_at DESC NULLS LAST LIMIT 1`, telegramID) var u VPNUser var ext *string var internal []string err := row.Scan(&u.ID, &u.TelegramID, &u.RemnawaveUUID, &u.RemnawaveUsername, &ext, &internal, &u.ExpireAt) if err == pgx.ErrNoRows { return nil, nil } if err != nil { return nil, err } u.ExternalSquadUUID = ext u.InternalSquadUUIDs = internal return &u, nil } func (d *DB) GetVPNByUsername(ctx context.Context, username string) (*VPNUser, error) { row := d.pool.QueryRow(ctx, ` SELECT id, telegram_id, remnawave_uuid::text, remnawave_username, external_squad_uuid::text, internal_squad_uuids::text[], expire_at FROM vpn_users WHERE remnawave_username = $1`, username) var u VPNUser var ext *string var internal []string err := row.Scan(&u.ID, &u.TelegramID, &u.RemnawaveUUID, &u.RemnawaveUsername, &ext, &internal, &u.ExpireAt) if err == pgx.ErrNoRows { return nil, nil } if err != nil { return nil, err } u.ExternalSquadUUID = ext u.InternalSquadUUIDs = internal return &u, nil } func nullStr(s string) *string { if s == "" { return nil } return &s }