Support ID-based trust center URLs with slug fallback

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
This commit is contained in:
Bryan Frimin
2025-10-13 23:23:08 +02:00
parent a848f81a5c
commit c4c4fda49f
4 changed files with 84 additions and 32 deletions

View File

@@ -157,10 +157,10 @@ export default function TrustCenterPage({ queryRef }: Props) {
}); });
}; };
const trustCenterUrl = organization.trustCenter?.slug const trustCenterUrl = organization.trustCenter?.id
? organization.customDomain?.domain ? organization.customDomain?.domain
? `https://${organization.customDomain.domain}` ? `https://${organization.customDomain.domain}`
: `${window.location.origin}/trust/${organization.trustCenter.slug}` : `${window.location.origin}/trust/${organization.trustCenter.id}`
: null; : null;

View File

@@ -6,8 +6,8 @@ export function getLogoUrl(logoPath: string): string {
return `/logos/${logoPath}`; return `/logos/${logoPath}`;
} }
const slug = trustMatch[1]; const slugOrId = trustMatch[1];
return `/trust/${slug}/logos/${logoPath}`; return `/trust/${slugOrId}/logos/${logoPath}`;
} }
export function getTrustCenterUrl(path: string): string { export function getTrustCenterUrl(path: string): string {

View File

@@ -382,3 +382,25 @@ func (s *Service) LoadTrustCenterBySlug(ctx context.Context, slug string) (*Trus
return &info, err return &info, err
} }
func (s *Service) LoadTrustCenterByID(ctx context.Context, id gid.GID) (*TrustCenterInfo, error) {
var info TrustCenterInfo
err := s.pg.WithConn(
ctx,
func(conn pg.Conn) error {
scope := coredata.NewScope(id.TenantID())
var trustCenter coredata.TrustCenter
if err := trustCenter.LoadByID(ctx, conn, scope, id); err != nil {
return fmt.Errorf("cannot load trust center: %w", err)
}
info.ID = trustCenter.ID
info.OrganizationID = trustCenter.OrganizationID
return nil
},
)
return &info, err
}

View File

@@ -22,6 +22,7 @@ import (
"github.com/getprobo/probo/pkg/agents" "github.com/getprobo/probo/pkg/agents"
"github.com/getprobo/probo/pkg/connector" "github.com/getprobo/probo/pkg/connector"
"github.com/getprobo/probo/pkg/gid"
"github.com/getprobo/probo/pkg/probo" "github.com/getprobo/probo/pkg/probo"
"github.com/getprobo/probo/pkg/saferedirect" "github.com/getprobo/probo/pkg/saferedirect"
"github.com/getprobo/probo/pkg/server/api" "github.com/getprobo/probo/pkg/server/api"
@@ -117,10 +118,10 @@ func (s *Server) setupRoutes() {
// API routes // API routes
s.router.Mount("/api", s.apiServer) s.router.Mount("/api", s.apiServer)
// Trust center routes by slug // Trust center routes by slug or ID
s.router.Route("/trust/{slug}", func(r chi.Router) { s.router.Route("/trust/{slugOrId}", func(r chi.Router) {
r.Use(s.loadTrustCenterBySlug) r.Use(s.loadTrustCenterBySlugOrID)
r.Use(s.stripTrustSlugPrefix) r.Use(s.stripTrustPrefix)
r.Mount("/", s.trustCenterRouter()) r.Mount("/", s.trustCenterRouter())
}) })
@@ -141,32 +142,61 @@ func (s *Server) setExtraHeaders(w http.ResponseWriter) {
} }
} }
// loadTrustCenterBySlug middleware loads trust center info from slug and adds to context // loadTrustCenterBySlugOrID middleware loads trust center info from slug or ID and adds to context
func (s *Server) loadTrustCenterBySlug(next http.Handler) http.Handler { func (s *Server) loadTrustCenterBySlugOrID(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
slug := chi.URLParam(r, "slug") slugOrId := chi.URLParam(r, "slugOrId")
s.logger.InfoCtx(ctx, "loading trust center by slug", // Try to parse as GID first
log.String("slug", slug), var trustCenter *probo.TrustCenterInfo
var err error
if id, parseErr := gid.ParseGID(slugOrId); parseErr == nil {
// It's a valid ID, load by ID
s.logger.InfoCtx(ctx, "loading trust center by ID",
log.String("id", id.String()),
log.String("path", r.URL.Path), log.String("path", r.URL.Path),
) )
trustCenter, err := s.proboService.LoadTrustCenterBySlug(ctx, slug) trustCenter, err = s.proboService.LoadTrustCenterByID(ctx, id)
if err != nil { if err != nil {
s.logger.WarnCtx(ctx, "trust center not found", s.logger.WarnCtx(ctx, "trust center not found",
log.String("slug", slug), log.String("id", id.String()),
log.Error(err), log.Error(err),
) )
http.Error(w, "Trust center not found", http.StatusNotFound) http.Error(w, "Trust center not found", http.StatusNotFound)
return return
} }
s.logger.InfoCtx(ctx, "trust center loaded", s.logger.InfoCtx(ctx, "trust center loaded by ID",
log.String("slug", slug), log.String("id", id.String()),
log.String("trust_center_id", trustCenter.ID.String()), log.String("trust_center_id", trustCenter.ID.String()),
log.String("organization_id", trustCenter.OrganizationID.String()), log.String("organization_id", trustCenter.OrganizationID.String()),
) )
} else {
// Not a valid ID, treat as slug
s.logger.InfoCtx(ctx, "loading trust center by slug",
log.String("slug", slugOrId),
log.String("path", r.URL.Path),
)
trustCenter, err = s.proboService.LoadTrustCenterBySlug(ctx, slugOrId)
if err != nil {
s.logger.WarnCtx(ctx, "trust center not found",
log.String("slug", slugOrId),
log.Error(err),
)
http.Error(w, "Trust center not found", http.StatusNotFound)
return
}
s.logger.InfoCtx(ctx, "trust center loaded by slug",
log.String("slug", slugOrId),
log.String("trust_center_id", trustCenter.ID.String()),
log.String("organization_id", trustCenter.OrganizationID.String()),
)
}
ctx = s.addTrustCenterToContext(ctx, trustCenter.ID.TenantID(), trustCenter.OrganizationID) ctx = s.addTrustCenterToContext(ctx, trustCenter.ID.TenantID(), trustCenter.OrganizationID)
next.ServeHTTP(w, r.WithContext(ctx)) next.ServeHTTP(w, r.WithContext(ctx))
@@ -217,11 +247,11 @@ func (s *Server) addTrustCenterToContext(ctx context.Context, tenantID, organiza
return ctx return ctx
} }
// stripTrustSlugPrefix middleware strips /trust/{slug} from the path // stripTrustPrefix middleware strips /trust/{slugOrId} from the path
func (s *Server) stripTrustSlugPrefix(next http.Handler) http.Handler { func (s *Server) stripTrustPrefix(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
slug := chi.URLParam(r, "slug") slugOrId := chi.URLParam(r, "slugOrId")
prefix := "/trust/" + slug prefix := "/trust/" + slugOrId
// Strip the prefix from the path // Strip the prefix from the path
if r.URL.Path == prefix { if r.URL.Path == prefix {