mirror of
https://shylinux.com/x/community
synced 2025-04-26 01:54:05 +08:00
361 lines
15 KiB
Go
361 lines
15 KiB
Go
package gonganxitong
|
|
|
|
import (
|
|
"shylinux.com/x/ice"
|
|
"shylinux.com/x/icebergs/base/aaa"
|
|
"shylinux.com/x/icebergs/base/ctx"
|
|
"shylinux.com/x/icebergs/base/mdb"
|
|
"shylinux.com/x/icebergs/base/tcp"
|
|
"shylinux.com/x/icebergs/base/web"
|
|
kit "shylinux.com/x/toolkits"
|
|
|
|
"shylinux.com/x/community/src/api"
|
|
"shylinux.com/x/community/src/gonganxitong/model"
|
|
"shylinux.com/x/mysql-story/src/db"
|
|
)
|
|
|
|
type Portal struct {
|
|
ice.Hash
|
|
Table
|
|
user user
|
|
city city
|
|
event event
|
|
message message
|
|
recent recent
|
|
service service
|
|
export string `data:"true"`
|
|
short string `data:"index"`
|
|
field string `data:"time,icons,name,index,order,enable,init,type,role,view,command_uid"`
|
|
create string `name:"create index name icons"`
|
|
list string `name:"list place_uid index uid auto" role:"void"`
|
|
placeCreate string `name:"placeCreate city_name* street_name* place_name* place_type*:select address" icon:"bi bi-plus-square-dotted" role:"void"`
|
|
placeRemove string `name:"placeRemove" role:"void"`
|
|
placeAuth string `name:"placeAuth" role:"void"`
|
|
command string `name:"command" role:"void"`
|
|
run string `name:"run" role:"void"`
|
|
}
|
|
|
|
func (s Portal) Init(m *ice.Message, arg ...string) {
|
|
m.Design(s.List, "", kit.JoinWord(s.Keys(s.Place, model.UID), ctx.INDEX, model.UID, ice.AUTO))
|
|
s.LoadTrans(m, arg...)
|
|
s.Hash.Init(m, arg...)
|
|
}
|
|
func (s Portal) Exit(m *ice.Message, arg ...string) {
|
|
mdb.HashSelectUpdate(m.Message, "", func(value ice.Map) { delete(value, model.COMMAND_UID); delete(value, mdb.TARGET) })
|
|
s.Hash.Exit(m, arg...)
|
|
}
|
|
func (s Portal) BeforeMigrate(m *ice.Message, arg ...string) {
|
|
if m.Cmd(web.CODE_MYSQL_CLIENT).Length() == 0 {
|
|
if s.AutoCmd(m, web.CODE_MYSQL_CLIENT).Table(func(value ice.Maps) { m.Cmd(web.CODE_MYSQL_CLIENT, s.Create, aaa.SESS, "", kit.Simple(value)) }).Length() == 0 {
|
|
m.Cmd(web.CODE_MYSQL_CLIENT, s.Create, aaa.SESS, "mysql", "driver", "mysql", "database", "mysql", tcp.HOST, "localhost", tcp.PORT, "10001", aaa.USERNAME, "root", aaa.PASSWORD, "root")
|
|
}
|
|
}
|
|
}
|
|
func (s Portal) AfterMigrate(m *ice.Message, arg ...string) {
|
|
if name := kit.Select("", kit.Split(m.PrefixKey(), "."), -2); !m.Exists("src/" + name) {
|
|
return
|
|
}
|
|
cmd := m.GetCommand()
|
|
m.Cmdy(s.Prefix(m, s.service), s.Table.Update, ctx.INDEX, m.PrefixKey(), mdb.NAME, cmd.Help+" "+ice.Info.Title(), mdb.ICON, m.Resource(kit.Select(ice.Info.NodeIcon, cmd.Icon)))
|
|
m.Cmd(command{}).Table(func(value ice.Maps) {
|
|
if kit.HasSuffix(value[model.INDEX], ".allow") {
|
|
cmdPortal[kit.ReplaceAll(value[model.INDEX], ".allow", ".portal")] = value[model.PORTAL]
|
|
cmdSpace[kit.ReplaceAll(value[model.INDEX], ".allow", ".portal")] = value[model.SPACE]
|
|
}
|
|
cmdPortal[value[model.INDEX]] = value[model.PORTAL]
|
|
cmdSpace[value[model.INDEX]] = value[model.SPACE]
|
|
})
|
|
}
|
|
func (s Portal) Inputs(m *ice.Message, arg ...string) {
|
|
m.Cmdy(s.Place, m.ActionKey(), arg)
|
|
}
|
|
func (s Portal) Command(m *ice.Message, arg ...string) {
|
|
if cmdPortal[arg[0]] != "" && cmdPortal[arg[0]] != m.PrefixKey() {
|
|
s.AutoCmdy(m, cmdPortal[arg[0]], m.ActionKey(), arg)
|
|
return
|
|
}
|
|
ctx.Command(m.Message, arg...)
|
|
}
|
|
func (s Portal) Run(m *ice.Message, arg ...string) {
|
|
if cmdPortal[arg[0]] != "" && cmdPortal[arg[0]] != m.PrefixKey() {
|
|
s.AutoCmdy(m, cmdPortal[arg[0]], m.ActionKey(), arg)
|
|
return
|
|
}
|
|
s.DisplayBase(m, "common.js")
|
|
m.OptionDefault(model.SERVICE_UID, ServiceUID(m))
|
|
m.OptionDefault(model.COMMAND_UID, s.Hash.List(m.Spawn(), arg[0]).Append(model.COMMAND_UID))
|
|
m.Search(arg[0], func(key string, cmd *ice.Command) {
|
|
sub, role := "", cmd.Role
|
|
if len(arg) > 1 && arg[1] == ctx.ACTION {
|
|
if action, ok := cmd.Actions[arg[2]]; ok {
|
|
sub, role = arg[2], action.Role
|
|
}
|
|
} else if len(arg) > 1 {
|
|
if action, ok := cmd.Actions[arg[1]]; ok {
|
|
sub, role = arg[1], action.Role
|
|
} else {
|
|
m.Option(s.Keys(s.Place, model.UID), arg[1])
|
|
}
|
|
}
|
|
s.UserPlaceRole(m)
|
|
if kit.IsIn(role, "", aaa.VOID, aaa.TECH, aaa.ROOT) {
|
|
kit.If(!ctx.PodCmd(m.Message, arg) && aaa.Right(m.Message, arg), func() { m.Cmdy(arg) })
|
|
} else {
|
|
if !m.Cmdy(arg[0], s.CheckRole, kit.Split(role)).IsErr() {
|
|
m.Cmdy(arg)
|
|
}
|
|
}
|
|
if sub != mdb.INPUTS && kit.IndexOf(arg, mdb.INPUTS) == -1 {
|
|
s.Place.RewriteAppend(m)
|
|
}
|
|
})
|
|
}
|
|
func (s Portal) List(m *ice.Message, arg ...string) {
|
|
if m.Option(mdb.VIEW) == mdb.TABLE {
|
|
s.Hash.List(m, arg...).PushAction(mdb.DETAIL, s.Hash.Remove).SortInt(mdb.ORDER)
|
|
return
|
|
}
|
|
m.OptionDefault(model.SERVICE_UID, ServiceUID(m))
|
|
if len(arg) == 0 {
|
|
USER_PLACE_ROLE := s.Keys(s.UserPlace, model.ROLE)
|
|
m.Cmdy(m.PrefixKey(), s.PlaceList, m.Option(model.USER_UID)).Table(func(value ice.Maps) {
|
|
button := []ice.Any{}
|
|
switch UserPlaceRole(kit.Int(value[USER_PLACE_ROLE])) {
|
|
case UserPlaceCreator, UserPlaceLandlord:
|
|
if value[model.AUTH_STATUS] == "" {
|
|
button = append(button, s.PlaceAuth)
|
|
}
|
|
}
|
|
m.PushButton(append(button, s.PlaceRemove)...)
|
|
}).Action(s.PlaceCreate)
|
|
s.Button(m, "", s.PlaceCreate)
|
|
} else {
|
|
if msg := s.PlaceListOption(m, arg...); arg[0] != "" && msg.Length() > 0 {
|
|
defer s.AddRecent(msg, arg[0])
|
|
}
|
|
s.Hash.List(m).SortInt(mdb.ORDER)
|
|
}
|
|
s.Place.RewriteAppend(m)
|
|
s.DisplayBase(m, "").DisplayCSS("")
|
|
}
|
|
func (s Portal) PlaceListOption(m *ice.Message, arg ...string) *ice.Message {
|
|
msg := m.Cmd(m.PrefixKey(), s.PlaceList, m.Option(model.USER_UID), arg[0])
|
|
if msg.Length() == 0 {
|
|
msg = m.Cmd(s.Place, s.Table.Select, model.UID, arg[0])
|
|
if msg.Length() == 0 {
|
|
return msg
|
|
}
|
|
msg.Push(s.Keys(s.UserPlace, model.ROLE), "0")
|
|
msg.RenameAppend(model.NAME, s.Keys(s.Place, model.NAME), model.TYPE, s.Keys(s.Place, model.TYPE))
|
|
s.SelectJoin(msg, s.Street, model.NAME, model.CITY_UID)
|
|
s.SelectJoinCity(msg)
|
|
s.SelectJoinAuth(msg)
|
|
}
|
|
if kit.Int(msg.Append(s.Keys(s.UserPlace, model.ROLE))) == 0 {
|
|
msg.Append(model.DASHBOARD_UID, "")
|
|
}
|
|
s.Place.RewriteAppend(msg)
|
|
m.Options(msg.AppendSimple(
|
|
s.Keys(s.Place, model.NAME), s.Keys(s.Place, model.TYPE), s.Keys(s.UserPlace, model.ROLE),
|
|
model.CITY_NAME, s.Keys(s.Street, model.NAME), model.AUTH_STATUS, model.DASHBOARD_UID,
|
|
))
|
|
m.Option(model.PLACE_NAME, msg.Append(s.Keys(s.Place, model.NAME)))
|
|
m.Option(model.STREET_NAME, msg.Append(s.Keys(s.Street, model.NAME)))
|
|
return msg
|
|
}
|
|
func (s Portal) PlaceCreate(m *ice.Message, arg ...string) {
|
|
if s.city.FindOrCreateByName(m, arg...); m.IsErr() {
|
|
return
|
|
} else if s.Street.FindOrCreateByName(m, arg...); m.IsErr() {
|
|
return
|
|
}
|
|
name := m.Option(s.Keys(s.Place, model.NAME))
|
|
arg = kit.TransArgKeys(arg, s.Keys(s.Place, model.NAME), model.NAME, s.Keys(s.Place, model.INFO), model.INFO, s.Keys(s.Place, model.TYPE), model.TYPE)
|
|
if m.Cmdy(s.Place, s.Insert, arg[2:]).IsErr() {
|
|
return
|
|
}
|
|
s.RecordEventWithName(m.Options(mdb.NAME, name, s.Keys(s.Place, model.UID), m.Result()), "")
|
|
args := kit.Simple(m.OptionSimple(s.Keys(s.Place, model.UID), model.USER_UID), model.ROLE, UserPlaceCreator)
|
|
m.SetResult().Cmdy(s.UserPlace, s.Insert, args)
|
|
args = append(args, s.Keys(s.UserPlace, model.UID), m.Result())
|
|
m.Options(args).Cmd("", s.AfterPlaceCreate, args)
|
|
}
|
|
func (s Portal) PlaceRemove(m *ice.Message, arg ...string) {
|
|
m.Cmd("", s.BeforePlaceRemove, m.OptionSimple(model.USER_UID, model.UID))
|
|
m.Cmdy(s.UserPlace, s.Delete, m.OptionSimple(model.USER_UID, model.UID))
|
|
}
|
|
func (s Portal) PlaceList(m *ice.Message, arg ...string) *ice.Message {
|
|
s.Tables(m, s.Place).FieldsWithCreatedAT(m, s.UserPlace, s.Keys(s.Place, model.UID),
|
|
s.Keys(s.Place, model.NAME), s.Keys(s.Place, model.TYPE), s.Keys(s.UserPlace, model.ROLE),
|
|
s.Key(s.Place, model.INIT), s.AS(s.Key(s.UserPlace, model.STATUS), model.MEMBER_STATUS),
|
|
s.Keys(s.Street, model.UID), model.AUTH_UID)
|
|
if len(arg) == 1 {
|
|
m.Cmdy(s.UserPlace, s.Table.Select, model.USER_UID, arg[0])
|
|
} else if len(arg) == 2 {
|
|
m.FieldsSetDetail().Cmdy(s.UserPlace, s.Table.Select, model.USER_UID, arg[0], s.Keys(s.Place, model.UID), arg[1])
|
|
} else {
|
|
return m
|
|
}
|
|
s.SelectJoin(m, s.Street, model.NAME, model.CITY_UID)
|
|
s.SelectJoinCity(m)
|
|
s.SelectJoinAuth(m)
|
|
return m
|
|
}
|
|
func (s Portal) PlaceInfo(m *ice.Message, arg ...string) {
|
|
msg := m.Cmd(s.Place, s.Table.Select, model.UID, m.Option(s.Keys(s.Place, model.UID)))
|
|
s.SelectJoin(msg, s.Street, model.NAME, model.CITY_UID)
|
|
s.SelectJoinCity(msg)
|
|
m.Option(model.CITY_NAME, msg.Append(model.CITY_NAME))
|
|
m.Option(model.STREET_NAME, msg.Append(s.Keys(s.Street, model.NAME)))
|
|
m.Option(model.PLACE_NAME, msg.Append(model.NAME))
|
|
}
|
|
func (s Portal) PlaceAuth(m *ice.Message, arg ...string) {
|
|
if m.Option(model.AUTH_UID) != "" {
|
|
return
|
|
}
|
|
place_uid, place_name := m.Option(s.Keys(s.Place, model.UID)), m.Option(s.Keys(s.Place, model.NAME))
|
|
m.Option(model.COMPANY_NAME, m.Option(s.Keys(s.Street, model.NAME)))
|
|
msg := s.AutoCmd(m, api.RENZHENGSHOUQUAN_PORTAL, s.PlaceCreate, m.OptionSimple(model.CITY_NAME, model.COMPANY_NAME),
|
|
model.AUTH_TYPE, ice.AUTO, model.AUTH_NAME, place_name, model.FROM_UID, ice.AUTO,
|
|
model.SERVICE_UID, ServiceUID(m), model.PLACE_UID, place_uid,
|
|
)
|
|
m.Cmd(s.Place, s.UpdateAuth, msg.Option(model.AUTH_UID), model.UID, place_uid)
|
|
s.RecordEventWithName(m.Options(model.NAME, place_name, model.UID, place_uid), "")
|
|
msg.Cmd(s.Prefix(m, s), s.AfterPlaceAuth)
|
|
s.StorageCreate(m, "")
|
|
}
|
|
|
|
func (s Portal) ValueCreate(m *ice.Message, arg ...string) {
|
|
s.Table.Insert(m, kit.Simple(arg, m.OptionSimple(model.USER_UID, s.Keys(s.Place, model.UID)))...)
|
|
}
|
|
func (s Portal) ValueRemove(m *ice.Message, arg ...string) {
|
|
s.Table.Delete(m, m.OptionSimple(s.Keys(s.Place, model.UID), model.UID)...)
|
|
}
|
|
func (s Portal) ValueModify(m *ice.Message, arg ...string) {
|
|
s.Table.Update(m, kit.Dict(arg), m.OptionSimple(s.Keys(s.Place, model.UID), model.UID)...)
|
|
}
|
|
func (s Portal) ValueList(m *ice.Message, arg ...string) {
|
|
PLACE_UID := s.Keys(s.Place, model.UID)
|
|
if len(arg) == 0 {
|
|
if m.Option(PLACE_UID) != "" {
|
|
s.Table.Select(m, m.OptionSimple(PLACE_UID)...)
|
|
}
|
|
return
|
|
}
|
|
s.Table.FieldsWithCreatedAT(m, m.Option(db.TARGET), m.Optionv(mdb.FIELDS).([]ice.Any)...)
|
|
if len(arg) == 1 {
|
|
s.Table.Select(m, PLACE_UID, arg[0]).Action(s.Create)
|
|
} else if len(arg) == 2 {
|
|
s.Table.SelectDetail(m, PLACE_UID, arg[0], model.UID, arg[1])
|
|
} else {
|
|
return
|
|
}
|
|
if s.IsVisitor(m) {
|
|
m.Action()
|
|
} else {
|
|
m.PushAction(s.Remove)
|
|
}
|
|
}
|
|
func (s Portal) BeforePlaceCreate(m *ice.Message, arg ...string) {}
|
|
func (s Portal) AfterPlaceCreate(m *ice.Message, arg ...string) {}
|
|
func (s Portal) BeforePlaceRemove(m *ice.Message, arg ...string) {}
|
|
func (s Portal) AfterPlaceRemove(m *ice.Message, arg ...string) {}
|
|
func (s Portal) BeforePlaceAuth(m *ice.Message, arg ...string) {}
|
|
func (s Portal) AfterPlaceAuth(m *ice.Message, arg ...string) {}
|
|
|
|
func (s Portal) AddRecent(m *ice.Message, arg ...string) {
|
|
if kit.IsIn(m.Append(model.AUTH_STATUS), "2", "issued") {
|
|
m.Cmd(s.Prefix(m, s.recent), s.Create, s.GetCommands(m, model.SERVICE_UID, arg...), model.PLACE_UID, m.Option(s.Keys(s.Place, model.UID)), model.AUTH_STATUS, "2")
|
|
} else {
|
|
m.Cmd(s.Prefix(m, s.recent), s.Create, s.GetCommands(m, model.SERVICE_UID, arg...), model.PLACE_UID, m.Option(s.Keys(s.Place, model.UID)))
|
|
}
|
|
}
|
|
func (s Portal) RecordEvent(m *ice.Message, arg ...string) {
|
|
s.event.Record(m.Spawn(kit.Dict(model.PLACE_UID, m.Option(s.Keys(s.Place, model.UID)))), arg[0], arg[1:]...)
|
|
}
|
|
func (s Portal) MarketInsert(m *ice.Message, arg ...string) {
|
|
m.Option(model.PLACE_UID, m.Option(s.Keys(s.Place, model.UID)))
|
|
m.Option(ctx.ARGS, kit.Join([]string{m.Option(model.PLACE_UID), m.Option(model.UID)}))
|
|
m.Cmdy(s.Prefix(m, market{}), s.Create, arg)
|
|
}
|
|
func (s Portal) DashboardCreate(m *ice.Message, name string, arg ...string) func() {
|
|
defer s.SaveBack(m, ice.MSG_USERPOD)()
|
|
kit.If(name == "", func() { name = m.Option(s.Keys(s.Place, model.NAME)) })
|
|
s.AutoCmdy(m, api.DASHBOARD_PORTAL, s.PlaceCreate, m.OptionSimple(model.CITY_NAME, model.COMPANY_NAME), model.DASHBOARD_NAME, name, model.DASHBOARD_TYPE, "0")
|
|
s.AutoCmd(m, api.RENZHENGSHOUQUAN_AUTH, s.UpdateField, m.OptionSimple(model.DASHBOARD_UID), model.UID, m.Option(model.AUTH_UID))
|
|
return func() { s.DashboardUpdate(m) }
|
|
}
|
|
func (s Portal) DashboardInsert(m *ice.Message, score int, title, unit string, index ice.Any, field string, arg ...ice.Any) {
|
|
kit.If(len(arg) == 0, func() { arg = append(arg, s.Keys(s.Place, model.UID), m.Option(s.Keys(s.Place, model.UID))) })
|
|
s.AutoCmd(m, api.DASHBOARD_SUMMARY, s.Insert, model.SPACE, m.Option(ice.MSG_USERPOD), model.INDEX, s.Prefix(m, index),
|
|
model.QUERY, kit.Format(arg), mdb.FIELD, field, model.TITLE, title, model.SCORE, score, model.UNIT, unit, m.OptionSimple(model.DASHBOARD_UID))
|
|
}
|
|
func (s Portal) DashboardUpdate(m *ice.Message, arg ...string) {
|
|
if m.Option(model.DASHBOARD_UID) != "" {
|
|
s.AutoCmd(m, api.DASHBOARD_SUMMARY, "scan", kit.Dict(m.OptionSimple(model.DASHBOARD_UID)))
|
|
}
|
|
}
|
|
func (s Portal) StorageCreate(m *ice.Message, name string, arg ...string) {
|
|
kit.If(name == "", func() { name = m.Option(s.Keys(s.Place, model.NAME)) })
|
|
s.AutoCmdy(m, api.STORAGE_PORTAL, s.PlaceCreate, m.OptionSimple(model.CITY_NAME, model.COMPANY_NAME), model.STORAGE_NAME, name, model.STORAGE_TYPE, "0")
|
|
s.AutoCmd(m, api.RENZHENGSHOUQUAN_AUTH, s.UpdateField, m.OptionSimple(model.STORAGE_UID), model.UID, m.Option(model.AUTH_UID))
|
|
}
|
|
func (s Portal) StorageInsert(m *ice.Message, title, content string) {
|
|
s.AutoCmd(m, api.STORAGE_FILE, s.Insert, model.TITLE, title, model.CONTENT, content, m.OptionSimple(model.STORAGE_UID, model.USER_UID))
|
|
}
|
|
|
|
func init() { ice.TeamCtxCmd(Portal{Table: newTable()}) }
|
|
|
|
func (s Portal) UserPlaceRole(m *ice.Message, arg ...string) *ice.Message {
|
|
if m.Option(model.USER_ROLE) == "" {
|
|
msg := m.Cmd(s.UserPlace, s.Table.Select, m.OptionSimple(s.Keys(s.Place, model.UID), model.USER_UID))
|
|
if MemberStatus(kit.Int(msg.Append(model.STATUS))) == MemberNormal {
|
|
m.Option(model.USER_ROLE, msg.Append(model.ROLE))
|
|
} else {
|
|
m.Option(model.USER_ROLE, "0")
|
|
}
|
|
}
|
|
return m
|
|
}
|
|
func (s Portal) UserPlaceCmd(m *ice.Message, arg ...string) {
|
|
m.Cmdy(s.UserPlace, arg)
|
|
}
|
|
func (s Portal) PlaceCmd(m *ice.Message, arg ...string) {
|
|
m.Cmdy(s.Place, arg)
|
|
}
|
|
|
|
func (s Portal) CommandUpdate(m *ice.Message, arg ...string) {
|
|
m.Config(model.SERVICE_UID, arg[0])
|
|
s.Hash.Select(m.Spawn()).Table(func(value ice.Maps) {
|
|
uid := m.Cmdx(command{}, s.Table.Modify, model.SERVICE_UID, arg[0], mdb.ICON, value[mdb.ICONS], model.NAME, value[model.NAME], model.INDEX, value[model.INDEX])
|
|
s.Hash.Modify(m, ctx.INDEX, value[ctx.INDEX], model.COMMAND_UID, uid)
|
|
})
|
|
}
|
|
func (s Portal) CommandSelect(m *ice.Message, arg ...string) {
|
|
s.Hash.Select(m, arg...)
|
|
}
|
|
|
|
func (s Portal) Create(m *ice.Message, arg ...string) {
|
|
args := []string{ctx.INDEX, m.Option(ctx.INDEX)}
|
|
msg := s.Hash.Select(m.Spawn(), m.Option(ctx.INDEX))
|
|
kit.If(msg.Length() > 0, func() { args = append(args, mdb.TIME, msg.Append(mdb.TIME)) })
|
|
m.Search(m.Option(ctx.INDEX), func(key string, cmd *ice.Command) {
|
|
args = append(args, mdb.NAME, cmd.Help, mdb.ICONS, cmd.Icon)
|
|
kit.For([]string{mdb.ORDER, mdb.TYPE, aaa.ROLE, mdb.VIEW}, func(key string) {
|
|
value := m.Conf(m.Option(ctx.INDEX), kit.Keym(key))
|
|
args = append(args, key, kit.Select(value, msg.Append(key)))
|
|
})
|
|
})
|
|
s.Hash.Create(m, args...)
|
|
}
|
|
func (s Portal) Remove(m *ice.Message, arg ...string) { s.Hash.Remove(m, arg...) }
|
|
func (s Portal) Modify(m *ice.Message, arg ...string) { s.Hash.Modify(m, arg...) }
|
|
func (s Portal) Show(m *ice.Message, arg ...string) {
|
|
m.Cmd(s.Prefix(m, s), s.Create, ctx.INDEX, m.PrefixKey())
|
|
}
|
|
func (s Portal) Link(m *ice.Message, arg ...string) string {
|
|
return m.MergePodCmd("", s.Prefix(m, s)) + "#" + kit.TrimSuffix(kit.Join([]string{arg[0], kit.Select(s.Prefix(m, apply{}), arg, 1), kit.Select("", arg, 2)}, ":"), ":")
|
|
}
|
|
|
|
func init() { ice.TeamCtxCmd(Portal{Table: newTable()}) }
|