270 lines
8.6 KiB
Go
270 lines
8.6 KiB
Go
package model
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"time"
|
|
|
|
userentity "spark-server/internal/module/user/entity"
|
|
"spark-server/internal/pkg/errs"
|
|
)
|
|
|
|
func (m *Repo) ListUsers(ctx context.Context, emailLike string, page, size int) ([]UserRow, int64, error) {
|
|
db, err := m.session(ctx)
|
|
if err != nil {
|
|
return nil, 0, err
|
|
}
|
|
base := db.Table("t_users AS u").Joins("LEFT JOIN t_user_emails e ON e.user_id = u.id")
|
|
emailLike = strings.TrimSpace(emailLike)
|
|
if emailLike != "" {
|
|
base = base.Where("e.email LIKE ?", "%"+emailLike+"%")
|
|
}
|
|
var total int64
|
|
_ = base.Count(&total).Error
|
|
var rows []userScanRow
|
|
if err := base.Select(userListSelect).Order("u.id DESC").Offset(page * size).Limit(size).Scan(&rows).Error; err != nil {
|
|
return nil, 0, mapDBErr(err)
|
|
}
|
|
return userScanToRows(rows), total, nil
|
|
}
|
|
|
|
const userListSelect = `u.id, u.spark_id, u.nickname, u.avatar, u.status, u.last_active_at, u.created_at,
|
|
COALESCE(e.email,'') AS email,
|
|
COALESCE((SELECT d.device_id FROM t_user_devices d WHERE d.user_id = u.id ORDER BY d.last_login_at DESC LIMIT 1), 0) AS device_id,
|
|
COALESCE((SELECT CAST(dev.device_type AS CHAR) FROM t_user_devices d INNER JOIN t_devices dev ON dev.device_id = d.device_id WHERE d.user_id = u.id ORDER BY d.last_login_at DESC LIMIT 1), '') AS platform`
|
|
|
|
func (m *Repo) UsersByEmail(ctx context.Context, email string) ([]UserRow, error) {
|
|
db, err := m.session(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var rows []userScanRow
|
|
err = db.Raw(`
|
|
SELECT u.id, u.spark_id, u.nickname, u.avatar, u.status, u.last_active_at, u.created_at,
|
|
e.email,
|
|
COALESCE((SELECT d.device_id FROM t_user_devices d WHERE d.user_id = u.id ORDER BY d.last_login_at DESC LIMIT 1), 0) AS device_id,
|
|
COALESCE((SELECT CAST(dev.device_type AS CHAR) FROM t_user_devices d INNER JOIN t_devices dev ON dev.device_id = d.device_id WHERE d.user_id = u.id ORDER BY d.last_login_at DESC LIMIT 1), '') AS platform
|
|
FROM t_user_emails e
|
|
INNER JOIN t_users u ON u.id = e.user_id
|
|
WHERE e.email = ?`, email).Scan(&rows).Error
|
|
if err != nil {
|
|
return nil, mapDBErr(err)
|
|
}
|
|
return userScanToRows(rows), nil
|
|
}
|
|
|
|
func (m *Repo) UserByID(ctx context.Context, id int64) (*UserRow, error) {
|
|
db, err := m.session(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var rows []userScanRow
|
|
err = db.Raw(`
|
|
SELECT u.id, u.spark_id, u.nickname, u.avatar, u.status, u.last_active_at, u.created_at,
|
|
COALESCE(e.email,'') AS email,
|
|
COALESCE((SELECT d.device_id FROM t_user_devices d WHERE d.user_id = u.id ORDER BY d.last_login_at DESC LIMIT 1), 0) AS device_id,
|
|
COALESCE((SELECT CAST(dev.device_type AS CHAR) FROM t_user_devices d INNER JOIN t_devices dev ON dev.device_id = d.device_id WHERE d.user_id = u.id ORDER BY d.last_login_at DESC LIMIT 1), '') AS platform
|
|
FROM t_users u
|
|
LEFT JOIN t_user_emails e ON e.user_id = u.id
|
|
WHERE u.id = ?`, id).Scan(&rows).Error
|
|
if err != nil {
|
|
return nil, mapDBErr(err)
|
|
}
|
|
if len(rows) == 0 || rows[0].ID == 0 {
|
|
return nil, errs.ErrNotFound
|
|
}
|
|
r := userScanToRow(rows[0])
|
|
return &r, nil
|
|
}
|
|
|
|
func (m *Repo) UsersByNickname(ctx context.Context, nickname string) ([]UserRow, error) {
|
|
db, err := m.session(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var rows []userScanRow
|
|
err = db.Raw(`
|
|
SELECT u.id, u.spark_id, u.nickname, u.avatar, u.status, u.last_active_at, u.created_at,
|
|
COALESCE(e.email,'') AS email, 0 AS device_id, '' AS platform
|
|
FROM t_users u
|
|
LEFT JOIN t_user_emails e ON e.user_id = u.id
|
|
WHERE u.nickname LIKE ?
|
|
ORDER BY u.id DESC LIMIT 50`, "%"+strings.TrimSpace(nickname)+"%").Scan(&rows).Error
|
|
if err != nil {
|
|
return nil, mapDBErr(err)
|
|
}
|
|
return userScanToRows(rows), nil
|
|
}
|
|
|
|
func (m *Repo) UsersByDevice(ctx context.Context, deviceID string, deviceIDNum uint64) ([]UserRow, error) {
|
|
db, err := m.session(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var rows []userScanRow
|
|
err = db.Raw(`
|
|
SELECT u.id, u.spark_id, u.nickname, u.avatar, u.status, u.last_active_at, u.created_at,
|
|
COALESCE(e.email,'') AS email, d.device_id, CAST(dev.device_type AS CHAR) AS platform
|
|
FROM t_user_devices d
|
|
INNER JOIN t_devices dev ON dev.device_id = d.device_id
|
|
INNER JOIN t_users u ON u.id = d.user_id
|
|
LEFT JOIN t_user_emails e ON e.user_id = u.id
|
|
WHERE CAST(d.device_id AS CHAR) = ? OR d.device_id = ?
|
|
ORDER BY d.last_login_at DESC LIMIT 50`, deviceID, deviceIDNum).Scan(&rows).Error
|
|
if err != nil {
|
|
return nil, mapDBErr(err)
|
|
}
|
|
return userScanToRows(rows), nil
|
|
}
|
|
|
|
func (m *Repo) UsersByIP(ctx context.Context, ip string) ([]UserRow, error) {
|
|
db, err := m.session(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var rows []userScanRow
|
|
err = db.Raw(`
|
|
SELECT DISTINCT u.id, u.spark_id, u.nickname, u.avatar, u.status, u.last_active_at, u.created_at,
|
|
COALESCE(e.email,'') AS email, d.device_id, CAST(dev.device_type AS CHAR) AS platform
|
|
FROM t_user_devices d
|
|
INNER JOIN t_devices dev ON dev.device_id = d.device_id
|
|
INNER JOIN t_users u ON u.id = d.user_id
|
|
LEFT JOIN t_user_emails e ON e.user_id = u.id
|
|
WHERE dev.last_client_ip = ?
|
|
ORDER BY u.id DESC LIMIT 100`, ip).Scan(&rows).Error
|
|
if err != nil {
|
|
return nil, mapDBErr(err)
|
|
}
|
|
return userScanToRows(rows), nil
|
|
}
|
|
|
|
func (m *Repo) SetUserStatusByEmail(ctx context.Context, email string, status userentity.Status) error {
|
|
db, err := m.session(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
res := db.Exec(`
|
|
UPDATE t_users u
|
|
INNER JOIN t_user_emails e ON e.user_id = u.id
|
|
SET u.status = ?, u.updated_at = ?
|
|
WHERE e.email = ?`, int(status), time.Now(), email)
|
|
if res.Error != nil {
|
|
return mapDBErr(res.Error)
|
|
}
|
|
if res.RowsAffected == 0 {
|
|
return errs.ErrNotFound
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (m *Repo) SetNicknameByEmail(ctx context.Context, email, nickname string) error {
|
|
db, err := m.session(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
res := db.Exec(`
|
|
UPDATE t_users u
|
|
INNER JOIN t_user_emails e ON e.user_id = u.id
|
|
SET u.nickname = ?, u.updated_at = ?
|
|
WHERE e.email = ?`, nickname, time.Now(), email)
|
|
if res.Error != nil {
|
|
return mapDBErr(res.Error)
|
|
}
|
|
if res.RowsAffected == 0 {
|
|
return errs.ErrNotFound
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (m *Repo) ClearAvatarByEmail(ctx context.Context, email string) error {
|
|
db, err := m.session(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
res := db.Exec(`
|
|
UPDATE t_users u
|
|
INNER JOIN t_user_emails e ON e.user_id = u.id
|
|
SET u.avatar = '', u.updated_at = ?
|
|
WHERE e.email = ?`, time.Now(), email)
|
|
if res.Error != nil {
|
|
return mapDBErr(res.Error)
|
|
}
|
|
if res.RowsAffected == 0 {
|
|
return errs.ErrNotFound
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type SameIPRankRow struct {
|
|
IP string
|
|
UserCount int64
|
|
DeviceCount int64
|
|
}
|
|
|
|
func (m *Repo) SameIPRank(ctx context.Context, limit int) ([]SameIPRankRow, error) {
|
|
db, err := m.session(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var rows []struct {
|
|
IP string `gorm:"column:ip"`
|
|
UserCount int64 `gorm:"column:user_count"`
|
|
DeviceCount int64 `gorm:"column:device_count"`
|
|
}
|
|
err = db.Raw(`
|
|
SELECT dev.last_client_ip AS ip, COUNT(DISTINCT d.user_id) AS user_count, COUNT(*) AS device_count
|
|
FROM t_user_devices d
|
|
INNER JOIN t_devices dev ON dev.device_id = d.device_id
|
|
WHERE dev.last_client_ip IS NOT NULL AND dev.last_client_ip <> '' AND dev.last_client_ip NOT LIKE '127.%' AND dev.last_client_ip <> '::1'
|
|
GROUP BY dev.last_client_ip
|
|
ORDER BY user_count DESC
|
|
LIMIT ?`, limit).Scan(&rows).Error
|
|
if err != nil {
|
|
return nil, mapDBErr(err)
|
|
}
|
|
out := make([]SameIPRankRow, len(rows))
|
|
for i, r := range rows {
|
|
out[i] = SameIPRankRow{IP: r.IP, UserCount: r.UserCount, DeviceCount: r.DeviceCount}
|
|
}
|
|
return out, nil
|
|
}
|
|
|
|
func (m *Repo) LookupUserIDByEmail(ctx context.Context, email string) (int64, error) {
|
|
db, err := m.session(ctx)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
var id int64
|
|
err = db.Table("t_user_emails").Select("user_id").Where("email = ?", email).Scan(&id).Error
|
|
return id, mapDBErr(err)
|
|
}
|
|
|
|
type userScanRow struct {
|
|
ID int64 `gorm:"column:id"`
|
|
SparkID string `gorm:"column:spark_id"`
|
|
Nickname string `gorm:"column:nickname"`
|
|
Avatar string `gorm:"column:avatar"`
|
|
Status int `gorm:"column:status"`
|
|
LastActiveAt *time.Time `gorm:"column:last_active_at"`
|
|
CreatedAt time.Time `gorm:"column:created_at"`
|
|
Email string `gorm:"column:email"`
|
|
DeviceID uint64 `gorm:"column:device_id"`
|
|
Platform string `gorm:"column:platform"`
|
|
}
|
|
|
|
func userScanToRows(rows []userScanRow) []UserRow {
|
|
out := make([]UserRow, 0, len(rows))
|
|
for _, r := range rows {
|
|
out = append(out, userScanToRow(r))
|
|
}
|
|
return out
|
|
}
|
|
|
|
func userScanToRow(r userScanRow) UserRow {
|
|
return UserRow{
|
|
ID: r.ID, SparkID: r.SparkID, Nickname: r.Nickname, Avatar: r.Avatar,
|
|
Status: r.Status, LastActiveAt: r.LastActiveAt, CreatedAt: r.CreatedAt,
|
|
Email: r.Email, DeviceID: r.DeviceID, Platform: r.Platform,
|
|
}
|
|
}
|