Search Apps Documentation Source Content File Folder Download Copy Actions Download State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

feedback_actions.gno

5.23 Kb · 111 lines
  1package memba_weighted_host
  2
  3import (
  4	"chain"
  5	"strconv"
  6	"strings"
  7	"gno.land/p/samcrew/memba_weighted_policy"
  8)
  9
 10const FeedbackPath = "gno.land/r/samcrew/memba_feedback_v2"
 11
 12type FeedbackActionKind string
 13
 14const (
 15	FeedbackAcceptOwner FeedbackActionKind = "accept-owner"
 16	FeedbackReturnOwner FeedbackActionKind = "return-owner"
 17	FeedbackAbortReturn FeedbackActionKind = "abort-return"
 18	FeedbackAddMember FeedbackActionKind = "add-member"
 19	FeedbackRemoveMember FeedbackActionKind = "remove-member"
 20	FeedbackSetRoles FeedbackActionKind = "set-roles"
 21	FeedbackCreateText FeedbackActionKind = "create-text-channel"
 22	FeedbackUnpause FeedbackActionKind = "unpause"
 23)
 24
 25type FeedbackPolicy struct{ dao, successor address }
 26
 27func NewFeedbackPolicy(dao, successor address) FeedbackPolicy {
 28	if !dao.IsValid() || dao != chain.PackageAddress("gno.land/r/samcrew/memba_dao") {
 29		panic("feedback policy requires the founding DAO address")
 30	}
 31	if !successor.IsValid() || successor == dao || successor == chain.PackageAddress(FeedbackPath) {
 32		panic("feedback policy requires a valid distinct successor")
 33	}
 34	return FeedbackPolicy{dao: dao, successor: successor}
 35}
 36func (p FeedbackPolicy) DAO() address { return p.dao }
 37func (p FeedbackPolicy) Successor() address { return p.successor }
 38
 39type FeedbackAction struct {
 40	kind FeedbackActionKind
 41	recipient, subject address
 42	roles string
 43	name, description string
 44}
 45func (p FeedbackPolicy) Accept() FeedbackAction { return FeedbackAction{kind: FeedbackAcceptOwner} }
 46func (p FeedbackPolicy) Return() FeedbackAction { return FeedbackAction{kind: FeedbackReturnOwner, recipient: p.successor} }
 47func (p FeedbackPolicy) AbortReturn() FeedbackAction { return FeedbackAction{kind: FeedbackAbortReturn, recipient: p.successor} }
 48func (p FeedbackPolicy) AddMember(who address, roles string) FeedbackAction { a:=FeedbackAction{kind: FeedbackAddMember, subject:who, roles:roles}; a.Bytes(); return a }
 49func (p FeedbackPolicy) RemoveMember(who address) FeedbackAction { a:=FeedbackAction{kind: FeedbackRemoveMember, subject:who}; a.Bytes(); return a }
 50func (p FeedbackPolicy) SetRoles(who address, roles string) FeedbackAction { a:=FeedbackAction{kind: FeedbackSetRoles, subject:who, roles:roles}; a.Bytes(); return a }
 51func (p FeedbackPolicy) CreateText(name, description string) FeedbackAction { a:=FeedbackAction{kind: FeedbackCreateText, name:name, description:description}; a.Bytes(); return a }
 52func FeedbackResume() FeedbackAction { return FeedbackAction{kind: FeedbackUnpause} }
 53func (a FeedbackAction) Kind() FeedbackActionKind { return a.kind }
 54func (a FeedbackAction) Recipient() address { return a.recipient }
 55func (a FeedbackAction) Subject() address { return a.subject }
 56func (a FeedbackAction) Roles() string { return a.roles }
 57func (a FeedbackAction) Name() string { return a.name }
 58func (a FeedbackAction) Description() string { return a.description }
 59
 60func validFeedbackName(name string) bool {
 61	if len(name)<1 || len(name)>50 { return false }
 62	for _,c:=range name { if !((c>='a'&&c<='z')||(c>='0'&&c<='9')||c=='-') { return false } }
 63	return true
 64}
 65func validFeedbackDescription(description string) bool {
 66	if len(description)<1 || len(description)>200 { return false }
 67	for _,c:=range description { if c<32 || c==127 { return false } }
 68	return true
 69}
 70
 71// Only the four target ACL roles are representable; every role list has a
 72// canonical order, so a voted commitment cannot alias another role grant.
 73func canonicalFeedbackRoles(roles string) bool {
 74	if roles == "" { return false }
 75	parts:=strings.Split(roles, ",")
 76	if len(parts)>4 { return false }
 77	previous:=-1
 78	for _,part:=range parts {
 79		index:=-1
 80		switch part { case "admin": index=0; case "dev": index=1; case "ops": index=2; case "member": index=3 }
 81		if index<=previous { return false }
 82		previous=index
 83	}
 84	return true
 85}
 86func (a FeedbackAction) Bytes() string {
 87	base:="feedback/v1|"+FeedbackPath+"|"+string(a.kind)
 88	switch a.kind {
 89	case FeedbackAcceptOwner, FeedbackUnpause:
 90		if a.recipient!="" || a.subject!="" || a.roles!="" || a.name!="" || a.description!="" { panic("malformed feedback action") }
 91		return base
 92	case FeedbackReturnOwner, FeedbackAbortReturn:
 93		if !a.recipient.IsValid() || a.subject!="" || a.roles!="" || a.name!="" || a.description!="" { panic("malformed feedback return action") }
 94		return base+"|"+string(a.recipient)
 95	case FeedbackAddMember, FeedbackSetRoles:
 96		if !a.subject.IsValid() || a.recipient!="" || a.name!="" || a.description!="" || !canonicalFeedbackRoles(a.roles) { panic("invalid feedback member action") }
 97		return base+"|"+string(a.subject)+"|"+strconv.Itoa(len(a.roles))+":"+a.roles
 98	case FeedbackRemoveMember:
 99		if !a.subject.IsValid() || a.recipient!="" || a.roles!="" || a.name!="" || a.description!="" { panic("invalid feedback member action") }
100		return base+"|"+string(a.subject)
101	case FeedbackCreateText:
102		if a.recipient!="" || a.subject!="" || a.roles!="" || !validFeedbackName(a.name) || !validFeedbackDescription(a.description) { panic("invalid feedback text creation") }
103		return base+"|"+a.name+"|"+strconv.Itoa(len(a.description))+":"+a.description
104	default: panic("unsupported feedback action")
105	}
106}
107func (a FeedbackAction) Category() memba_weighted_policy.Category {
108	a.Bytes()
109	if a.kind==FeedbackUnpause { return memba_weighted_policy.Financial }
110	return memba_weighted_policy.Critical
111}