core/blocks/context.go
Alex Dunmow 99fc63ddfd feat: WO-PS-002–008 SDK type packages
- rbac/: Role type, constants, HasPermission, RoleFromString
- blocks/: BlockFunc, BlockMeta, BlockContext, context accessors, BlockRegistry interface
- templates/: TemplateFunc, meta types, TemplateRegistry interface
- auth/: Claims, PublicClaims, context extractors
- content/: Content interface, AuthorProfile/PageInfo/PostInfo types
- settings/: Settings interface, map accessor helpers
- gating/: AccessRule, AccessResult, EvaluateAccess, Gating interface
- crypto/: Crypto interface (Encrypt/Decrypt)
- render/: BlockNoteToHTML standalone renderer
- video/: ParseEmbedURL, EmbedIframeURL
- ai/: ToolDefinition, ToolResult, ToolRegistry interface

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-30 22:32:29 +08:00

334 lines
9.9 KiB
Go

package blocks
import (
"context"
"net/http"
"time"
"github.com/google/uuid"
)
type templateKeyContextKey struct{}
func WithTemplateKey(ctx context.Context, templateKey string) context.Context {
return context.WithValue(ctx, templateKeyContextKey{}, templateKey)
}
func GetTemplateKey(ctx context.Context) string {
if v, ok := ctx.Value(templateKeyContextKey{}).(string); ok {
return v
}
return ""
}
type queriesContextKey struct{}
func WithQueries(ctx context.Context, queries any) context.Context {
return context.WithValue(ctx, queriesContextKey{}, queries)
}
func GetQueries(ctx context.Context) any {
return ctx.Value(queriesContextKey{})
}
type currentPageContextKey struct{}
func WithCurrentPage(ctx context.Context, page any) context.Context {
return context.WithValue(ctx, currentPageContextKey{}, page)
}
func GetCurrentPage(ctx context.Context) any {
return ctx.Value(currentPageContextKey{})
}
type currentBlogPostContextKey struct{}
func WithCurrentBlogPost(ctx context.Context, post any) context.Context {
return context.WithValue(ctx, currentBlogPostContextKey{}, post)
}
func GetCurrentBlogPost(ctx context.Context) any {
return ctx.Value(currentBlogPostContextKey{})
}
type currentAuthorContextKey struct{}
func WithCurrentAuthor(ctx context.Context, author any) context.Context {
return context.WithValue(ctx, currentAuthorContextKey{}, author)
}
func GetCurrentAuthor(ctx context.Context) any {
return ctx.Value(currentAuthorContextKey{})
}
type currentCategoryContextKey struct{}
func WithCurrentCategory(ctx context.Context, category any) context.Context {
return context.WithValue(ctx, currentCategoryContextKey{}, category)
}
func GetCurrentCategory(ctx context.Context) any {
return ctx.Value(currentCategoryContextKey{})
}
type requestedPathContextKey struct{}
func WithRequestedPath(ctx context.Context, path string) context.Context {
return context.WithValue(ctx, requestedPathContextKey{}, path)
}
func GetRequestedPath(ctx context.Context) string {
if v, ok := ctx.Value(requestedPathContextKey{}).(string); ok {
return v
}
return ""
}
type injectedSlotsContextKey struct{}
func WithInjectedSlots(ctx context.Context, slots map[string]string) context.Context {
return context.WithValue(ctx, injectedSlotsContextKey{}, slots)
}
func GetInjectedSlotContent(ctx context.Context, slotName string) string {
if slots, ok := ctx.Value(injectedSlotsContextKey{}).(map[string]string); ok {
return slots[slotName]
}
return ""
}
func GetInjectedSlots(ctx context.Context) map[string]string {
if slots, ok := ctx.Value(injectedSlotsContextKey{}).(map[string]string); ok {
return slots
}
return nil
}
type masterPageContextKey struct{}
func WithMasterPage(ctx context.Context, masterPage any) context.Context {
return context.WithValue(ctx, masterPageContextKey{}, masterPage)
}
func GetMasterPage(ctx context.Context) any {
return ctx.Value(masterPageContextKey{})
}
func IsMasterPageContext(ctx context.Context) bool {
return ctx.Value(masterPageContextKey{}) != nil
}
type requestContextKey struct{}
func WithRequest(ctx context.Context, r *http.Request) context.Context {
return context.WithValue(ctx, requestContextKey{}, r)
}
func GetRequest(ctx context.Context) *http.Request {
if r, ok := ctx.Value(requestContextKey{}).(*http.Request); ok {
return r
}
return nil
}
type isEditorContextKey struct{}
func WithIsEditor(ctx context.Context, isEditor bool) context.Context {
return context.WithValue(ctx, isEditorContextKey{}, isEditor)
}
func IsEditor(ctx context.Context) bool {
if v, ok := ctx.Value(isEditorContextKey{}).(bool); ok {
return v
}
return false
}
type expectedSlotsContextKey struct{}
func WithExpectedSlots(ctx context.Context, slots []string) context.Context {
return context.WithValue(ctx, expectedSlotsContextKey{}, slots)
}
func GetExpectedSlots(ctx context.Context) []string {
if v, ok := ctx.Value(expectedSlotsContextKey{}).([]string); ok {
return v
}
return nil
}
type blockIDContextKey struct{}
func WithBlockID(ctx context.Context, id uuid.UUID) context.Context {
return context.WithValue(ctx, blockIDContextKey{}, id)
}
func GetBlockID(ctx context.Context) uuid.UUID {
if v, ok := ctx.Value(blockIDContextKey{}).(uuid.UUID); ok {
return v
}
return uuid.Nil
}
type currentPageIDContextKey struct{}
func WithCurrentPageID(ctx context.Context, id uuid.UUID) context.Context {
return context.WithValue(ctx, currentPageIDContextKey{}, id)
}
func GetCurrentPageID(ctx context.Context) uuid.UUID {
if v, ok := ctx.Value(currentPageIDContextKey{}).(uuid.UUID); ok {
return v
}
return uuid.Nil
}
type slotRendererContextKey struct{}
func WithSlotRenderer(ctx context.Context, r SlotRenderer) context.Context {
return context.WithValue(ctx, slotRendererContextKey{}, r)
}
func GetSlotRenderer(ctx context.Context) SlotRenderer {
if r, ok := ctx.Value(slotRendererContextKey{}).(SlotRenderer); ok {
return r
}
return nil
}
type humanProofBannerContextKey struct{}
func WithHumanProofBanner(ctx context.Context, data *HumanProofBannerData) context.Context {
return context.WithValue(ctx, humanProofBannerContextKey{}, data)
}
func GetHumanProofBanner(ctx context.Context) *HumanProofBannerData {
if v, ok := ctx.Value(humanProofBannerContextKey{}).(*HumanProofBannerData); ok {
return v
}
return nil
}
type embedResolverContextKey struct{}
func WithEmbedResolver(ctx context.Context, resolver any) context.Context {
return context.WithValue(ctx, embedResolverContextKey{}, resolver)
}
func GetEmbedResolver(ctx context.Context) any {
return ctx.Value(embedResolverContextKey{})
}
// RenderSlot renders children for the current container block.
func RenderSlot(ctx context.Context) string {
blockID := GetBlockID(ctx)
if blockID == uuid.Nil {
return ""
}
renderer := GetSlotRenderer(ctx)
if renderer == nil {
return ""
}
return renderer.RenderContainerSlot(ctx, blockID)
}
// BlockContext provides contextual information available to all block templates.
type BlockContext struct {
URL string `pongo2:"url"`
Path string `pongo2:"path"`
Slug string `pongo2:"slug"`
PageID string `pongo2:"pageId"`
PageTitle string `pongo2:"pageTitle"`
TemplateKey string `pongo2:"templateKey"`
IsEditor bool `pongo2:"isEditor"`
Timestamp int64 `pongo2:"timestamp"`
IsLoggedIn bool `pongo2:"isLoggedIn"`
UserID string `pongo2:"userId"`
UserEmail string `pongo2:"userEmail"`
UserRole string `pongo2:"userRole"`
Method string `pongo2:"method"`
Host string `pongo2:"host"`
Query map[string]string `pongo2:"query"`
Referrer string `pongo2:"referrer"`
UserAgent string `pongo2:"userAgent"`
IP string `pongo2:"ip"`
Cookies map[string]string `pongo2:"cookies"`
Headers map[string]string `pongo2:"headers"`
Country string `pongo2:"country"`
City string `pongo2:"city"`
Timezone string `pongo2:"timezone"`
Now time.Time `pongo2:"now"`
CurrentAuthor map[string]any `pongo2:"currentAuthor"`
CurrentPost map[string]any `pongo2:"currentPost"`
CurrentCategory map[string]any `pongo2:"currentCategory"`
Site map[string]any `pongo2:"site"`
IsPublicLoggedIn bool `pongo2:"isPublicLoggedIn"`
PublicUserID string `pongo2:"publicUserId"`
PublicUsername string `pongo2:"publicUsername"`
PublicDisplayName string `pongo2:"publicDisplayName"`
PublicEmailVerified bool `pongo2:"publicEmailVerified"`
DetailRowID string `pongo2:"detailRowId"`
DetailTableID string `pongo2:"detailTableId"`
DetailRowData map[string]any `pongo2:"detailRowData"`
BlogIndexURL string `pongo2:"blogIndexUrl"`
CategoryPageURL string `pongo2:"categoryPageUrl"`
}
type blockContextKey struct{}
func WithBlockContext(ctx context.Context, blockCtx *BlockContext) context.Context {
return context.WithValue(ctx, blockContextKey{}, blockCtx)
}
func GetBlockContext(ctx context.Context) *BlockContext {
if bc, ok := ctx.Value(blockContextKey{}).(*BlockContext); ok {
return bc
}
return nil
}
// ToMap converts the BlockContext to a map for pongo2 template injection.
func (bc *BlockContext) ToMap() map[string]any {
return map[string]any{
"url": bc.URL, "path": bc.Path, "slug": bc.Slug,
"pageId": bc.PageID, "pageTitle": bc.PageTitle,
"templateKey": bc.TemplateKey, "isEditor": bc.IsEditor,
"timestamp": bc.Timestamp, "now": bc.Now,
"isLoggedIn": bc.IsLoggedIn, "userId": bc.UserID,
"userEmail": bc.UserEmail, "userRole": bc.UserRole,
"method": bc.Method, "host": bc.Host, "query": bc.Query,
"referrer": bc.Referrer, "userAgent": bc.UserAgent,
"ip": bc.IP, "cookies": bc.Cookies, "headers": bc.Headers,
"country": bc.Country, "city": bc.City, "timezone": bc.Timezone,
"currentAuthor": bc.CurrentAuthor, "currentPost": bc.CurrentPost,
"currentCategory": bc.CurrentCategory, "site": bc.Site,
"isPublicLoggedIn": bc.IsPublicLoggedIn,
"publicUserId": bc.PublicUserID, "publicUsername": bc.PublicUsername,
"publicDisplayName": bc.PublicDisplayName,
"publicEmailVerified": bc.PublicEmailVerified,
"detailRowId": bc.DetailRowID, "detailTableId": bc.DetailTableID,
"detailRowData": bc.DetailRowData,
"blogIndexUrl": bc.BlogIndexURL, "categoryPageUrl": bc.CategoryPageURL,
}
}
// DetailRowInfo holds the resolved data table row for detail pages.
type DetailRowInfo struct {
TableID string
RowID string
Data map[string]any
}
type detailRowKey struct{}
func WithDetailRow(ctx context.Context, tableID, rowID string, data map[string]any) context.Context {
return context.WithValue(ctx, detailRowKey{}, &DetailRowInfo{TableID: tableID, RowID: rowID, Data: data})
}
func GetDetailRow(ctx context.Context) *DetailRowInfo {
if v, ok := ctx.Value(detailRowKey{}).(*DetailRowInfo); ok {
return v
}
return nil
}