package repository import ( "context" "errors" "github.com/google/uuid" "github.com/jackc/pgx/v5" "github.com/travelswitch/travelhub/backend/internal/models" ) // TenantBySlug resolves the tenant a caller is signing in to. Suspended // tenants are treated as absent so their users cannot authenticate. func (r *Repository) TenantBySlug(ctx context.Context, slug string) (models.Tenant, error) { const q = ` SELECT id, slug, name, status, created_at FROM tenants WHERE slug = $1 AND status = 'active'` var t models.Tenant err := r.pool.QueryRow(ctx, q, slug). Scan(&t.ID, &t.Slug, &t.Name, &t.Status, &t.CreatedAt) if errors.Is(err, pgx.ErrNoRows) { return models.Tenant{}, ErrNotFound } return t, err } // ListTenants powers the tenant picker on the sign-in screen. It is the only // unauthenticated read in the service and deliberately exposes nothing beyond // the slug and display name. func (r *Repository) ListTenants(ctx context.Context) ([]models.Tenant, error) { const q = ` SELECT id, slug, name, status, created_at FROM tenants WHERE status = 'active' ORDER BY name` rows, err := r.pool.Query(ctx, q) if err != nil { return nil, err } defer rows.Close() tenants := []models.Tenant{} for rows.Next() { var t models.Tenant if err := rows.Scan(&t.ID, &t.Slug, &t.Name, &t.Status, &t.CreatedAt); err != nil { return nil, err } tenants = append(tenants, t) } return tenants, rows.Err() } // UserByEmail looks up a login within one tenant. The tenant filter is what // stops credentials from one agency authenticating against another. func (r *Repository) UserByEmail(ctx context.Context, tenantID uuid.UUID, email string) (models.User, error) { const q = ` SELECT id, tenant_id, email, password_hash, full_name, role, created_at FROM users WHERE tenant_id = $1 AND lower(email) = lower($2)` var u models.User err := r.pool.QueryRow(ctx, q, tenantID, email).Scan( &u.ID, &u.TenantID, &u.Email, &u.PasswordHash, &u.FullName, &u.Role, &u.CreatedAt, ) if errors.Is(err, pgx.ErrNoRows) { return models.User{}, ErrNotFound } return u, err }