package store import ( "context" "strings" "git.118im.com/im_team/im_workbench/internal/config" "github.com/jmoiron/sqlx" ) // CoreStore provides read-only access to shared IM data. type CoreStore struct { db *sqlx.DB } func coreStoreOwnsDB(primaryDSN, coreDSN string) bool { return strings.TrimSpace(primaryDSN) != strings.TrimSpace(coreDSN) } func openCoreDSN(cfg config.MySQLConfig) (*CoreStore, error) { db, err := openMySQLDB(cfg) if err != nil { return nil, err } return &CoreStore{db: db}, nil } func (s *CoreStore) Close() error { if s == nil || s.db == nil { return nil } return s.db.Close() } func (s *CoreStore) fileUploadMetadata(ctx context.Context, tenantID int64, fileID string) fileUploadMetadata { var meta fileUploadMetadata decodedID, storageName := parseUploadFileID(fileID) locationCandidates := uploadLocationCandidates(fileID, storageName) if decodedID <= 0 && len(locationCandidates) == 0 { return meta } if decodedID > 0 { err := s.db.GetContext(ctx, &meta, `SELECT IFNULL(mimetype,'') AS mimetype,IFNULL(size,0) AS size,IFNULL(etag,'') AS etag,IFNULL(location,'') AS location,IFNULL(original_name,'') AS original_name FROM im_fileuploads WHERE tenant_id=? AND id=? LIMIT 1`, tenantID, decodedID) if err == nil { return meta } } for _, candidate := range locationCandidates { err := s.db.GetContext(ctx, &meta, `SELECT IFNULL(mimetype,'') AS mimetype,IFNULL(size,0) AS size,IFNULL(etag,'') AS etag,IFNULL(location,'') AS location,IFNULL(original_name,'') AS original_name FROM im_fileuploads WHERE tenant_id=? AND (location=? OR location LIKE ?) ORDER BY createdat DESC LIMIT 1`, tenantID, candidate, "%/"+candidate) if err == nil { return meta } } return meta } func (s *CoreStore) populateUserSummaries(ctx context.Context, tenantID int64, ids []int64, result map[int64]UserSummary) error { query, args, err := sqlx.In(`SELECT user_id,nickname AS display_name,IFNULL(avatar_file_id,'') AS avatar_file_id FROM im_user_profiles WHERE tenant_id=? AND user_id IN (?) ORDER BY user_id ASC`, tenantID, ids) if err != nil { return err } var profileRows []struct { UserID int64 `db:"user_id"` DisplayName string `db:"display_name"` AvatarFileID string `db:"avatar_file_id"` } if err := s.db.SelectContext(ctx, &profileRows, s.db.Rebind(query), args...); err != nil && !isMissingTable(err) { return err } for _, row := range profileRows { summary := result[row.UserID] if summary.UserID == 0 { summary.UserID = row.UserID } if summary.DisplayName == "" { summary.DisplayName = strings.TrimSpace(row.DisplayName) } if summary.AvatarFileID == "" { summary.AvatarFileID = row.AvatarFileID } result[row.UserID] = summary } query, args, err = sqlx.In(`SELECT id AS user_id, COALESCE( NULLIF(JSON_UNQUOTE(JSON_EXTRACT(public,'$.display_name')),''), NULLIF(JSON_UNQUOTE(JSON_EXTRACT(public,'$.fn')),''), NULLIF(JSON_UNQUOTE(JSON_EXTRACT(public,'$.nickname')),''), NULLIF(JSON_UNQUOTE(JSON_EXTRACT(public,'$.name')),''), '' ) AS display_name FROM im_users WHERE tenant_id=? AND id IN (?)`, tenantID, ids) if err != nil { return err } var userRows []struct { UserID int64 `db:"user_id"` DisplayName string `db:"display_name"` } if err := s.db.SelectContext(ctx, &userRows, s.db.Rebind(query), args...); err != nil && !isMissingTable(err) { return err } for _, row := range userRows { summary := result[row.UserID] if summary.UserID == 0 { summary.UserID = row.UserID } if summary.DisplayName == "" { summary.DisplayName = strings.TrimSpace(row.DisplayName) } result[row.UserID] = summary } return nil }