From ab8de9ba4987d333fed5c56e6cb5e4213b8f1b4b Mon Sep 17 00:00:00 2001 From: shy Date: Fri, 10 Nov 2023 02:12:48 +0800 Subject: [PATCH] add wx.shy --- base/aaa/sess.go | 6 +- base/aaa/user.go | 1 + base/cli/cli.go | 7 +- base/cli/qrcode.go | 2 +- base/gdb/event.go | 4 +- base/gdb/gdb.go | 2 + base/mdb/lock.go | 6 ++ base/mdb/mdb.go | 2 + base/web/share.go | 6 ++ core/chat/favor.go | 7 +- core/chat/header.go | 2 +- core/chat/{icons.go => icon.go} | 4 +- core/chat/location/amap.go | 2 +- core/chat/location/bmap.go | 2 +- core/chat/location/location.go | 3 +- core/chat/location/tmap.go | 2 +- core/mall/goods.go | 3 +- misc/wx/access.go | 108 ++++++++++++++----------------- misc/wx/agent.go | 46 +++++++++++++ misc/wx/agent.js | 111 ++++++++++++++++++++++++++++++++ misc/wx/event.go | 16 ----- misc/wx/events.go | 48 ++++++++++++++ misc/wx/favor.go | 22 ------- misc/wx/login.go | 91 +++++++++++++++----------- misc/wx/menu.go | 54 +++++++--------- misc/wx/qrcode.go | 31 +++++++++ misc/wx/text.go | 38 +++++------ misc/wx/users.go | 35 ++++++++++ misc/wx/wx.go | 2 +- misc/wx/wx.shy | 42 +++++++----- 30 files changed, 481 insertions(+), 224 deletions(-) rename core/chat/{icons.go => icon.go} (78%) create mode 100644 misc/wx/agent.go create mode 100644 misc/wx/agent.js delete mode 100644 misc/wx/event.go create mode 100644 misc/wx/events.go delete mode 100644 misc/wx/favor.go create mode 100644 misc/wx/qrcode.go create mode 100644 misc/wx/users.go diff --git a/base/aaa/sess.go b/base/aaa/sess.go index 940fa9a9..cdc02851 100644 --- a/base/aaa/sess.go +++ b/base/aaa/sess.go @@ -55,9 +55,9 @@ func SessAuth(m *ice.Message, value ice.Any, arg ...string) *ice.Message { value = kit.Dict(USERNICK, kit.Select("", val, 0), USERNAME, kit.Select("", val, 1), USERROLE, kit.Select("", val, 2)) } return m.Auth( - USERNICK, m.Option(ice.MSG_USERNICK, kit.Value(value, USERNICK)), - USERNAME, m.Option(ice.MSG_USERNAME, kit.Value(value, USERNAME)), - USERROLE, m.Option(ice.MSG_USERROLE, kit.Value(value, USERROLE)), + USERNICK, m.Option(ice.MSG_USERNICK, kit.Format(kit.Value(value, USERNICK))), + USERNAME, m.Option(ice.MSG_USERNAME, kit.Format(kit.Value(value, USERNAME))), + USERROLE, m.Option(ice.MSG_USERROLE, kit.Format(kit.Value(value, USERROLE))), arg, logs.FileLineMeta(kit.Select(logs.FileLine(-1), m.Option("aaa.checker"))), ) } diff --git a/base/aaa/user.go b/base/aaa/user.go index d9570dfb..29e9c8fe 100644 --- a/base/aaa/user.go +++ b/base/aaa/user.go @@ -56,6 +56,7 @@ func init() { } func UserInfo(m *ice.Message, name ice.Any, key, meta string) (value string) { + if m.Cmd(USER, kit.Select(m.Option(ice.MSG_USERNAME), name), func(val ice.Maps) { value = val[key] }).Length() == 0 && kit.Format(name) == m.Option(ice.MSG_USERNAME) { return m.Option(meta) } diff --git a/base/cli/cli.go b/base/cli/cli.go index 9d5d2f93..df68cf21 100644 --- a/base/cli/cli.go +++ b/base/cli/cli.go @@ -1,9 +1,14 @@ package cli -import ice "shylinux.com/x/icebergs" +import ( + ice "shylinux.com/x/icebergs" + kit "shylinux.com/x/toolkits" +) const CLI = "cli" var Index = &ice.Context{Name: CLI, Help: "命令模块"} +func Prefix(arg ...string) string { return kit.Keys(CLI, arg) } + func init() { ice.Index.Register(Index, nil, RUNTIME, SYSTEM, DAEMON, FOREVER, MIRRORS, QRCODE) } diff --git a/base/cli/qrcode.go b/base/cli/qrcode.go index 8b335613..8279ba18 100644 --- a/base/cli/qrcode.go +++ b/base/cli/qrcode.go @@ -50,7 +50,7 @@ func init() { QRCODE: {Name: "qrcode text fg@key bg@key size auto", Help: "二维码", Actions: ice.Actions{ ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) { ice.AddRender(ice.RENDER_QRCODE, func(m *ice.Message, args ...ice.Any) string { - return m.Cmd(QRCODE, kit.Simple(args...)).Result() + return m.Cmd(Prefix(QRCODE), kit.Simple(args...)).Result() }) }}, mdb.INPUTS: {Hand: func(m *ice.Message, arg ...string) { diff --git a/base/gdb/event.go b/base/gdb/event.go index c42e4114..64a505c1 100644 --- a/base/gdb/event.go +++ b/base/gdb/event.go @@ -44,13 +44,13 @@ var list map[string]int = map[string]int{} func Watch(m *ice.Message, key string, arg ...string) *ice.Message { kit.If(len(arg) == 0, func() { arg = append(arg, m.PrefixKey()) }) - return m.Cmd(EVENT, LISTEN, EVENT, key, ice.CMD, kit.Join(arg, ice.SP)) + return m.Cmd(Prefix(EVENT), LISTEN, EVENT, key, ice.CMD, kit.Join(arg, ice.SP)) } func Event(m *ice.Message, key string, arg ...ice.Any) *ice.Message { if key = kit.Select(kit.Keys(m.CommandKey(), m.ActionKey()), key); list[key] == 0 { return m } - return m.Cmdy(EVENT, HAPPEN, EVENT, key, arg, logs.FileLineMeta(-1)) + return m.Cmdy(Prefix(EVENT), HAPPEN, EVENT, key, arg, logs.FileLineMeta(-1)) } func EventDeferEvent(m *ice.Message, key string, arg ...ice.Any) func(string, ...ice.Any) { Event(m, key, arg...) diff --git a/base/gdb/gdb.go b/base/gdb/gdb.go index 5c11729c..5876dfa4 100644 --- a/base/gdb/gdb.go +++ b/base/gdb/gdb.go @@ -49,4 +49,6 @@ const GDB = "gdb" var Index = &ice.Context{Name: GDB, Help: "事件模块"} +func Prefix(arg ...string) string { return kit.Keys(GDB, arg) } + func init() { ice.Index.Register(Index, &Frame{}, SIGNAL, EVENT, TIMER, ROUTINE) } diff --git a/base/mdb/lock.go b/base/mdb/lock.go index 81110341..5736ff7d 100644 --- a/base/mdb/lock.go +++ b/base/mdb/lock.go @@ -30,6 +30,12 @@ func RLock(m configMessage, arg ...string) func() { return getLock(m, arg...).RL func Config(m configMessage, key string, arg ...Any) string { return kit.Format(Configv(m, key, arg...)) } +func ConfigSimple(m configMessage, key ...string) (res []string) { + for _, key := range key { + res = append(res, key, kit.Format(Configv(m, key))) + } + return +} func Configv(m configMessage, key string, arg ...Any) Any { kit.If(len(arg) > 0, func() { Confv(m, m.PrefixKey(), kit.Keym(key), arg[0]) }) return Confv(m, m.PrefixKey(), kit.Keym(key)) diff --git a/base/mdb/mdb.go b/base/mdb/mdb.go index 9291910d..4dd60712 100644 --- a/base/mdb/mdb.go +++ b/base/mdb/mdb.go @@ -92,6 +92,7 @@ const ( STORE = kit.MDB_STORE FSIZE = kit.MDB_FSIZE + ICONS = "icons" TOOLS = "tools" SOURCE = "_source" TARGET = "_target" @@ -101,6 +102,7 @@ const ( INPUTS = "inputs" CREATE = "create" REMOVE = "remove" + UPDATE = "update" INSERT = "insert" DELETE = "delete" MODIFY = "modify" diff --git a/base/web/share.go b/base/web/share.go index b56f6e88..197b9c10 100644 --- a/base/web/share.go +++ b/base/web/share.go @@ -185,3 +185,9 @@ func ProxyUpload(m *ice.Message, pod string, p string) string { m.Cmd(SPACE, pod, SPIDE, PROXY, URL, url, nfs.SIZE, size, CACHE, cache.Format(ice.MOD_TIME), UPLOAD, mdb.AT+p) return kit.Select(p, pp, file.ExistsFile(pp)) } +func ShareLocal(m *ice.Message, p string) string { + if kit.HasPrefix(p, nfs.PS, HTTP) { + return p + } + return MergeLink(m, "/share/local/"+p) +} diff --git a/core/chat/favor.go b/core/chat/favor.go index 009cc6d4..af1164cf 100644 --- a/core/chat/favor.go +++ b/core/chat/favor.go @@ -23,7 +23,7 @@ const FAVOR = "favor" func init() { Index.MergeCommands(ice.Commands{ - FAVOR: {Help: "收藏夹", Icon: "favor.png", Actions: ice.MergeActions(ice.Actions{ + FAVOR: {Name: "favor hash auto", Help: "收藏夹", Icon: "favor.png", Actions: ice.MergeActions(ice.Actions{ mdb.SEARCH: {Hand: func(m *ice.Message, arg ...string) { if mdb.IsSearchPreview(m, arg) { m.Cmds("", func(value ice.Maps) { @@ -58,7 +58,7 @@ func init() { "scanQRCode": {Name: "favor create", Help: "扫码"}, "record1": {Name: "favor upload", Help: "截图"}, "record2": {Name: "favor upload", Help: "录屏"}, - mdb.CREATE: {Name: "create type name text", Hand: func(m *ice.Message, arg ...string) { + mdb.CREATE: {Name: "create type name text*", Hand: func(m *ice.Message, arg ...string) { if strings.HasPrefix(m.Option(mdb.TEXT), ice.HTTP) { m.OptionDefault(mdb.TYPE, mdb.LINK, mdb.NAME, kit.ParseURL(m.Option(mdb.TEXT)).Host) } @@ -81,7 +81,7 @@ func init() { } }}, cli.OPENS: {Hand: func(m *ice.Message, arg ...string) { cli.Opens(m, m.Option(mdb.TEXT)) }}, - }, FavorAction(), mdb.ExportHashAction()), Hand: func(m *ice.Message, arg ...string) { + }, FavorAction(), mdb.ExportHashAction(mdb.SHORT, mdb.TEXT, mdb.FIELD, "time,hash,type,name,text")), Hand: func(m *ice.Message, arg ...string) { if len(arg) > 0 && arg[0] == ctx.ACTION { if m.Option(ice.MSG_INDEX) == m.PrefixKey() { m.Option(mdb.TYPE, mdb.HashSelects(m.Spawn(), m.Option(mdb.HASH)).Append(mdb.TYPE)) @@ -98,6 +98,7 @@ func init() { } else { m.Action(mdb.CREATE, web.UPLOAD, "getClipboardData", "record1", "record2") } + m.SortStrR(mdb.TIME) } else { if web.PodCmd(m, web.SPACE, arg...) { return diff --git a/core/chat/header.go b/core/chat/header.go index 67b1c8cc..94871174 100644 --- a/core/chat/header.go +++ b/core/chat/header.go @@ -99,7 +99,7 @@ func init() { m.Option("language.list", m.Cmd(nfs.DIR, nfs.TemplatePath(m, aaa.LANGUAGE)+nfs.PS, nfs.FILE).Appendv(nfs.FILE)) m.Option("theme.list", m.Cmd(nfs.DIR, nfs.TemplatePath(m, aaa.THEME)+nfs.PS, nfs.FILE).Appendv(nfs.FILE)) m.Option(nfs.REPOS, m.Cmdv(web.SPIDE, nfs.REPOS, web.CLIENT_URL)) - m.Option(ICONS, mdb.Conf(m, ICONS, kit.Keym(nfs.PATH))) + m.Option("icons", mdb.Conf(m, ICON, kit.Keym(nfs.PATH))) m.Option(MENUS, mdb.Config(m, MENUS)) m.Echo(mdb.Config(m, TITLE)) if mdb.HashSelect(m); m.Length() == 0 { diff --git a/core/chat/icons.go b/core/chat/icon.go similarity index 78% rename from core/chat/icons.go rename to core/chat/icon.go index 43c78573..9d6563a8 100644 --- a/core/chat/icons.go +++ b/core/chat/icon.go @@ -11,11 +11,11 @@ import ( kit "shylinux.com/x/toolkits" ) -const ICONS = "icons" +const ICON = "icon" func init() { Index.MergeCommands(ice.Commands{ - ICONS: {Help: "图标", Actions: ctx.ConfAction(nfs.PATH, "bootstrap-icons/font/bootstrap-icons.css"), Hand: func(m *ice.Message, arg ...string) { + ICON: {Help: "图标", Actions: ctx.ConfAction(nfs.PATH, "bootstrap-icons/font/bootstrap-icons.css"), Hand: func(m *ice.Message, arg ...string) { m.Cmd(lex.SPLIT, ice.USR_MODULES+mdb.Config(m, nfs.PATH), kit.Dict(lex.SPLIT_SPACE, " {:;}"), func(text string, ls []string) { if len(ls) > 2 && ls[2] == nfs.CONTENT { name := "bi " + strings.TrimPrefix(ls[0], nfs.PT) diff --git a/core/chat/location/amap.go b/core/chat/location/amap.go index a3d4ed02..efe554cd 100644 --- a/core/chat/location/amap.go +++ b/core/chat/location/amap.go @@ -1,4 +1,4 @@ -package chat +package location import ( "path" diff --git a/core/chat/location/bmap.go b/core/chat/location/bmap.go index 4695b011..6bead919 100644 --- a/core/chat/location/bmap.go +++ b/core/chat/location/bmap.go @@ -1,4 +1,4 @@ -package chat +package location import ( ice "shylinux.com/x/icebergs" diff --git a/core/chat/location/location.go b/core/chat/location/location.go index cf0ef004..4a25786d 100644 --- a/core/chat/location/location.go +++ b/core/chat/location/location.go @@ -1,4 +1,4 @@ -package chat +package location import ( ice "shylinux.com/x/icebergs" @@ -17,6 +17,7 @@ const ( CITY = "city" DISTRICT = "district" STREET = "street" + SCALE = "scale" ) const LOCATION = "location" diff --git a/core/chat/location/tmap.go b/core/chat/location/tmap.go index 2d0ecafe..59a931d6 100644 --- a/core/chat/location/tmap.go +++ b/core/chat/location/tmap.go @@ -1,4 +1,4 @@ -package chat +package location import ( "net/http" diff --git a/core/mall/goods.go b/core/mall/goods.go index e13e03cd..f78ad88f 100644 --- a/core/mall/goods.go +++ b/core/mall/goods.go @@ -2,6 +2,7 @@ package mall import ( ice "shylinux.com/x/icebergs" + "shylinux.com/x/icebergs/base/aaa" "shylinux.com/x/icebergs/base/ctx" "shylinux.com/x/icebergs/base/mdb" "shylinux.com/x/icebergs/base/nfs" @@ -21,7 +22,7 @@ func init() { mdb.CREATE: {Name: "create zone* name* text price* count*=1 units*=件,个,份,斤 image*=4@img"}, mdb.MODIFY: {Name: "modify zone* name* text price* count*=1 units*=件,个,份,斤 image*=4@img"}, ORDER: {Name: "order count*=1", Help: "选购", Hand: func(m *ice.Message, arg ...string) { m.Cmdy(CART, mdb.INSERT, arg) }}, - }, web.ExportCacheAction(nfs.IMAGE), mdb.ExportHashAction(ctx.TOOLS, kit.Fields(Prefix(CART), Prefix(ORDER)), mdb.FIELD, "time,hash,zone,name,text,price,count,units,image")), Hand: func(m *ice.Message, arg ...string) { + }, aaa.RoleAction(), web.ExportCacheAction(nfs.IMAGE), mdb.ExportHashAction(ctx.TOOLS, kit.Fields(Prefix(CART), Prefix(ORDER)), mdb.FIELD, "time,hash,zone,name,text,price,count,units,image")), Hand: func(m *ice.Message, arg ...string) { kit.If(len(arg) == 0 && m.IsMobileUA(), func() { m.OptionDefault(ice.MSG_FIELDS, "zone,name,price,count,units,text,hash,time,image") }) mdb.HashSelect(m, arg...).PushAction(ORDER).Action("filter:text") web.PushPodCmd(m, "", arg...).Sort("zone,name") diff --git a/misc/wx/access.go b/misc/wx/access.go index d470a30e..02a255f7 100644 --- a/misc/wx/access.go +++ b/misc/wx/access.go @@ -4,96 +4,84 @@ import ( "crypto/sha1" "net/http" "strings" - "time" ice "shylinux.com/x/icebergs" + "shylinux.com/x/icebergs/base/aaa" "shylinux.com/x/icebergs/base/ctx" - "shylinux.com/x/icebergs/base/gdb" "shylinux.com/x/icebergs/base/mdb" - "shylinux.com/x/icebergs/base/nfs" "shylinux.com/x/icebergs/base/tcp" "shylinux.com/x/icebergs/base/web" - "shylinux.com/x/icebergs/core/chat" + "shylinux.com/x/icebergs/base/web/html" + "shylinux.com/x/icebergs/core/chat/oauth" kit "shylinux.com/x/toolkits" ) -func _wx_sign(m *ice.Message, nonce, stamp string) string { - return kit.Format(sha1.Sum([]byte(kit.Join(kit.Sort(kit.Simple( - kit.Format("jsapi_ticket=%s", m.Cmdx(ACCESS, TICKET)), - kit.Format("url=%s", m.Option(ice.MSG_USERWEB)), - kit.Format("timestamp=%s", stamp), - kit.Format("noncestr=%s", nonce), - )), "&")))) -} -func _wx_config(m *ice.Message, nonce string) { - m.Option("signature", _wx_sign(m, m.Option("noncestr", nonce), m.Option("timestamp", kit.Format(time.Now().Unix())))) - ctx.OptionFromConfig(m, APPID, nfs.SCRIPT) -} -func _wx_check(m *ice.Message) { - check := kit.Sort([]string{mdb.Config(m, TOKEN), m.Option("timestamp"), m.Option("nonce")}) - if sig := kit.Format(sha1.Sum([]byte(strings.Join(check, "")))); !m.Warn(sig != m.Option("signature"), ice.ErrNotRight, check) { - kit.If(m.Option("echostr") != "", func() { m.RenderResult(m.Option("echostr")) }, func() { m.Echo(ice.TRUE) }) - } -} - const ( APPID = "appid" - APPMM = "appmm" + SECRET = "secret" TOKEN = "token" TOKENS = "tokens" EXPIRES = "expires" TICKET = "ticket" EXPIRE = "expire" - CONFIG = "config" - CHECK = "check" ) const ( - ERRCODE = "errcode" - ERRMSG = "errmsg" + CGI_BIN = "https://api.weixin.qq.com/cgi-bin/" + QRCODE_CREATE = "qrcode/create" + MENU_CREATE = "menu/create" + USER_INFO = "user/info" + USER_GET = "user/get" ) const ACCESS = "access" func init() { Index.MergeCommands(ice.Commands{ - ACCESS: {Name: "access appid auto ticket tokens login", Help: "认证", Actions: ice.MergeActions(ice.Actions{ - ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) { - m.Cmd(web.SPIDE, mdb.CREATE, WX, mdb.Config(m, tcp.SERVER)) - gdb.Watch(m, chat.HEADER_AGENT, m.PrefixKey()) + ACCESS: {Help: "认证", Meta: Meta(), Actions: ice.MergeActions(ice.Actions{ + ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) { m.Cmd(web.SPIDE, mdb.CREATE, WX, mdb.Config(m, tcp.SERVER)) }}, + mdb.CREATE: {Name: "login usernick access* appid* secret* token* icons", Help: "登录", Hand: func(m *ice.Message, arg ...string) { + mdb.HashCreate(m, m.OptionSimple(aaa.USERNICK, ACCESS, APPID, SECRET, TOKEN, mdb.ICONS)) + ctx.ConfigFromOption(m, ACCESS, APPID, TOKEN) }}, - chat.HEADER_AGENT: {Hand: func(m *ice.Message, arg ...string) { - if strings.Index(m.Option(ice.MSG_USERUA), "MicroMessenger") > -1 { - _wx_config(m, mdb.Config(m, APPID)) + aaa.CHECK: {Hand: func(m *ice.Message, arg ...string) { + check := kit.Sort([]string{mdb.Config(m, TOKEN), m.Option(TIMESTAMP), m.Option(NONCE)}) + if sig := kit.Format(sha1.Sum([]byte(strings.Join(check, "")))); !m.Warn(sig != m.Option(SIGNATURE), ice.ErrNotRight, check) { + m.Echo(ice.TRUE) } }}, - LOGIN: {Name: "login appid appmm token", Help: "登录", Hand: func(m *ice.Message, arg ...string) { - ctx.ConfigFromOption(m, APPID, APPMM, TOKEN) - }}, - TOKENS: {Help: "令牌", Hand: func(m *ice.Message, arg ...string) { - if now := time.Now().Unix(); mdb.Config(m, TOKENS) == "" || now > kit.Int64(mdb.Config(m, EXPIRES)) { - msg := m.Cmd(web.SPIDE, WX, http.MethodGet, "/cgi-bin/token?grant_type=client_credential", APPID, mdb.Config(m, APPID), "secret", mdb.Config(m, APPMM)) - if m.Warn(msg.Append(ERRCODE) != "", msg.Append(ERRCODE), msg.Append(ERRMSG)) { - return - } - mdb.Config(m, EXPIRES, now+kit.Int64(msg.Append("expires_in"))) - mdb.Config(m, TOKENS, msg.Append("access_token")) + AGENT: {Hand: func(m *ice.Message, arg ...string) { ctx.OptionFromConfig(m, ACCESS, APPID) }}, + TOKENS: {Hand: func(m *ice.Message, arg ...string) { + msg := mdb.HashSelect(m.Spawn(), m.Option(ACCESS)) + if msg.Append(TOKENS) == "" || m.Time() > msg.Append(EXPIRES) { + res := m.Cmd(web.SPIDE, WX, http.MethodGet, "token?grant_type=client_credential", msg.AppendSimple(APPID, SECRET)) + mdb.HashModify(m, m.OptionSimple(ACCESS), EXPIRES, m.Time(kit.Format("%vs", res.Append(oauth.EXPIRES_IN))), TOKENS, res.Append(oauth.ACCESS_TOKEN)) + msg = mdb.HashSelect(m.Spawn(), m.Option(ACCESS)) } - m.Echo(mdb.Config(m, TOKENS)).Status(EXPIRES, time.Unix(kit.Int64(mdb.Config(m, EXPIRES)), 0).Format(ice.MOD_TIME)) + m.Echo(msg.Append(TOKENS)).Status(msg.AppendSimple(EXPIRES)) }}, - TICKET: {Help: "票据", Hand: func(m *ice.Message, arg ...string) { - if now := time.Now().Unix(); mdb.Config(m, TICKET) == "" || now > kit.Int64(mdb.Config(m, EXPIRE)) { - msg := m.Cmd(web.SPIDE, WX, http.MethodGet, "/cgi-bin/ticket/getticket?type=jsapi", "access_token", m.Cmdx("", TOKENS)) - if m.Warn(msg.Append(ERRCODE) != "0", msg.Append(ERRCODE), msg.Append(ERRMSG)) { - return - } - mdb.Config(m, EXPIRE, now+kit.Int64(msg.Append("expires_in"))) - mdb.Config(m, TICKET, msg.Append(TICKET)) + TICKET: {Hand: func(m *ice.Message, arg ...string) { + msg := mdb.HashSelect(m.Spawn(), m.Option(ACCESS)) + if msg.Append(TICKET) == "" || m.Time() > msg.Append(EXPIRE) { + res := m.Cmd(web.SPIDE, WX, http.MethodGet, "ticket/getticket?type=jsapi", arg, oauth.ACCESS_TOKEN, m.Cmdx(ACCESS, TOKENS)) + mdb.HashModify(m, m.OptionSimple(ACCESS), EXPIRE, m.Time(kit.Format("%vs", res.Append(oauth.EXPIRES_IN))), TICKET, res.Append(TICKET)) + msg = mdb.HashSelect(m.Spawn(), m.Option(ACCESS)) } - m.Echo(mdb.Config(m, TICKET)).Status(EXPIRE, time.Unix(kit.Int64(mdb.Config(m, EXPIRE)), 0).Format(ice.MOD_TIME)) + m.Echo(msg.Append(TICKET)).Status(msg.AppendSimple(EXPIRE)) }}, - CONFIG: {Hand: func(m *ice.Message, arg ...string) { _wx_config(m, mdb.Config(m, APPID)) }}, - CHECK: {Hand: func(m *ice.Message, arg ...string) { _wx_check(m) }}, - }, mdb.HashAction(tcp.SERVER, "https://api.weixin.qq.com", nfs.SCRIPT, "/plugin/local/chat/wx.js")), Hand: func(m *ice.Message, arg ...string) { - m.Echo(mdb.Config(m, APPID)) + }, mdb.ImportantHashAction(mdb.SHORT, ACCESS, mdb.FIELD, "time,access,usernick,appid,icons", tcp.SERVER, CGI_BIN)), Hand: func(m *ice.Message, arg ...string) { + mdb.HashSelect(m, arg...).StatusTimeCount(mdb.ConfigSimple(m, ACCESS, APPID), web.LINK, web.MergeURL2(m, "/chat/wx/login/")) }}, }) } +func SpideGet(m *ice.Message, api string, arg ...ice.Any) ice.Any { + return kit.UnMarshal(m.Cmdx(web.SPIDE, WX, web.SPIDE_RAW, http.MethodGet, kit.MergeURL(api, oauth.ACCESS_TOKEN, m.Cmdx(ACCESS, TOKENS)), arg)) +} +func SpidePost(m *ice.Message, api string, arg ...ice.Any) ice.Any { + return kit.UnMarshal(m.Cmdx(web.SPIDE, WX, web.SPIDE_RAW, http.MethodPost, kit.MergeURL(api, oauth.ACCESS_TOKEN, m.Cmdx(ACCESS, TOKENS)), arg)) +} +func Meta() ice.Map { + return kit.Dict(ice.CTX_TRANS, kit.Dict(html.INPUT, kit.Dict( + ACCESS, "账号", APPID, "应用", SECRET, "密码", + EXPIRE_SECONDS, "有效期", + SCENE, "场景", RIVER, "一级", STORM, "二级", + ))) +} diff --git a/misc/wx/agent.go b/misc/wx/agent.go new file mode 100644 index 00000000..450322d7 --- /dev/null +++ b/misc/wx/agent.go @@ -0,0 +1,46 @@ +package wx + +import ( + "crypto/sha1" + "strings" + "time" + + ice "shylinux.com/x/icebergs" + "shylinux.com/x/icebergs/base/gdb" + "shylinux.com/x/icebergs/base/mdb" + "shylinux.com/x/icebergs/base/web" + "shylinux.com/x/icebergs/core/chat" + "shylinux.com/x/icebergs/core/chat/location" + kit "shylinux.com/x/toolkits" +) + +func _wx_sign(m *ice.Message, nonce, stamp string) string { + return kit.Format(sha1.Sum([]byte(kit.Join(kit.Sort(kit.Simple( + kit.Format("jsapi_ticket=%s", m.Cmdx(ACCESS, TICKET)), + kit.Format("url=%s", m.R.Header.Get(web.Referer)), + kit.Format("timestamp=%s", stamp), + kit.Format("noncestr=%s", nonce), + )), "&")))) +} + +const ( + SIGNATURE = "signature" + TIMESTAMP = "timestamp" + NONCESTR = "noncestr" + NONCE = "nonce" +) +const AGENT = "agent" + +func init() { + Index.MergeCommands(ice.Commands{ + AGENT: {Name: "agent auto", Actions: ice.MergeActions(ice.Actions{ + chat.HEADER_AGENT: {Hand: func(m *ice.Message, arg ...string) { + kit.If(strings.Index(m.Option(ice.MSG_USERUA), "MicroMessenger") > -1, func() { m.Option(mdb.PLUGIN, m.PrefixKey()) }) + }}, + "scanQRCode1": {Hand: func(m *ice.Message, arg ...string) { m.Cmdy(chat.FAVOR, mdb.CREATE, arg) }}, + "getLocation": {Hand: func(m *ice.Message, arg ...string) { m.Cmdy(location.LOCATION, mdb.CREATE, arg) }}, + }, gdb.EventsAction(chat.HEADER_AGENT)), Hand: func(m *ice.Message, arg ...string) { + m.Cmdy(ACCESS, AGENT).Options(SIGNATURE, _wx_sign(m, m.Option(NONCESTR, "some"), m.Option(TIMESTAMP, kit.Format(time.Now().Unix())))).Display("") + }}, + }) +} diff --git a/misc/wx/agent.js b/misc/wx/agent.js new file mode 100644 index 00000000..ccd847ec --- /dev/null +++ b/misc/wx/agent.js @@ -0,0 +1,111 @@ +Volcanos(chat.ONIMPORT, { + _init: function(can, msg) { msg.Option(ice.MSG_ACTION, ""), can.require(["https://res.wx.qq.com/open/js/jweixin-1.6.0.js"], function(can) { + wx.config({debug: msg.Option("debug") == ice.TRUE, signature: msg.Option("signature"), timestamp: msg.Option("timestamp"), nonceStr: msg.Option("noncestr"), appId: msg.Option("appid"), + jsApiList: can.core.Item({ + scanQRCode: function(can, cb) { wx.scanQRCode({needResult: cb? 1: 0, scanType: ["qrCode","barCode"], success: function (res) { + can.base.isFunc(cb) && cb(can.base.ParseJSON(res.resultStr)) + } }) }, + getLocation: function(can, cb) { wx.getLocation({type: "gcj02", success: function (res) { + can.base.isFunc(cb) && cb({type: "gcj02", name: "当前位置", text: "当前位置", latitude: parseInt(res.latitude*100000), longitude: parseInt(res.longitude*100000) }) + } }) }, + openLocation: function(can, msg) { wx.openLocation({ + name: msg.Option(mdb.NAME), address: msg.Option(mdb.TEXT), infoUrl: msg.Option(mdb.LINK), + longitude: parseFloat(msg.Option("longitude")), latitude: parseFloat(msg.Option("latitude")), scale: msg.Option("scale")||14, + }) }, + chooseImage: function(can, cb, count) { wx.chooseImage({count: count||9, sizeType: ['original', 'compressed'], sourceType: ['album', 'camera'], success: function (res) { + can.base.isFunc(cb) && cb(res.localIds) + } }) }, + }, function(key, value) { return can.user.agent[key] = value, key }).concat([ + // "uploadImage", "previewImage", + // "updateAppMessageShareData", "updateTimelineShareData", + ]), + }) + }) }, +}) +Volcanos(chat.ONACTION, {list: [ + "scanQRCode", "scanQRCode1", "getLocation", "openLocation", + "uploadImage", "chooseImage", "previewImage", + "updateAppMessageShareData", "updateTimelineShareData", + "openAddress", +], + scanQRCode: function(event, can, button) { + wx.scanQRCode({needResult: 0, scanType: ["qrCode","barCode"]}) + }, + scanQRCode1: function(event, can, button) { + wx.scanQRCode({needResult: 1, scanType: ["qrCode","barCode"], success: function (res) { + can.run(event, [ctx.ACTION, button, mdb.TEXT, res.resultStr], function() {}) + can._output.innerHTML = res.resultStr + } }) + }, + getLocation: function(event, can, button) { + wx.getLocation({type: "gcj02", success: function (res) { + can.run(event, [ctx.ACTION, button, mdb.NAME, "current", "longitude", res.longitude.toFixed(6), "latitude", res.latitude.toFixed(6)], function() {}) + can._output.innerHTML = JSON.stringify(res) + } }) + }, + openLocation: function(event, can, button) { + wx.getLocation({type: "gcj02", success: function (res) { wx.openLocation(res) }}) + }, + uploadImage: function(event, can, button) { + wx.chooseImage({success: function (res) { + can.core.List(res.localIds, function(item) { + wx.uploadImage({ + localId: item, isShowProgressTips: 1, + success: function (res) { + var serverId = res.serverId; + can._output.innerHTML = serverId + } + }) + + }) + }}) + }, + chooseImage: function(event, can, button) { + wx.chooseImage({ + // count: 9, sourceType: ['album', 'camera'], sizeType: ['original', 'compressed'], + success: function (res) { + can.page.Append(can, can._output, can.core.List(res.localIds, function(item) { + return {img: item, style: {"max-width": can.ConfWidth()}} + })) + } + }) + }, + previewImage: function(event, can, button) { + wx.previewImage({ + urls: [ + 'https://2021.shylinux.com/share/local/usr/icons/timg.png', + "https://2021.shylinux.com/share/local/usr/icons/mall.png", + ], + }) + }, + updateAppMessageShareData: function(event, can, button) { + wx.updateAppMessageShareData({ + title: document.title, desc: "工具系统", link: location.href, + imgUrl: 'https://2021.shylinux.com/share/local/usr/icons/timg.png', + success: function (res) { can._output.innerHTML = JSON.stringify(res) }, + }) + }, + updateTimelineShareData: function(event, can, button) { + wx.updateTimelineShareData({ + title: document.title, desc: "工具系统", link: location.href, + imgUrl: 'https://2021.shylinux.com/share/local/usr/icons/timg.png', + success: function (res) { can._output.innerHTML = JSON.stringify(res) }, + }) + }, + openAddress: function(event, can, button) { + wx.openAddress({ + success: function (res) { + can._output.innerHTML = JSON.stringify(res) + + var userName = res.userName; // 收货人姓名 + var postalCode = res.postalCode; // 邮编 + var provinceName = res.provinceName; // 国标收货地址第一级地址(省) + var cityName = res.cityName; // 国标收货地址第二级地址(市) + var countryName = res.countryName; // 国标收货地址第三级地址(国家) + var detailInfo = res.detailInfo; // 详细收货地址信息 + var nationalCode = res.nationalCode; // 收货地址国家码 + var telNumber = res.telNumber; // 收货人手机号码 + } + }) + }, +}) diff --git a/misc/wx/event.go b/misc/wx/event.go deleted file mode 100644 index 8178a286..00000000 --- a/misc/wx/event.go +++ /dev/null @@ -1,16 +0,0 @@ -package wx - -import ( - ice "shylinux.com/x/icebergs" -) - -const EVENT = "event" - -func init() { - Index.MergeCommands(ice.Commands{ - EVENT: {Name: "event", Help: "事件", Actions: ice.Actions{ - "subscribe": {Help: "订阅", Hand: func(m *ice.Message, arg ...string) { m.Cmdy(MENU, "home") }}, - "unsubscribe": {Help: "取关", Hand: func(m *ice.Message, arg ...string) {}}, - }}, - }) -} diff --git a/misc/wx/events.go b/misc/wx/events.go new file mode 100644 index 00000000..1ff1a3dc --- /dev/null +++ b/misc/wx/events.go @@ -0,0 +1,48 @@ +package wx + +import ( + ice "shylinux.com/x/icebergs" + "shylinux.com/x/icebergs/base/ctx" + "shylinux.com/x/icebergs/base/mdb" + "shylinux.com/x/icebergs/base/nfs" + "shylinux.com/x/icebergs/base/web" + kit "shylinux.com/x/toolkits" +) + +const EVENTS = "events" + +func init() { + const ( + SUBSCRIBE = "subscribe" + UNSUBSCRIBE = "unsubscribe" + SCAN = "scan" + SCANCODE_WAITMSG = "scancode_waitmsg" + CLICK = "click" + ) + Index.MergeCommands(ice.Commands{ + EVENTS: {Help: "事件", Actions: ice.Actions{ + SUBSCRIBE: {Help: "订阅", Hand: func(m *ice.Message, arg ...string) { + m.Cmdy(TEXT, web.LINK, kit.MergeURL2(m.Option(ice.MSG_USERWEB), nfs.PS)) + }}, + UNSUBSCRIBE: {Help: "取关", Hand: func(m *ice.Message, arg ...string) {}}, + SCAN: {Help: "扫码", Hand: func(m *ice.Message, arg ...string) { + msg := m.Cmd(QRCODE, m.Option(ACCESS), arg[0]) + m.Options(ice.MSG_USERPOD, msg.Append(web.SPACE)) + link := m.Cmd(web.SHARE, mdb.CREATE, mdb.TYPE, web.FIELD, mdb.NAME, msg.Append(ctx.INDEX), mdb.TEXT, msg.Append(ctx.ARGS)).Option(web.LINK) + m.Cmdy(TEXT, web.LINK, link, msg.Append(mdb.NAME), msg.Append(mdb.TEXT), msg.Append(mdb.ICONS)) + }}, + SCANCODE_WAITMSG: {Help: "扫码", Hand: func(m *ice.Message, arg ...string) { + m.Cmdy(TEXT, web.LINK, m.Option("ScanResult")) + }}, + CLICK: {Help: "菜单", Hand: func(m *ice.Message, arg ...string) { + msg := m.Cmd(MENU, m.Option(ACCESS), arg[0]) + m.Options(mdb.ICONS, msg.Append(mdb.ICONS), mdb.NAME, msg.Append(mdb.NAME), mdb.TEXT, kit.Select(msg.Append(ctx.INDEX), msg.Append(mdb.TEXT))) + if msg.Append(ctx.INDEX) == "" { + m.Cmdy(TEXT, web.LINK, kit.MergeURL2(m.Option(ice.MSG_USERWEB), nfs.PS)) + } else { + m.Cmdy(TEXT, web.LINK, m.MergePodCmd("", msg.Append(ctx.INDEX), kit.Split(msg.Append(ctx.ARGS)))) + } + }}, + }}, + }) +} diff --git a/misc/wx/favor.go b/misc/wx/favor.go deleted file mode 100644 index 2f85a0ac..00000000 --- a/misc/wx/favor.go +++ /dev/null @@ -1,22 +0,0 @@ -package wx - -import ( - ice "shylinux.com/x/icebergs" - "shylinux.com/x/icebergs/base/aaa" - "shylinux.com/x/icebergs/base/mdb" - kit "shylinux.com/x/toolkits" -) - -const FAVOR = "favor" - -func init() { - Index.MergeCommands(ice.Commands{ - FAVOR: {Name: "favor text:text auto create", Help: "收藏", Actions: mdb.HashAction( - mdb.SHORT, mdb.TEXT, mdb.FIELD, "time,type,name,text", mdb.LINK, "https://open.weixin.qq.com/qr/code", - ), Hand: func(m *ice.Message, arg ...string) { - mdb.HashSelect(m, arg...).Table(func(value ice.Maps) { - m.PushQRCode(mdb.SCAN, kit.MergeURL(mdb.Config(m, mdb.LINK), aaa.USERNAME, value[mdb.TEXT])) - }) - }}, - }) -} diff --git a/misc/wx/login.go b/misc/wx/login.go index d051d12d..47a63be0 100644 --- a/misc/wx/login.go +++ b/misc/wx/login.go @@ -4,13 +4,16 @@ import ( "bytes" "encoding/xml" "io/ioutil" + "strings" ice "shylinux.com/x/icebergs" "shylinux.com/x/icebergs/base/aaa" + "shylinux.com/x/icebergs/base/ctx" + "shylinux.com/x/icebergs/base/gdb" "shylinux.com/x/icebergs/base/mdb" "shylinux.com/x/icebergs/base/web" "shylinux.com/x/icebergs/core/chat" - "shylinux.com/x/icebergs/core/wiki" + "shylinux.com/x/icebergs/core/chat/location" kit "shylinux.com/x/toolkits" ) @@ -22,70 +25,80 @@ func _wx_parse(m *ice.Message) { MsgType string MsgId int64 Event string + EventKey string Content string - Title string - Description string - Url string - PicUrl string Location_X float64 Location_Y float64 Scale string Label string + Title string + Description string + MediaId int64 + PicUrl string + Url string + ScanCodeInfo struct { + ScanType string + ScanResult string + } }{} defer m.R.Body.Close() buf, _ := ioutil.ReadAll(m.R.Body) - m.Debug("buf: %+v", string(buf)) xml.NewDecoder(bytes.NewBuffer(buf)).Decode(&data) + m.Option("debug", "true") + m.Debug("buf: %+v", string(buf)) m.Debug("data: %+v", data) - m.Option("FromUserName", data.FromUserName) - m.Option("ToUserName", data.ToUserName) + m.Option(ACCESS, data.ToUserName) m.Option("CreateTime", data.CreateTime) - m.Option("MsgId", data.MsgId) + m.Option(aaa.USERNAME, data.FromUserName) + m.Option(mdb.TYPE, data.MsgType) + m.Option(mdb.ID, data.MsgId) m.Option("Event", data.Event) - m.Option("MsgType", data.MsgType) - m.Option("Content", data.Content) - m.Option("Title", data.Title) - m.Option("Description", data.Description) - m.Option("URL", data.Url) - m.Option("URL", data.PicUrl) - m.Option("LocationX", kit.Int(data.Location_X*100000)) - m.Option("LocationY", kit.Int(data.Location_Y*100000)) - m.Option("Scale", data.Scale) + m.Option("EventKey", data.EventKey) + m.Option(mdb.TEXT, data.Content) + m.Option(web.LINK, kit.Select(data.Url, data.PicUrl)) + m.Option(location.LATITUDE, kit.Format("%0.6f", data.Location_X)) + m.Option(location.LONGITUDE, kit.Format("%0.6f", data.Location_Y)) + m.Option(location.SCALE, data.Scale) m.Option("Label", data.Label) + m.Option("Title", data.Title) + m.Option("MediaId", data.MediaId) + m.Option("Description", data.Description) + m.Option("ScanResult", data.ScanCodeInfo.ScanResult) } const LOGIN = "login" func init() { + web.Index.MergeCommands(ice.Commands{ + "/MP_verify_0xp0zkW3fIzIq2Bo.txt": {Actions: aaa.WhiteAction(), Hand: func(m *ice.Message, arg ...string) { m.RenderResult("0xp0zkW3fIzIq2Bo") }}, + }) Index.MergeCommands(ice.Commands{ web.PP(LOGIN): {Actions: aaa.WhiteAction(), Hand: func(m *ice.Message, arg ...string) { - if m.Cmdx(ACCESS, CHECK) == "" { + if m.Cmdx(ACCESS, aaa.CHECK) == "" { + return + } else if m.Option("echostr") != "" { + m.RenderResult(m.Option("echostr")) return } _wx_parse(m) - m.Option(ice.MSG_USERZONE, WX) - aaa.SessAuth(m, kit.Dict(aaa.USERNAME, m.Option("FromUserName"), aaa.USERROLE, aaa.UserRole(m, m.Option("FromUserName")))) - switch m.Option("MsgType") { - case EVENT: - m.Cmdy(EVENT, m.Option("Event")) + aaa.SessAuth(m.Options(ice.MSG_USERZONE, WX), kit.Dict(aaa.USERNAME, m.Option(aaa.USERNAME), aaa.USERROLE, aaa.UserRole(m, m.Option(aaa.USERNAME)))) + switch m.Option(mdb.TYPE) { + case gdb.EVENT: + m.Cmdy(EVENTS, strings.ToLower(m.Option("Event")), kit.Split(m.Option("EventKey"))) + case location.LOCATION: + m.Cmdy(location.LOCATION, mdb.CREATE, mdb.TEXT, m.Option("Label"), m.OptionSimple(location.LONGITUDE, location.LATITUDE, location.SCALE)) case TEXT: - if cmds := kit.Split(m.Option("Content")); aaa.Right(m, cmds) { - m.Cmdy(TEXT, cmds) - } else { - m.Cmdy(MENU, "home") + if cmds := kit.Split(m.Option(mdb.TEXT)); aaa.Right(m, cmds) { + m.Cmdy(TEXT, ctx.CMDS, cmds) + break } - case mdb.LINK: - m.Cmdy(chat.FAVOR, mdb.CREATE, mdb.TYPE, mdb.LINK, mdb.NAME, m.Option("Title"), mdb.TEXT, m.Option("URL")) - case wiki.IMAGE: - m.Cmdy(chat.FAVOR, mdb.CREATE, mdb.TYPE, wiki.IMAGE, mdb.NAME, m.Option("Title"), mdb.TEXT, m.Option("URL")) - case chat.LOCATION: - m.Cmdy(chat.LOCATION, mdb.CREATE, mdb.TYPE, "", mdb.NAME, m.Option("Label"), mdb.TEXT, m.Option("Label"), - "latitude", m.Option("LocationX"), "longitude", m.Option("LocationY"), "scale", m.Option("Scale"), - ) + fallthrough + default: + m.Cmdy(chat.FAVOR, mdb.CREATE, mdb.TYPE, m.Option(mdb.TYPE), mdb.NAME, m.Option("Title"), mdb.TEXT, kit.Select(m.Option(mdb.TEXT), m.Option(web.LINK))) } }}, - LOGIN: {Name: "login", Help: "登录", Actions: ice.Actions{ - mdb.CREATE: {Name: "create appid appmm token", Hand: func(m *ice.Message, arg ...string) { m.Cmd(ACCESS, LOGIN, arg) }}, - }}, + LOGIN: {Name: "login list", Help: "登录", Actions: ice.Actions{ + mdb.CREATE: {Hand: func(m *ice.Message, arg ...string) { m.Cmd(ACCESS, mdb.CREATE, arg) }}, + }, Hand: func(m *ice.Message, arg ...string) { m.Cmdy(ACCESS) }}, }) } diff --git a/misc/wx/menu.go b/misc/wx/menu.go index f695c753..6fad515d 100644 --- a/misc/wx/menu.go +++ b/misc/wx/menu.go @@ -4,43 +4,37 @@ import ( ice "shylinux.com/x/icebergs" "shylinux.com/x/icebergs/base/mdb" "shylinux.com/x/icebergs/base/web" - "shylinux.com/x/icebergs/core/wiki" kit "shylinux.com/x/toolkits" ) -func _wx_action(m *ice.Message) (count int) { - m.SetResult().RenderResult() - m.Echo(` - - -%s - -`, m.Option("ToUserName"), m.Option("FromUserName"), m.Option("CreateTime"), "news") - m.Table(func(value ice.Maps) { count++ }) - m.Echo(`%d`, count).Echo(``) - share := m.Cmdx(web.SHARE, mdb.CREATE, mdb.TYPE, web.LOGIN) - m.Table(func(value ice.Maps) { - m.Echo(` -<![CDATA[%s]]> - - - - -`, value[wiki.TITLE], value[wiki.SPARK], value[wiki.IMAGE], kit.MergeURL2(kit.Format(value[wiki.REFER]), "/share/"+share)) - }).Echo(``).Echo(``) - m.Debug("echo: %v", m.Result()) - return -} - +const ( + SCENE = "scene" + RIVER = "river" + STORM = "storm" +) const MENU = "menu" func init() { Index.MergeCommands(ice.Commands{ - MENU: {Name: "menu zone id auto insert", Help: "菜单", Actions: ice.MergeActions(ice.Actions{ - mdb.INSERT: {Name: "insert zone=home title=hi refer=hello image"}, - }, mdb.ZoneAction(mdb.FIELDS, "time,id,title,refer,image")), Hand: func(m *ice.Message, arg ...string) { - if mdb.ZoneSelect(m, arg...); len(arg) > 0 { - _wx_action(m) + MENU: {Name: "menu access hash auto", Help: "菜单", Meta: Meta(), Actions: ice.MergeActions(ice.Actions{ + mdb.CREATE: {Name: "create scene*=main river*=1,2,3 storm*=1,2,3,4,5,6 type*=click,view,scancode_push,scancode_waitmsg,pic_sysphoto,pic_photo_or_album,pic_weixin,location_select name* text icons space index args"}, + mdb.UPDATE: {Name: "update scene*", Hand: func(m *ice.Message, arg ...string) { + list := kit.Dict() + m.Cmd("", m.Option(ACCESS), func(value ice.Maps) { + if value[SCENE] == m.Option(SCENE) { + key := kit.Keys("button", kit.Int(value[RIVER])-1) + kit.If(value[STORM] != "1", func() { key = kit.Keys(key, "sub_button", kit.Int(value[STORM])-2) }) + kit.If(value[mdb.TYPE] == "view", func() { value[mdb.TEXT] = web.MergeLink(m, value[mdb.TEXT]) }) + kit.Value(list, key, kit.Dict(mdb.TYPE, value[mdb.TYPE], mdb.NAME, value[mdb.NAME], mdb.KEY, value[mdb.HASH], web.URL, value[mdb.TEXT])) + } + }) + m.Echo(kit.Formats(SpidePost(m, MENU_CREATE, web.SPIDE_DATA, kit.Formats(list)))) + }}, + }, mdb.ExportHashAction(mdb.SHORT, "scene,river,storm", mdb.FIELD, "time,hash,scene,river,storm,type,name,text,icons,space,index,args")), Hand: func(m *ice.Message, arg ...string) { + if len(arg) == 0 { + m.Cmdy(ACCESS).PushAction("").Option(ice.MSG_ACTION, "") + } else { + mdb.HashSelect(m, arg[1:]...).Sort(mdb.Config(m, mdb.SHORT), ice.STR, ice.INT, ice.INT).Action(mdb.CREATE, mdb.UPDATE) } }}, }) diff --git a/misc/wx/qrcode.go b/misc/wx/qrcode.go new file mode 100644 index 00000000..77fdf4a6 --- /dev/null +++ b/misc/wx/qrcode.go @@ -0,0 +1,31 @@ +package wx + +import ( + ice "shylinux.com/x/icebergs" + "shylinux.com/x/icebergs/base/mdb" + "shylinux.com/x/icebergs/base/web" + kit "shylinux.com/x/toolkits" +) + +const ( + EXPIRE_SECONDS = "expire_seconds" +) +const QRCODE = "qrcode" + +func init() { + Index.MergeCommands(ice.Commands{ + QRCODE: {Name: "qrcode access hash auto", Help: "桌牌", Meta: Meta(), Actions: ice.MergeActions(ice.Actions{ + mdb.CREATE: {Name: "create type=QR_STR_SCENE,QR_LIMIT_STR_SCENE name*=1 text* icons expire_seconds=3600 space index* args", Hand: func(m *ice.Message, arg ...string) { + h := mdb.HashCreate(m.Spawn(), arg) + res := SpidePost(m, QRCODE_CREATE, "action_name", m.Option(mdb.TYPE), "action_info.scene.scene_str", h, m.OptionSimple(EXPIRE_SECONDS)) + mdb.HashModify(m, mdb.HASH, h, mdb.LINK, kit.Value(res, web.URL), mdb.TIME, m.Time(kit.Format("%ss", kit.Select("60", m.Option(EXPIRE_SECONDS))))) + }}, + }, mdb.ExportHashAction(mdb.SHORT, mdb.UNIQ, mdb.FIELD, "time,hash,name,text,icons,space,index,args,type,link")), Hand: func(m *ice.Message, arg ...string) { + if len(arg) == 0 { + m.Cmdy(ACCESS).PushAction("").Option(ice.MSG_ACTION, "") + } else if mdb.HashSelect(m, arg[1:]...); len(arg) > 1 { + kit.If(m.Time() < m.Append(mdb.TIME), func() { m.PushQRCode(QRCODE, m.Append(mdb.LINK)) }) + } + }}, + }) +} diff --git a/misc/wx/text.go b/misc/wx/text.go index f12cd3c3..c76eed5f 100644 --- a/misc/wx/text.go +++ b/misc/wx/text.go @@ -6,35 +6,29 @@ import ( "shylinux.com/x/icebergs/base/ctx" "shylinux.com/x/icebergs/base/mdb" "shylinux.com/x/icebergs/base/nfs" + "shylinux.com/x/icebergs/base/web" kit "shylinux.com/x/toolkits" ) -func _wx_reply(m *ice.Message, tmpl string) { - if res, err := kit.Render(mdb.Config(m, nfs.TEMPLATE), m); err == nil { - m.SetResult().RenderResult(string(res)) - } -} - const TEXT = "text" func init() { Index.MergeCommands(ice.Commands{ - TEXT: {Name: "text", Help: "文本", Actions: ice.MergeActions(ice.Actions{ - MENU: {Name: "menu name=home", Hand: func(m *ice.Message, arg ...string) { m.Cmdy(MENU, m.Option(mdb.NAME)) }}, - }, ctx.ConfAction(nfs.TEMPLATE, text)), Hand: func(m *ice.Message, arg ...string) { - if m.Cmdy(arg); m.IsErrNotFound() { - m.SetResult().Cmdy(cli.SYSTEM, arg) - } - kit.If(m.Result() == "", func() { m.TableEcho() }) - _wx_reply(m, m.CommandKey()) + TEXT: {Help: "文本", Actions: ice.Actions{ + ctx.CMDS: {Hand: func(m *ice.Message, arg ...string) { + msg := m.Cmd(arg) + kit.If(msg.IsErrNotFound(), func() { msg.SetResult().Cmdy(cli.SYSTEM, arg) }) + kit.If(msg.Result() == "", func() { msg.TableEcho() }) + m.Cmdy("", msg.Result()) + }}, + web.LINK: {Name: "link link name text icons", Hand: func(m *ice.Message, arg ...string) { + kit.If(m.Option(mdb.ICONS) == "", func() { m.Option(mdb.ICONS, m.Cmdv(ACCESS, m.Option(ACCESS), mdb.ICONS)) }) + m.Option(mdb.ICONS, web.ShareLocal(m, m.Option(mdb.ICONS))) + m.Cmdy("", m.OptionDefault(mdb.TEXT, "工具系统"), "link.xml") + }}, + }, Hand: func(m *ice.Message, arg ...string) { + m.Echo(nfs.Template(m.Options(mdb.TEXT, arg[0]), kit.Select("welcome.xml", arg, 1))).RenderResult() + m.Debug("text: %v", m.Result()) }}, }) } - -var text = ` - - -{{.Option "CreateTime"}} - - -` diff --git a/misc/wx/users.go b/misc/wx/users.go new file mode 100644 index 00000000..26c61eee --- /dev/null +++ b/misc/wx/users.go @@ -0,0 +1,35 @@ +package wx + +import ( + "time" + + ice "shylinux.com/x/icebergs" + "shylinux.com/x/icebergs/base/aaa" + "shylinux.com/x/icebergs/base/mdb" + kit "shylinux.com/x/toolkits" +) + +const ( + OPENID = "openid" +) +const USERS = "users" + +func init() { + Index.MergeCommands(ice.Commands{ + USERS: {Name: "users access openid auto", Help: "用户", Meta: Meta(), Hand: func(m *ice.Message, arg ...string) { + if len(arg) == 0 { + m.Cmdy(ACCESS).PushAction("").Option(ice.MSG_ACTION, "") + } else if m.Options(ACCESS, arg[0]); len(arg) == 1 { + res := SpideGet(m, USER_GET) + kit.For(kit.Value(res, "data.openid"), func(value string) { + res := SpideGet(m, USER_INFO, OPENID, value) + m.Push(mdb.TIME, time.Unix(kit.Int64(kit.Value(res, "subscribe_time")), 0).Format(ice.MOD_TIME)) + m.Push("", res, []string{OPENID, "sex", aaa.USERNICK, aaa.LANGUAGE, aaa.PROVINCE, aaa.CITY}) + }) + m.StatusTimeCountTotal(kit.Value(res, mdb.TOTAL), mdb.NEXT, kit.Value(res, "next_openid")) + } else { + m.Push(ice.FIELDS_DETAIL, SpideGet(m, USER_INFO, OPENID, arg[1])) + } + }}, + }) +} diff --git a/misc/wx/wx.go b/misc/wx/wx.go index 4e12282a..a208ebc5 100644 --- a/misc/wx/wx.go +++ b/misc/wx/wx.go @@ -8,6 +8,6 @@ import ( const WX = "wx" -var Index = &ice.Context{Name: WX, Help: "公众号"} +var Index = &ice.Context{Name: WX, Help: "微信公众号"} func init() { chat.Index.Register(Index, &web.Frame{}) } diff --git a/misc/wx/wx.shy b/misc/wx/wx.shy index 71200d14..0e415b18 100644 --- a/misc/wx/wx.shy +++ b/misc/wx/wx.shy @@ -2,25 +2,35 @@ title "微信公众号" refer ` 官网 https://weixin.qq.com/ 后台 https://mp.weixin.qq.com/ +测试 https://mp.weixin.qq.com/debug/cgi-bin/sandboxinfo?action=showinfo&t=sandbox/index 文档 https://developers.weixin.qq.com/doc/offiaccount/Getting_Started/Overview.html ` + +chapter "配置" +field web.chat.wx.access +field web.chat.wx.qrcode +field web.chat.wx.menu +field web.chat.wx.users + +chapter "数据" +field web.chat.favor +field web.chat.location +return +order ` +wx.go +wx.shy +access.go +qrcode.go +menu.go +text.go +login.go +events.go +users.go +agent.go +agent.js +` + qrcode `http://weixin.qq.com/r/_B1-Z7TEXOkjrfAE90jq` -chapter "应用" -field "访问" web.chat.wx.access -field "收藏" web.chat.wx.favor -field "菜单" web.chat.wx.menu -field "位置" web.chat.location - -chapter "权限" -field "共享" web.share -field "会话" aaa.sess -field "用户" aaa.user - chapter "企业微信" field "机器人" web.chat.wework.bot - -chapter "项目" -field "源代码" web.code.inner args `usr/icebergs/ misc/wx/login.go` -field "趋势图" web.code.git.trend args `icebergs` -field "架构图" web.code.git.spide args `icebergs`