Skip to content

refactor api #32

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 24 additions & 17 deletions projects/gnoland/gno.land/p/eve000/event/agenda/agenda.gno
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,25 @@ import (
)

type Agenda struct {
Name string
Location *location.Location
StartDate time.Time
EndDate time.Time
Banner *component.Content
Description string
Sessions []*session.Session
renderOpts *component.RenderOpts
Name string
Location *location.Location
StartDate time.Time
EndDate time.Time
Banner *component.Content
Description string
Sessions []*session.Session
renderOpts *component.RenderOpts
}

var _ component.Component = (*Agenda)(nil)

func FormatDate(date time.Time) string {
if date.IsZero() {
return ""
}
return date.Format(component.DtFmt)
}

func (a *Agenda) SetBanner(heading *component.Content) {
a.Banner = heading
}
Expand All @@ -37,10 +44,10 @@ func (a *Agenda) ToMarkdown() string {
if a.RenderOpts().Location {
markdown += "### " + a.Location.Name + "\n\n"
}
if a.StartDate.Format(component.DtFmt) == a.EndDate.Format(component.DtFmt) {
markdown += a.StartDate.Format(component.DtFmt) + "\n\n"
if FormatDate(a.StartDate) == FormatDate(a.EndDate) {
markdown += FormatDate(a.StartDate) + "\n\n"
} else {
markdown += a.StartDate.Format(component.DtFmt) + " - " + a.EndDate.Format(component.DtFmt) + "\n\n"
markdown += FormatDate(a.StartDate) + " - " + FormatDate(a.EndDate) + "\n\n"
}
markdown += a.Description + "\n\n"

Expand All @@ -53,7 +60,7 @@ func (a *Agenda) ToMarkdown() string {
// Group sessions by date
sessionsByDate := make(map[string][]*session.Session)
for _, session := range a.Sessions {
date := session.StartTime.Format(component.DtFmt)
date := FormatDate(session.StartTime)
sessionsByDate[date] = append(sessionsByDate[date], session)
}

Expand Down Expand Up @@ -100,8 +107,8 @@ func (a *Agenda) ToJson() string {
json := "{\n"
json += "\"Name\":\"" + a.Name + "\",\n"
json += "\"Location\":" + a.Location.ToJson() + ",\n"
json += "\"StartDate\":\"" + a.StartDate.Format(time.RFC3339) + "\",\n"
json += "\"EndDate\":\"" + a.EndDate.Format(time.RFC3339) + "\",\n"
json += "\"StartDate\":\"" + FormatDate(a.StartDate) + "\",\n"
json += "\"EndDate\":\"" + FormatDate(a.EndDate) + "\",\n"
json += "\"Description\":\"" + a.Description + "\",\n"
json += "\"Sessions\":[\n"
for i, session := range a.Sessions {
Expand All @@ -127,10 +134,10 @@ func (a *Agenda) ToSVGFragment(y *int) string {
*y += 10
svg += component.RenderSVGLine(y, "subtitle", "", a.Location.Name)
*y += 10
if a.StartDate.Format(component.DtFmt) == a.EndDate.Format(component.DtFmt) {
svg += component.RenderSVGLine(y, "text", "", a.StartDate.Format(component.DtFmt))
if a.StartDate == a.EndDate {
svg += component.RenderSVGLine(y, "text", "", FormatDate(a.StartDate))
} else {
svg += component.RenderSVGLine(y, "text", "", a.StartDate.Format(component.DtFmt)+" - "+a.EndDate.Format(component.DtFmt))
svg += component.RenderSVGLine(y, "text", "", FormatDate(a.StartDate) + " - " + FormatDate(a.EndDate))
}
*y += 20
svg += component.RenderSVGLine(y, "text", "", a.Description)
Expand Down
12 changes: 7 additions & 5 deletions projects/gnoland/gno.land/p/eve000/event/component/component.gno
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,21 @@ import (
"strings"
"time"

"gno.land/p/moul/txlink"
"gno.land/p/demo/ufmt"
)

const DtFmt = "Mon Jan 2"

type Component interface {
ToAnchor() string
ToMarkdown() string // REVIEW: should we allow filtering?
ToMarkdown() string
ToJson() string
ToSVG() string
ToSvgDataUrl() string
RenderOpts() *RenderOpts
RenderOpts() *RenderOpts // REVIEW: should we remove renderOpts? we could add OnlineEvent vs InPersonEvent (see schema.org)
}

// RenderOpts is a "feature flag" struct for controlling the rendering of components.
// It allows for selective rendering of different parts of a component.
// REVIEW: consider using a new set of render opts per event rather than 1-per-registry as it is now
type RenderOpts struct {
Svg bool
Schedule bool
Expand Down Expand Up @@ -217,6 +215,10 @@ func escapeHtml(s string) string {
return s
}

func TxlinkButton(label, method string) string {
return Button(label, txlink.NewLink(method).URL())
}

func Button(label, path string) string {
return SubmitButton(label, path, 16, 120) // Default font size and min width
}
Expand Down
34 changes: 34 additions & 0 deletions projects/gnoland/gno.land/p/eve000/event/event.gno
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package event

import (
"std"
"strconv"
"time"

Expand All @@ -13,6 +14,39 @@ import (
"gno.land/p/eve000/event/speaker"
)

type Api interface {
AddOrganizer(addr std.Address)
AddProposer(addr, sender std.Address)
AddReviewer(addr, sender std.Address)
AddSpeaker(addr std.Address)
AdminRemoveRole(role string, addr std.Address)
AdminSetRole(role string, addr std.Address)
AssertAtLeastRole(role string, sender std.Address)
Destroy(markdown string)
HasRole(role string, addr std.Address) bool
JoinAsAttendee()
JoinWaitlist()
ListRoles() []string
Publish(markdown string)
RegisterEvent(evt *Event, opts *component.RenderOpts) string
RemoveOrganizer(addr std.Address)
RemoveProposer(addr, sender std.Address)
RemoveReviewer(addr, sender std.Address)
RemoveSelfAsAttendee()
RemoveSelfFromWaitlist()
RemoveSpeaker(addr std.Address)
Render(path string) string
RenderAcl(path string) string
RenderList(role string) string
ResetRoles()
RoleExists(role string) bool
SetContent(key, markdown string)
SetPatchLevel(level int)
SetRoleHandler(role string, fn func(string) bool)
Unpublish(key string)
UnsetRoleHandler(role string)
}

var f = ufmt.Sprintf

type Storage struct {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@ func (l *Location) SetDescription(description string) {
l.Description = description
}

// REVIEW: need setters for tags and renderOpts?

func (l *Location) ToAnchor() string {
return component.StringToAnchor(l.Name)
}
Expand Down
31 changes: 29 additions & 2 deletions projects/gnoland/gno.land/p/eve000/event/register/register.gno
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package register

import (
"std"
"strconv"
"strings"

"gno.land/p/demo/avl"
"gno.land/p/demo/ufmt"
Expand All @@ -12,7 +14,32 @@ import (
type Registry struct {
Events *avl.Tree
LiveEventId string
renderOpts *component.RenderOpts
RenderOpts *component.RenderOpts
patchLevel int // current patch level, used for debugging and content management
patchRealm string // realm that is allowed to update the patch level, used for debugging and content management
}

func NewRegistry(renderOpts *component.RenderOpts) *Registry {
return &Registry{
Events: avl.NewTree(),
LiveEventId: "",
RenderOpts: renderOpts,
patchLevel: 0,
patchRealm: "",
}
}

func (r *Registry) GetPatchLevel() string {
realmLink := strings.TrimPrefix(r.patchRealm, "gno.land")
return ufmt.Sprintf("[rev %d](%s)", r.patchLevel, realmLink)
}

func (r *Registry) SetPatchLevel(level int) {
if r.patchLevel+1 != level {
panic("patch level must be incremented by 1, current: " + strconv.Itoa(r.patchLevel) + ", new: " + strconv.Itoa(level))
}
r.patchRealm = std.CurrentRealm().PkgPath()
r.patchLevel = level
}

func (r *Registry) GetEvent(id string) *event.Event {
Expand All @@ -24,7 +51,7 @@ func (r *Registry) GetEvent(id string) *event.Event {
}

func (r *Registry) SetRenderOpts(opts *component.RenderOpts) {
r.renderOpts = opts
r.RenderOpts = opts
}

func (r *Registry) String() string {
Expand Down
68 changes: 68 additions & 0 deletions projects/gnoland/gno.land/r/buidlthefuture000/api.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package events

import (
"std"
"strings"

"gno.land/p/demo/avl"
)

var (
api = &App{}
registry = avl.NewTree()
displayPaths []string
realmAllowPrefix []string
)

func init() {
realmAllowPrefix = append(realmAllowPrefix, std.CurrentRealm().PkgPath()+"/") // must be in realm sub-path
}

func hasAllowedPrefix() bool {
prevRealm := std.PreviousRealm().PkgPath()
for _, callerPath := range realmAllowPrefix {
if strings.HasPrefix(prevRealm, callerPath) {
return true
}
}
return prevRealm == ""
}

func assertAccess() {
if !hasAllowedPrefix() {
panic("access denied: " + std.PreviousRealm().PkgPath() +
" realm must match an allowed prefix:[" + strings.Join(realmAllowPrefix, ",") + "]")
}
}

func Render(path string) string {
return api.Render(path)
}

// Register registers a ContentBlock function - use this to override the default rendering
func Register(key string, block func(path string) string) {
api.Register(key, block)
}

type App struct{}

func (*App) Register(key string, block func(path string) string) {
assertAccess()
if _, ok := registry.Get(key); ok {
// TODO emit update event
}
registry.Set(key, block)
}

func (*App) Render(path string) string {
sb := strings.Builder{}
for _, key := range displayPaths {
if block, ok := registry.Get(key); ok {
sb.WriteString("### " + key + "\n")
sb.WriteString(block.(func(path string) string)(path))
// TODO: also render TermSet
sb.WriteString("\n")
}
}
return sb.String()
}
31 changes: 31 additions & 0 deletions projects/gnoland/gno.land/r/buidlthefuture000/events/acl.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package events

import(
"std"
"strings"
)

var (
realmAllowPrefix []string
)

func init() {
realmAllowPrefix = append(realmAllowPrefix, std.CurrentRealm().PkgPath()+"/") // must be in realm sub-path
}

func hasAllowedPrefix() bool {
prevRealm := std.PreviousRealm().PkgPath()
for _, callerPath := range realmAllowPrefix {
if strings.HasPrefix(prevRealm, callerPath) {
return true
}
}
return prevRealm == ""
}

func assertAccess() {
if !hasAllowedPrefix() {
panic("access denied: " + std.PreviousRealm().PkgPath() +
" realm must match an allowed prefix:[" + strings.Join(realmAllowPrefix, ",") + "]")
}
}
Loading