1
0
mirror of https://shylinux.com/x/icebergs synced 2025-05-01 03:09:21 +08:00
This commit is contained in:
shylinux 2021-07-24 11:22:20 +08:00
parent a3734b31b0
commit f6d6fabb1c
20 changed files with 692 additions and 461 deletions

View File

@ -12,10 +12,9 @@ import (
) )
const ( const (
REDIRECT = "redirect" REFRESH = "refresh"
REFRESH = "refresh" STATUS = "status"
STATUS = "status" COOKIE = "cookie"
COOKIE = "cookie"
) )
func Render(msg *ice.Message, cmd string, args ...interface{}) { func Render(msg *ice.Message, cmd string, args ...interface{}) {
@ -24,7 +23,7 @@ func Render(msg *ice.Message, cmd string, args ...interface{}) {
} }
switch arg := kit.Simple(args...); cmd { switch arg := kit.Simple(args...); cmd {
case REDIRECT: // url [arg...] case ice.RENDER_REDIRECT: // url [arg...]
http.Redirect(msg.W, msg.R, kit.MergeURL(arg[0], arg[1:]), 307) http.Redirect(msg.W, msg.R, kit.MergeURL(arg[0], arg[1:]), 307)
case REFRESH: // [delay [text]] case REFRESH: // [delay [text]]

View File

@ -181,10 +181,10 @@ func init() {
switch msg.Append(kit.MDB_TYPE) { switch msg.Append(kit.MDB_TYPE) {
case LOGIN, RIVER: case LOGIN, RIVER:
m.Render(REDIRECT, "/", list) m.RenderRedirect("/", list)
case STORM: case STORM:
m.Render(REDIRECT, "/page/share.html", SHARE, m.Option(SHARE)) m.RenderRedirect("/page/share.html", SHARE, m.Option(SHARE))
} }
}}, }},

View File

@ -126,8 +126,9 @@ const ( // RENDER
RENDER_VIDEOS = "_videos" RENDER_VIDEOS = "_videos"
RENDER_QRCODE = "_qrcode" RENDER_QRCODE = "_qrcode"
RENDER_SCRIPT = "_script" RENDER_SCRIPT = "_script"
RENDER_DOWNLOAD = "_download"
RENDER_TEMPLATE = "_template" RENDER_TEMPLATE = "_template"
RENDER_DOWNLOAD = "_download"
RENDER_REDIRECT = "_redirect"
) )
const ( // PROCESS const ( // PROCESS
PROCESS_REFRESH = "_refresh" PROCESS_REFRESH = "_refresh"

View File

@ -257,9 +257,7 @@ func (m *Message) Render(cmd string, args ...interface{}) *Message {
if len(args) == 1 { if len(args) == 1 {
args = append(args, m) args = append(args, m)
} }
m.Debug("what %v", args)
if res, err := kit.Render(args[0].(string), args[1]); m.Assert(err) { if res, err := kit.Render(args[0].(string), args[1]); m.Assert(err) {
m.Debug("what")
m.Echo(string(res)) m.Echo(string(res))
} }
} }
@ -274,6 +272,12 @@ func (m *Message) RenderTemplate(args ...interface{}) *Message {
func (m *Message) RenderDownload(args ...interface{}) *Message { func (m *Message) RenderDownload(args ...interface{}) *Message {
return m.Render(RENDER_DOWNLOAD, args...) return m.Render(RENDER_DOWNLOAD, args...)
} }
func (m *Message) RenderRedirect(args ...interface{}) *Message {
return m.Render(RENDER_REDIRECT, args...)
}
func (m *Message) RenderIndex(serve, repos string) *Message {
return m.RenderDownload(path.Join(m.Conf(serve, kit.Keym(repos, kit.SSH_PATH)), m.Conf(serve, kit.Keym(repos, kit.SSH_INDEX))))
}
type Sort struct { type Sort struct {
Fields string Fields string

55
misc/lark/app.go Normal file
View File

@ -0,0 +1,55 @@
package lark
import (
"time"
ice "github.com/shylinux/icebergs"
"github.com/shylinux/icebergs/base/mdb"
"github.com/shylinux/icebergs/base/web"
kit "github.com/shylinux/toolkits"
)
const (
LOGIN = "login"
APPID = "appid"
APPMM = "appmm"
TOKEN = "token"
EXPIRE = "expire"
)
const APP = "app"
func init() {
Index.Merge(&ice.Context{
Configs: map[string]*ice.Config{
APP: {Name: APP, Help: "服务配置", Value: kit.Data(
kit.MDB_SHORT, APPID, kit.MDB_FIELD, "time,appid,appmm,duty,token,expire",
LARK, "https://open.feishu.cn/",
)},
},
Commands: map[string]*ice.Command{
ice.CTX_INIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
m.Cmd(web.SPIDE, mdb.CREATE, LARK, m.Conf(APP, kit.Keym(LARK)))
}},
APP: {Name: "app appid auto token login", Help: "应用", Action: map[string]*ice.Action{
LOGIN: {Name: "login appid appmm duty", Help: "登录", Hand: func(m *ice.Message, arg ...string) {
m.Cmdy(mdb.INSERT, m.Prefix(APP), "", mdb.HASH, arg)
}},
TOKEN: {Name: "token appid", Help: "令牌", Hand: func(m *ice.Message, arg ...string) {
msg := m.Cmd(APP, m.Option(APPID))
if now := time.Now().Unix(); msg.Append(TOKEN) == "" || now > kit.Int64(msg.Append(EXPIRE)) {
sub := m.Cmd(web.SPIDE, LARK, web.SPIDE_POST, "/open-apis/auth/v3/tenant_access_token/internal/",
APP_ID, msg.Append(APPID), "app_secret", msg.Append(APPMM))
m.Cmd(mdb.MODIFY, m.Prefix(APP), "", mdb.HASH, m.OptionSimple(APPID),
TOKEN, sub.Append("tenant_access_token"), EXPIRE, now+kit.Int64(sub.Append(EXPIRE)))
msg.Append(TOKEN, sub.Append("tenant_access_token"))
}
m.Echo(msg.Append(TOKEN))
}},
}, Hand: func(m *ice.Message, c *ice.Context, key string, arg ...string) {
m.Fields(len(arg) == 0, m.Conf(APP, kit.META_FIELD))
m.Cmdy(mdb.SELECT, m.Prefix(APP), "", mdb.HASH, APPID, arg)
}},
},
})
}

61
misc/lark/company.go Normal file
View File

@ -0,0 +1,61 @@
package lark
import (
ice "github.com/shylinux/icebergs"
"github.com/shylinux/icebergs/base/aaa"
kit "github.com/shylinux/toolkits"
)
func _company_list(m *ice.Message, appid string) {
_, data := _lark_get(m, appid, "/open-apis/contact/v1/scope/get/")
kit.Fetch(kit.Value(data, "data.authed_departments"), func(index int, ship_id string) {
_, data := _lark_get(m, appid, "/open-apis/contact/v1/department/detail/batch_get", "department_ids", ship_id)
kit.Fetch(kit.Value(data, "data.department_infos"), func(index int, value map[string]interface{}) {
m.Push(SHIP_ID, ship_id)
m.Push(kit.MDB_NAME, value[kit.MDB_NAME])
m.Push(kit.MDB_COUNT, value["member_count"])
m.Push(CHAT_ID, value[CHAT_ID])
})
})
m.Sort(kit.MDB_NAME)
}
func _company_members(m *ice.Message, appid string, ship_id string) {
_, data := _lark_get(m, appid, "/open-apis/contact/v1/department/user/list",
"department_id", ship_id, "page_size", "100", "fetch_child", "true")
kit.Fetch(kit.Value(data, "data.user_list"), func(index int, value map[string]interface{}) {
msg := m.Cmd(EMPLOYEE, appid, value[OPEN_ID])
m.PushImages(aaa.AVATAR, msg.Append("avatar_72"))
m.Push(aaa.GENDER, kit.Select("女", "男", msg.Append(aaa.GENDER) == "1"))
m.Push(kit.MDB_NAME, msg.Append(kit.MDB_NAME))
m.Push(kit.MDB_TEXT, msg.Append("description"))
m.Push(OPEN_ID, msg.Append(OPEN_ID))
})
m.Sort(kit.MDB_NAME)
}
const COMPANY = "company"
func init() {
Index.Merge(&ice.Context{Commands: map[string]*ice.Command{
COMPANY: {Name: "company appid ship_id open_id text auto", Help: "组织", Hand: func(m *ice.Message, c *ice.Context, key string, arg ...string) {
switch len(arg) {
case 0: // 应用列表
m.Cmdy(APP)
case 1: // 组织列表
_company_list(m, arg[0])
case 2: // 员工列表
_company_members(m, arg[0], arg[1])
case 3: // 员工详情
m.Cmdy(EMPLOYEE, arg[0], arg[2])
default: // 员工通知
m.Cmdy(SEND, arg[0], OPEN_ID, arg[2], arg[3:])
}
}},
}})
}

21
misc/lark/duty.go Normal file
View File

@ -0,0 +1,21 @@
package lark
import (
ice "github.com/shylinux/icebergs"
)
const DUTY = "duty"
func init() {
Index.Merge(&ice.Context{Commands: map[string]*ice.Command{
DUTY: {Name: "duty appid [title] text auto", Help: "通告", Hand: func(m *ice.Message, c *ice.Context, key string, arg ...string) {
if len(arg) < 2 {
m.Cmdy(APP)
return
}
duty := m.Cmd(APP, arg[0]).Append(DUTY)
m.Cmdy(SEND, arg[0], duty, arg[1:])
}},
}})
}

46
misc/lark/employee.go Normal file
View File

@ -0,0 +1,46 @@
package lark
import (
"strings"
ice "github.com/shylinux/icebergs"
"github.com/shylinux/icebergs/base/mdb"
kit "github.com/shylinux/toolkits"
)
func _employee_info(m *ice.Message, appid string, arg ...string) {
for _, id := range arg {
_, data := _lark_get(m, appid, "/open-apis/contact/v1/user/batch_get", "open_ids", id)
kit.Fetch(kit.Value(data, "data.user_infos"), func(index int, value map[string]interface{}) {
m.Push(mdb.DETAIL, value)
})
}
}
func _employee_openid(m *ice.Message, appid string, arg ...string) {
us := []string{}
for i := 0; i < len(arg); i++ {
us = append(us, kit.Select("mobiles", "emails", strings.Contains(arg[i], "@")), arg[i])
}
_lark_get(m, appid, "/open-apis/user/v1/batch_get_id", us)
for i := 0; i < len(arg); i++ {
m.Echo(m.Append(kit.Keys("data.mobile_users", arg[i], "0.open_id")))
}
}
const EMPLOYEE = "employee"
func init() {
Index.Merge(&ice.Context{Commands: map[string]*ice.Command{
EMPLOYEE: {Name: "employee appid open_id|mobile|email auto", Help: "员工", Hand: func(m *ice.Message, c *ice.Context, key string, arg ...string) {
if len(arg) < 2 {
return
}
if strings.HasPrefix(arg[1], "ou_") {
_employee_info(m, arg[0], arg[1:]...)
} else {
_employee_openid(m, arg[0], arg[1:]...)
}
}},
}})
}

38
misc/lark/event.go Normal file
View File

@ -0,0 +1,38 @@
package lark
import (
ice "github.com/shylinux/icebergs"
kit "github.com/shylinux/toolkits"
)
const (
P2P_CHAT_CREATE = "p2p_chat_create"
MESSAGE_READ = "message_read"
CHAT_DISBAND = "chat_disband"
ADD_BOT = "add_bot"
MSG_TYPE = "msg_type"
)
const EVENT = "event"
func init() {
Index.Merge(&ice.Context{Commands: map[string]*ice.Command{
EVENT: {Name: "event", Help: "事件", Action: map[string]*ice.Action{
P2P_CHAT_CREATE: {Name: "", Help: "", Hand: func(m *ice.Message, arg ...string) {
if m.Options(OPEN_CHAT_ID) {
m.Cmdy(SEND, m.Option(APP_ID), m.Option(OPEN_CHAT_ID), m.Conf(APP, kit.Keym(kit.MDB_TEMPLATE, m.Option(kit.MDB_TYPE))))
}
}},
MESSAGE_READ: {Name: "", Help: "", Hand: func(m *ice.Message, arg ...string) {
}},
CHAT_DISBAND: {Name: "", Help: "", Hand: func(m *ice.Message, arg ...string) {
}},
ADD_BOT: {Name: "", Help: "", Hand: func(m *ice.Message, arg ...string) {
if m.Options(OPEN_CHAT_ID) {
m.Cmdy(SEND, m.Option(APP_ID), m.Option(OPEN_CHAT_ID), m.Conf(APP, kit.Keym(kit.MDB_TEMPLATE, m.Option(kit.MDB_TYPE))))
}
}},
}, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
m.Cmdy(MSG, m.Option(MSG_TYPE))
}},
}})
}

78
misc/lark/form.go Normal file
View File

@ -0,0 +1,78 @@
package lark
import (
ice "github.com/shylinux/icebergs"
"github.com/shylinux/icebergs/base/aaa"
"github.com/shylinux/icebergs/base/web"
kit "github.com/shylinux/toolkits"
)
const FORM = "form"
func init() {
Index.Merge(&ice.Context{Commands: map[string]*ice.Command{
FORM: {Name: "form [chat_id|open_id|user_id|email] target title text [confirm|value|url arg...]...", Help: "消息", Hand: func(m *ice.Message, c *ice.Context, key string, arg ...string) {
var form = kit.Dict(CONTENT, kit.Dict())
switch arg[0] {
case CHAT_ID, OPEN_ID, USER_ID, aaa.EMAIL:
form[arg[0]], arg = arg[1], arg[2:]
default:
form[CHAT_ID], arg = arg[0], arg[1:]
}
elements := []interface{}{}
elements = append(elements, kit.Dict(
"tag", "div", "text", kit.Dict(
"tag", "plain_text", CONTENT, kit.Select(" ", arg[1]),
),
))
actions := []interface{}{}
for i := 2; i < len(arg); i++ {
button := kit.Dict(
"tag", "button", "type", "default", "text", kit.Dict(
"tag", "plain_text", CONTENT, kit.Select(" ", arg[i]),
),
)
content := arg[i]
switch arg[i+1] {
case "confirm":
button[arg[i+1]], i = kit.Dict(
"title", kit.Dict("tag", "lark_md", CONTENT, arg[i+2]),
"text", kit.Dict("tag", "lark_md", CONTENT, arg[i+3]),
), i+3
case "value":
button[arg[i+1]], i = kit.Dict(arg[i+2], arg[i+3]), i+3
case "url":
button[arg[i+1]], i = arg[i+2], i+2
default:
button["value"], i = kit.Dict(
ice.MSG_RIVER, m.Option(ice.MSG_RIVER),
ice.MSG_STORM, m.Option(ice.MSG_STORM),
arg[i+1], arg[i+2],
), i+2
}
kit.Value(button, "value.content", content)
kit.Value(button, "value.open_chat_id", m.Option(OPEN_CHAT_ID))
kit.Value(button, "value.description", arg[1])
kit.Value(button, "value.title", arg[0])
actions = append(actions, button)
}
elements = append(elements, kit.Dict("tag", "action", "actions", actions))
kit.Value(form, "msg_type", "interactive")
kit.Value(form, "card", kit.Dict(
"config", kit.Dict("wide_screen_mode", true),
"header", kit.Dict(
"title", kit.Dict("tag", "lark_md", CONTENT, arg[0]),
),
"elements", elements,
))
msg := _lark_post(m, m.Option(APP_ID), "/open-apis/message/v4/send/", web.SPIDE_DATA, kit.Formats(form))
m.Debug("%v", msg.Optionv(web.SPIDE_RES))
}},
}})
}

56
misc/lark/group.go Normal file
View File

@ -0,0 +1,56 @@
package lark
import (
ice "github.com/shylinux/icebergs"
"github.com/shylinux/icebergs/base/aaa"
kit "github.com/shylinux/toolkits"
)
func _group_list(m *ice.Message, appid string) {
_, data := _lark_get(m, appid, "/open-apis/chat/v4/list")
kit.Fetch(kit.Value(data, "data.groups"), func(index int, value map[string]interface{}) {
m.Push(CHAT_ID, value[CHAT_ID])
m.PushImages(aaa.AVATAR, kit.Format(value[aaa.AVATAR]), "72")
m.Push(kit.MDB_NAME, value[kit.MDB_NAME])
m.Push(kit.MDB_TEXT, value["description"])
m.Push(OPEN_ID, value["owner_open_id"])
})
m.Sort(kit.MDB_NAME)
}
func _group_members(m *ice.Message, appid string, chat_id string) {
_, data := _lark_get(m, appid, "/open-apis/chat/v4/info", "chat_id", chat_id)
kit.Fetch(kit.Value(data, "data.members"), func(index int, value map[string]interface{}) {
msg := m.Cmd(EMPLOYEE, appid, value[OPEN_ID])
m.PushImages(aaa.AVATAR, msg.Append("avatar_72"))
m.Push(aaa.GENDER, kit.Select("女", "男", msg.Append(aaa.GENDER) == "1"))
m.Push(kit.MDB_NAME, msg.Append(kit.MDB_NAME))
m.Push(kit.MDB_TEXT, msg.Append("description"))
m.Push(OPEN_ID, msg.Append(OPEN_ID))
})
m.Sort(kit.MDB_NAME)
}
const GROUP = "group"
func init() {
Index.Merge(&ice.Context{Commands: map[string]*ice.Command{
GROUP: {Name: "group appid chat_id open_id text auto", Help: "群组", Hand: func(m *ice.Message, c *ice.Context, key string, arg ...string) {
switch len(arg) {
case 0: // 应用列表
m.Cmdy(APP)
case 1: // 群组列表
_group_list(m, arg[0])
case 2: // 组员列表
_group_members(m, arg[0], arg[1])
case 3: // 组员详情
m.Cmdy(EMPLOYEE, arg[0], arg[2])
default: // 组员通知
m.Cmdy(SEND, arg[0], OPEN_ID, arg[2], arg[3:])
}
}},
}})
}

40
misc/lark/home.go Normal file
View File

@ -0,0 +1,40 @@
package lark
import (
ice "github.com/shylinux/icebergs"
"github.com/shylinux/icebergs/base/web"
"github.com/shylinux/icebergs/core/chat"
kit "github.com/shylinux/toolkits"
)
const HOME = "home"
func init() {
Index.Merge(&ice.Context{Commands: map[string]*ice.Command{
HOME: {Name: "home river storm title content", Help: "首页", Hand: func(m *ice.Message, c *ice.Context, key string, arg ...string) {
name := kit.Select(m.Option(ice.MSG_USERNAME), m.Option(ice.MSG_USERNICK))
if len(name) > 10 {
name = name[:10]
}
name += "的" + kit.Select("应用列表", arg, 2)
text, link, list := kit.Select("", arg, 3), kit.MergeURL2(m.Conf(web.SHARE, kit.Keym(kit.MDB_DOMAIN)), "/chat/lark/sso"), []string{}
if len(arg) == 0 {
m.Cmd("web.chat./river").Table(func(index int, val map[string]string, head []string) {
m.Cmd("web.chat./river", val[kit.MDB_HASH], chat.TOOL).Table(func(index int, value map[string]string, head []string) {
list = append(list, kit.Keys(val[kit.MDB_NAME], value[kit.MDB_NAME]),
kit.SSH_CMD, kit.Format([]string{HOME, val[kit.MDB_HASH], value[kit.MDB_HASH], val[kit.MDB_NAME] + "." + value[kit.MDB_NAME]}))
})
})
} else {
m.Option(ice.MSG_RIVER, arg[0])
m.Option(ice.MSG_STORM, arg[1])
link = kit.MergeURL(link, chat.RIVER, arg[0], chat.STORM, arg[1])
m.Cmd("web.chat./river", arg[0], chat.TOOL, arg[1]).Table(func(index int, value map[string]string, head []string) {
list = append(list, value[kit.SSH_CMD], kit.SSH_CMD, kit.Keys(value[kit.SSH_CTX], value[kit.SSH_CMD]))
})
}
m.Cmd(FORM, CHAT_ID, m.Option(OPEN_CHAT_ID), name, text, "打开网页", "url", link, list)
}},
}})
}

View File

@ -2,468 +2,20 @@ package lark
import ( import (
ice "github.com/shylinux/icebergs" ice "github.com/shylinux/icebergs"
"github.com/shylinux/icebergs/base/aaa"
"github.com/shylinux/icebergs/base/cli"
"github.com/shylinux/icebergs/base/mdb"
"github.com/shylinux/icebergs/base/web" "github.com/shylinux/icebergs/base/web"
"github.com/shylinux/icebergs/core/chat" "github.com/shylinux/icebergs/core/chat"
"github.com/shylinux/icebergs/core/wiki"
kit "github.com/shylinux/toolkits"
"encoding/json"
"math/rand"
"net/http"
"strings"
"time"
)
func _lark_get(m *ice.Message, bot string, arg ...interface{}) (*ice.Message, interface{}) {
m.Option(web.SPIDE_HEADER, "Authorization", "Bearer "+m.Cmdx(APP, TOKEN, bot), web.ContentType, web.ContentJSON)
msg := m.Cmd(web.SPIDE, LARK, http.MethodGet, arg)
return msg, msg.Optionv(web.SPIDE_RES)
}
func _lark_post(m *ice.Message, bot string, arg ...interface{}) *ice.Message {
m.Option(web.SPIDE_HEADER, "Authorization", "Bearer "+m.Cmdx(APP, TOKEN, bot), web.ContentType, web.ContentJSON)
return m.Cmd(web.SPIDE, LARK, arg)
}
func _lark_parse(m *ice.Message) {
data := m.Optionv(ice.MSG_USERDATA)
if data == nil {
json.NewDecoder(m.R.Body).Decode(&data)
m.Optionv(ice.MSG_USERDATA, data)
switch d := data.(type) {
case map[string]interface{}:
for k, v := range d {
switch d := v.(type) {
case map[string]interface{}:
for k, v := range d {
m.Add(ice.MSG_OPTION, k, kit.Format(v))
}
default:
for _, v := range kit.Simple(v) {
m.Add(ice.MSG_OPTION, kit.Keys("msg", k), kit.Format(v))
}
}
}
}
}
m.Debug("msg: %v", kit.Format(data))
}
const (
P2P_CHAT_CREATE = "p2p_chat_create"
ADD_BOT = "add_bot"
)
const (
SHIP_ID = "ship_id"
OPEN_ID = "open_id"
CHAT_ID = "chat_id"
OPEN_CHAT_ID = "open_chat_id"
USER_OPEN_ID = "user_open_id"
)
const (
LOGIN = "login"
APPID = "appid"
APPMM = "appmm"
TOKEN = "token"
EXPIRE = "expire"
)
const (
APP = "app"
COMPANY = "company"
EMPLOYEE = "employee"
GROUP = "group"
SEND = "send"
DUTY = "duty"
HOME = "home"
FORM = "form"
TALK = "talk"
RAND = "rand"
) )
const LARK = "lark" const LARK = "lark"
var Index = &ice.Context{Name: LARK, Help: "机器人", var Index = &ice.Context{Name: LARK, Help: "机器人",
Configs: map[string]*ice.Config{
APP: {Name: APP, Help: "服务配置", Value: kit.Data(kit.MDB_SHORT, kit.MDB_NAME,
LARK, "https://open.feishu.cn", DUTY, "", kit.MDB_TEMPLATE, kit.Dict(
ADD_BOT, "我来也~", P2P_CHAT_CREATE, "让我们做好朋友吧~",
),
)},
COMPANY: {Name: COMPANY, Help: "组织配置", Value: kit.Data(kit.MDB_SHORT, SHIP_ID)},
EMPLOYEE: {Name: EMPLOYEE, Help: "员工配置", Value: kit.Data(kit.MDB_SHORT, OPEN_ID)},
},
Commands: map[string]*ice.Command{ Commands: map[string]*ice.Command{
ice.CTX_INIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { ice.CTX_INIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
m.Load() m.Load()
m.Cmd(web.SPIDE, mdb.CREATE, LARK, m.Conf(APP, kit.Keym(LARK)))
}}, }},
ice.CTX_EXIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { ice.CTX_EXIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
m.Save() m.Save()
}}, }},
APP: {Name: "app name auto token login", Help: "应用", Action: map[string]*ice.Action{
LOGIN: {Name: "login name appid appmm", Help: "登录", Hand: func(m *ice.Message, arg ...string) {
m.Cmdy(mdb.INSERT, m.Prefix(APP), "", mdb.HASH, arg)
}},
TOKEN: {Name: "token name", Help: "令牌", Hand: func(m *ice.Message, arg ...string) {
m.Option(mdb.FIELDS, "time,appid,appmm,token,expire")
msg := m.Cmd(mdb.SELECT, m.Prefix(APP), "", mdb.HASH, kit.MDB_NAME, m.Option(kit.MDB_NAME))
if now := time.Now().Unix(); msg.Append(TOKEN) == "" || now > kit.Int64(msg.Append(EXPIRE)) {
sub := m.Cmd(web.SPIDE, LARK, "/open-apis/auth/v3/tenant_access_token/internal/",
"app_id", msg.Append(APPID), "app_secret", msg.Append(APPMM))
m.Cmd(mdb.MODIFY, m.Prefix(APP), "", mdb.HASH, kit.MDB_NAME, m.Option(kit.MDB_NAME),
TOKEN, msg.Append(TOKEN, sub.Append("tenant_access_token")), EXPIRE, now+kit.Int64(sub.Append(EXPIRE)))
}
m.Echo(msg.Append(TOKEN))
}},
}, Hand: func(m *ice.Message, c *ice.Context, key string, arg ...string) {
m.Option(mdb.FIELDS, kit.Select("time,name,appid,token,expire", mdb.DETAIL, len(arg) > 0))
m.Cmdy(mdb.SELECT, m.Prefix(APP), "", mdb.HASH, kit.MDB_NAME, arg)
}},
COMPANY: {Name: "company ship_id open_id text auto", Help: "组织", Action: map[string]*ice.Action{
"info": {Name: "info ship_id", Hand: func(m *ice.Message, arg ...string) {
_, data := _lark_get(m, "bot", "/open-apis/contact/v1/department/detail/batch_get", "department_ids", m.Option(SHIP_ID))
kit.Fetch(kit.Value(data, "data.department_infos"), func(index int, value map[string]interface{}) {
m.Push("", value)
})
}},
"list": {Name: "list ship_id", Hand: func(m *ice.Message, arg ...string) {
_, data := _lark_get(m, "bot", "/open-apis/contact/v1/department/user/list",
"department_id", m.Option(SHIP_ID), "page_size", "100", "fetch_child", "true")
kit.Fetch(kit.Value(data, "data.user_list"), func(index int, value map[string]interface{}) {
msg := m.Cmd(EMPLOYEE, value[OPEN_ID])
m.PushImages(aaa.AVATAR, msg.Append("avatar_72"))
m.Push(aaa.GENDER, kit.Select("女", "男", msg.Append(aaa.GENDER) == "1"))
m.Push(kit.MDB_NAME, msg.Append(kit.MDB_NAME))
m.Push(kit.MDB_TEXT, msg.Append("description"))
m.Push(OPEN_ID, msg.Append(OPEN_ID))
})
}},
}, Hand: func(m *ice.Message, c *ice.Context, key string, arg ...string) {
if len(arg) == 0 { // 组织列表
_, data := _lark_get(m, "bot", "/open-apis/contact/v1/scope/get/")
kit.Fetch(kit.Value(data, "data.authed_departments"), func(index int, value string) {
m.Push(SHIP_ID, value)
msg := m.Cmd(COMPANY, "info", value)
m.Push(kit.MDB_NAME, msg.Append(kit.MDB_NAME))
m.Push(kit.MDB_COUNT, msg.Append("member_count"))
m.Push(CHAT_ID, msg.Append(CHAT_ID))
})
m.Sort(kit.MDB_NAME)
} else if len(arg) == 1 { // 员工列表
m.Cmdy(COMPANY, "list", arg[0])
} else if len(arg) == 2 { // 员工详情
m.Cmdy(EMPLOYEE, arg[1])
} else { // 员工通知
m.Cmdy(SEND, OPEN_ID, arg[1], arg[2:])
}
}},
EMPLOYEE: {Name: "employee open_id|mobile|email auto", Help: "员工", Hand: func(m *ice.Message, c *ice.Context, key string, arg ...string) {
if len(arg) == 0 {
return
}
if strings.HasPrefix(arg[0], "ou_") {
_, data := _lark_get(m, "bot", "/open-apis/contact/v1/user/batch_get", "open_ids", arg[0])
kit.Fetch(kit.Value(data, "data.user_infos"), func(index int, value map[string]interface{}) {
m.Push(mdb.DETAIL, value)
})
return
}
us := []string{}
for i := 0; i < len(arg); i++ {
us = append(us, kit.Select("mobiles", "emails", strings.Contains(arg[i], "@")), arg[i])
}
_lark_get(m, "bot", "/open-apis/user/v1/batch_get_id", us)
for i := 0; i < len(arg); i++ {
m.Echo(m.Append(kit.Keys("data.mobile_users", arg[i], "0.open_id")))
}
}},
GROUP: {Name: "group chat_id open_id text auto", Help: "群组", Action: map[string]*ice.Action{
"list": {Name: "list chat_id", Hand: func(m *ice.Message, arg ...string) {
_, data := _lark_get(m, "bot", "/open-apis/chat/v4/info", "chat_id", m.Option(CHAT_ID))
kit.Fetch(kit.Value(data, "data.members"), func(index int, value map[string]interface{}) {
msg := m.Cmd(EMPLOYEE, value[OPEN_ID])
m.PushImages(aaa.AVATAR, msg.Append("avatar_72"))
m.Push(aaa.GENDER, kit.Select("女", "男", msg.Append(aaa.GENDER) == "1"))
m.Push(kit.MDB_NAME, msg.Append(kit.MDB_NAME))
m.Push(kit.MDB_TEXT, msg.Append("description"))
m.Push(OPEN_ID, msg.Append(OPEN_ID))
})
}},
}, Hand: func(m *ice.Message, c *ice.Context, key string, arg ...string) {
if len(arg) == 0 { // 群组列表
_, data := _lark_get(m, "bot", "/open-apis/chat/v4/list")
kit.Fetch(kit.Value(data, "data.groups"), func(index int, value map[string]interface{}) {
m.Push(CHAT_ID, value[CHAT_ID])
m.PushImages(aaa.AVATAR, kit.Format(value[aaa.AVATAR]), "72")
m.Push(kit.MDB_NAME, value[kit.MDB_NAME])
m.Push(kit.MDB_TEXT, value["description"])
m.Push(OPEN_ID, value["owner_open_id"])
})
m.Sort(kit.MDB_NAME)
} else if len(arg) == 1 { // 组员列表
m.Cmdy(GROUP, "list", arg[0])
} else if len(arg) == 2 { // 组员详情
m.Cmdy(EMPLOYEE, arg[1])
} else { // 组员通知
m.Cmdy(SEND, CHAT_ID, arg[0], arg[2:])
}
}},
SEND: {Name: "send [chat_id|open_id|user_id|email] target [title] text", Help: "消息", Hand: func(m *ice.Message, c *ice.Context, key string, arg ...string) {
var form = kit.Dict("content", kit.Dict())
switch arg[0] {
case CHAT_ID, OPEN_ID, "user_id", "email":
form[arg[0]], arg = arg[1], arg[2:]
default:
form[CHAT_ID], arg = arg[0], arg[1:]
}
switch len(arg) {
case 0:
case 1:
kit.Value(form, "msg_type", "text")
kit.Value(form, "content.text", arg[0])
if strings.TrimSpace(arg[0]) == "" {
return
}
default:
if len(arg) == 2 && strings.TrimSpace(arg[1]) == "" {
return
}
content := []interface{}{}
line := []interface{}{}
for _, v := range arg[1:] {
if v == "\n" {
content, line = append(content, line), []interface{}{}
continue
}
line = append(line, map[string]interface{}{"tag": "text", "text": v + " "})
}
content = append(content, line)
kit.Value(form, "msg_type", "post")
kit.Value(form, "content.post", map[string]interface{}{
"zh_cn": map[string]interface{}{"title": arg[0], "content": content},
})
}
m.Copy(_lark_post(m, "bot", "/open-apis/message/v4/send/", web.SPIDE_DATA, kit.Format(form)))
}},
DUTY: {Name: "duty [title] text", Help: "通告", Hand: func(m *ice.Message, c *ice.Context, key string, arg ...string) {
m.Cmdy(SEND, m.Conf(APP, kit.Keym(DUTY)), arg)
}},
HOME: {Name: "home river storm title", Help: "首页", Hand: func(m *ice.Message, c *ice.Context, key string, arg ...string) {
name := kit.Select(m.Option(ice.MSG_USERNAME), m.Option(ice.MSG_USERNICK))
if len(name) > 10 {
name = name[:10]
}
name += "的" + kit.Select("应用列表", arg, 2)
text := ""
link, list := m.Conf(web.SHARE, "meta.domain"), []string{}
if len(arg) == 0 {
m.Cmd("web.chat./river").Table(func(index int, val map[string]string, head []string) {
m.Cmd("web.chat./river", val[kit.MDB_HASH], chat.TOOL).Table(func(index int, value map[string]string, head []string) {
list = append(list, kit.Keys(val[kit.MDB_NAME], value[kit.MDB_NAME]),
kit.SSH_CMD, kit.Format([]string{"home", val[kit.MDB_HASH], value[kit.MDB_HASH], val[kit.MDB_NAME] + "." + value[kit.MDB_NAME]}))
})
})
} else {
m.Option(ice.MSG_RIVER, arg[0])
m.Option(ice.MSG_STORM, arg[1])
link = kit.MergeURL(link, chat.RIVER, arg[0], chat.STORM, arg[1])
m.Cmd("web.chat./river", arg[0], chat.TOOL, arg[1]).Table(func(index int, value map[string]string, head []string) {
list = append(list, value[kit.SSH_CMD], kit.SSH_CMD, kit.Keys(value[kit.SSH_CTX], value[kit.SSH_CMD]))
})
}
m.Cmd(FORM, CHAT_ID, m.Option(OPEN_CHAT_ID), name, text, "打开网页", "url", link, list)
}},
FORM: {Name: "form chat_id|open_id|user_id|email target title text [confirm|value|url arg...]...", Help: "消息", Hand: func(m *ice.Message, c *ice.Context, key string, arg ...string) {
var form = map[string]interface{}{"content": map[string]interface{}{}}
switch arg[0] {
case CHAT_ID, OPEN_ID, "user_id", "email":
form[arg[0]], arg = arg[1], arg[2:]
default:
form[CHAT_ID], arg = arg[0], arg[1:]
}
elements := []interface{}{}
elements = append(elements, map[string]interface{}{
"tag": "div", "text": map[string]interface{}{
"tag": "plain_text", "content": arg[1],
},
})
actions := []interface{}{}
for i := 2; i < len(arg); i++ {
button := map[string]interface{}{
"type": "default", "tag": "button", "text": map[string]interface{}{
"tag": "plain_text", "content": arg[i],
},
}
content := arg[i]
switch arg[i+1] {
case "confirm":
button[arg[i+1]], i = map[string]interface{}{
"title": map[string]interface{}{"tag": "lark_md", "content": arg[i+2]},
"text": map[string]interface{}{"tag": "lark_md", "content": arg[i+3]},
}, i+3
case "value":
button[arg[i+1]], i = map[string]interface{}{arg[i+2]: arg[i+3]}, i+3
case "url":
button[arg[i+1]], i = arg[i+2], i+2
default:
button["value"], i = map[string]interface{}{
arg[i+1]: arg[i+2],
ice.MSG_RIVER: m.Option(ice.MSG_RIVER),
ice.MSG_STORM: m.Option(ice.MSG_STORM),
}, i+2
}
kit.Value(button, "value.content", content)
kit.Value(button, "value.open_chat_id", m.Option(OPEN_CHAT_ID))
kit.Value(button, "value.description", arg[1])
kit.Value(button, "value.title", arg[0])
actions = append(actions, button)
}
elements = append(elements, map[string]interface{}{"tag": "action", "actions": actions})
kit.Value(form, "msg_type", "interactive")
kit.Value(form, "card", map[string]interface{}{
"config": map[string]interface{}{"wide_screen_mode": true},
"header": map[string]interface{}{
"title": map[string]interface{}{"tag": "lark_md", "content": arg[0]},
},
"elements": elements,
})
_lark_post(m, "bot", "/open-apis/message/v4/send/", web.SPIDE_DATA, kit.Formats(form))
}},
TALK: {Name: "talk text", Help: "聊天", Hand: func(m *ice.Message, c *ice.Context, key string, arg ...string) {
m.Option(ice.MSG_USERZONE, LARK)
cmds := kit.Split(strings.Join(arg, " "))
if aaa.UserLogin(m, m.Option(OPEN_ID), ""); !m.Right(cmds) {
if aaa.UserLogin(m, m.Option(OPEN_CHAT_ID), ""); !m.Right(cmds) {
m.Cmd(DUTY, m.Option(OPEN_CHAT_ID), m.Option("text_without_at_bot"))
m.Cmd(HOME)
return // 没有权限
}
}
if cmds[0] == HOME {
m.Cmd(HOME, cmds[1:])
return // 没有命令
}
// 执行命令
if msg := m.Cmd(cmds); len(msg.Appendv(ice.MSG_APPEND)) > 0 || len(msg.Resultv()) > 0 {
if m.Copy(msg); len(m.Resultv()) == 0 {
m.Table()
}
} else {
m.Cmdy(cli.SYSTEM, cmds)
}
}},
RAND: {Name: "rand", Help: "随机", Hand: func(m *ice.Message, c *ice.Context, key string, arg ...string) {
msg := m.Cmd(GROUP, EMPLOYEE, m.Option(OPEN_CHAT_ID))
list := msg.Appendv("name")
if strings.Contains(m.Option("content"), "誰") {
m.Echo(strings.Replace(m.Option("content"), "誰", list[rand.Intn(len(list))], 1))
return
}
m.Echo(list[rand.Intn(len(list))])
}},
web.WEB_LOGIN: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {}},
"/msg": {Name: "/msg", Help: "聊天消息", Hand: func(m *ice.Message, c *ice.Context, key string, arg ...string) {
data := m.Optionv(ice.MSG_USERDATA)
if kit.Value(data, "action") != nil {
m.Option(ice.MSG_USERUA, "")
kit.Fetch(kit.Value(data, "action.value"), func(key string, value string) { m.Option(key, value) })
m.Cmdy(TALK, kit.Parse(nil, "", kit.Split(m.Option(kit.SSH_CMD))...))
m.Cmd(SEND, CHAT_ID, m.Option(OPEN_CHAT_ID), m.Option(wiki.TITLE)+" "+m.Option(kit.SSH_CMD), m.Result())
return
}
switch _lark_parse(m); m.Option("msg.type") {
case "url_verification": // 绑定验证
m.Render(ice.RENDER_RESULT, kit.Format(kit.Dict("challenge", m.Option("msg.challenge"))))
case "event_callback":
switch m.Option("type") {
case "message_read":
case "chat_disband":
case P2P_CHAT_CREATE, ADD_BOT:
// 创建对话
if m.Options(OPEN_CHAT_ID) {
m.Cmdy(SEND, m.Option(OPEN_CHAT_ID), m.Conf(APP, kit.Keym(kit.MDB_TEMPLATE, m.Option("type"))))
}
default:
switch m.Option("msg_type") {
case "location":
case "image":
// m.Rich(META, nil, kit.Dict(
// "url", m.Option("image_url"),
// "width", m.Option("image_width"),
// "height", m.Option("image_height"),
// ))
default:
if m.Options(OPEN_CHAT_ID) {
if m.Cmdy(TALK, strings.TrimSpace(m.Option("text_without_at_bot"))); len(m.Resultv()) > 0 {
m.Cmd(SEND, m.Option(OPEN_CHAT_ID), m.Result())
}
} else {
m.Cmd(DUTY, m.Option("type"), kit.Formats(data))
}
}
}
default:
m.Cmd(DUTY, m.Option("msg.type"), kit.Formats(data))
}
}},
"/sso": {Name: "/sso", Help: "网页", Hand: func(m *ice.Message, c *ice.Context, key string, arg ...string) {
if m.Options("code") {
msg := m.Cmd(web.SPIDE, LARK, "/open-apis/authen/v1/access_token", "grant_type", "authorization_code",
"code", m.Option("code"), "app_access_token", m.Cmdx(APP, "token", "bot"))
m.Option(aaa.USERZONE, LARK)
user := msg.Append("data.open_id")
web.RenderCookie(m, aaa.SessCreate(m, user))
m.Render("redirect", m.Conf(web.SHARE, "meta.domain"))
msg = m.Cmd(EMPLOYEE, m.Option(aaa.USERNAME, user))
m.Cmd(aaa.USER, mdb.MODIFY, aaa.USERZONE, LARK, aaa.USERNICK, msg.Append(kit.MDB_NAME),
aaa.AVATAR, msg.Append("avatar_url"), aaa.GENDER, kit.Select("女", "男", msg.Append(aaa.GENDER) == "1"),
aaa.COUNTRY, msg.Append(aaa.COUNTRY), aaa.CITY, msg.Append(aaa.CITY),
aaa.MOBILE, msg.Append(aaa.MOBILE),
)
return
}
m.Option(mdb.FIELDS, "time,appid,appmm,token,expire")
m.Cmd(mdb.SELECT, m.Prefix(APP), "", mdb.HASH, kit.MDB_NAME, "bot").Table(func(index int, value map[string]string, head []string) {
m.Render("redirect", kit.MergeURL2(m.Conf(APP, kit.Keym(LARK)), "/open-apis/authen/v1/index"),
"app_id", value[APPID], "redirect_uri", kit.MergeURL2(m.Conf(web.SHARE, kit.Keym(kit.MDB_DOMAIN)), "/chat/lark/sso"),
)
})
}},
}, },
} }

View File

@ -1,5 +1,6 @@
title "飞书机器人" title "飞书机器人"
refer "官网" ` refer "官网" `
官网 https://shylinux.com/chat/lark/sso
官网 https://www.feishu.cn/ 官网 https://www.feishu.cn/
文档 https://open.feishu.cn/document/uQjL04CN/ucDOz4yN4MjL3gzM 文档 https://open.feishu.cn/document/uQjL04CN/ucDOz4yN4MjL3gzM
源码 https://github.com/shylinux/icebergs/blob/master/misc/lark/lark.go 源码 https://github.com/shylinux/icebergs/blob/master/misc/lark/lark.go
@ -12,6 +13,7 @@ chapter "应用"
field "app" web.chat.lark.app field "app" web.chat.lark.app
field "group" web.chat.lark.group field "group" web.chat.lark.group
field "company" web.chat.lark.company field "company" web.chat.lark.company
field "duty" web.chat.lark.duty
chapter "权限" chapter "权限"
field sess aaa.sess field sess aaa.sess

106
misc/lark/msg.go Normal file
View File

@ -0,0 +1,106 @@
package lark
import (
"encoding/json"
"net/http"
"strings"
ice "github.com/shylinux/icebergs"
"github.com/shylinux/icebergs/base/web"
"github.com/shylinux/icebergs/core/wiki"
kit "github.com/shylinux/toolkits"
)
func _lark_get(m *ice.Message, appid string, arg ...interface{}) (*ice.Message, interface{}) {
m.Option(web.SPIDE_HEADER, "Authorization", "Bearer "+m.Cmdx(APP, TOKEN, appid), web.ContentType, web.ContentJSON)
msg := m.Cmd(web.SPIDE, LARK, http.MethodGet, arg)
return msg, msg.Optionv(web.SPIDE_RES)
}
func _lark_post(m *ice.Message, appid string, arg ...interface{}) *ice.Message {
m.Option(web.SPIDE_HEADER, "Authorization", "Bearer "+m.Cmdx(APP, TOKEN, appid), web.ContentType, web.ContentJSON)
return m.Cmd(web.SPIDE, LARK, arg)
}
func _lark_parse(m *ice.Message) {
data := m.Optionv(ice.MSG_USERDATA)
if data == nil {
json.NewDecoder(m.R.Body).Decode(&data)
m.Optionv(ice.MSG_USERDATA, data)
switch d := data.(type) {
case map[string]interface{}:
for k, v := range d {
switch d := v.(type) {
case map[string]interface{}:
for k, v := range d {
m.Add(ice.MSG_OPTION, k, kit.Format(v))
}
default:
for _, v := range kit.Simple(v) {
m.Add(ice.MSG_OPTION, kit.Keys(MSG, k), kit.Format(v))
}
}
}
}
}
m.Debug("msg: %v", kit.Format(data))
}
const (
APP_ID = "app_id"
SHIP_ID = "ship_id"
OPEN_ID = "open_id"
CHAT_ID = "chat_id"
USER_ID = "user_id"
OPEN_CHAT_ID = "open_chat_id"
USER_OPEN_ID = "user_open_id"
)
const MSG = "msg"
func init() {
Index.Merge(&ice.Context{Commands: map[string]*ice.Command{
web.WEB_LOGIN: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
m.Option(ice.MSG_USERZONE, LARK)
}},
"/msg": {Name: "/msg", Help: "聊天消息", Hand: func(m *ice.Message, c *ice.Context, key string, arg ...string) {
data := m.Optionv(ice.MSG_USERDATA)
if kit.Value(data, "action") != nil { // 卡片回调
m.Cmd(MSG, "card")
return
}
switch _lark_parse(m); m.Option("msg.type") {
case "url_verification": // 绑定验证
m.Render(ice.RENDER_RESULT, kit.Format(kit.Dict("challenge", m.Option("msg.challenge"))))
case "event_callback": // 事件回调
m.Cmd(EVENT, m.Option(kit.MDB_TYPE))
default: // 未知消息
m.Cmd(DUTY, m.Option("msg.type"), kit.Formats(data))
}
}},
MSG: {Name: "msg", Help: "聊天消息", Action: map[string]*ice.Action{
"location": {Name: "", Help: "", Hand: func(m *ice.Message, arg ...string) {
}},
"image": {Name: "", Help: "", Hand: func(m *ice.Message, arg ...string) {
}},
"card": {Name: "", Help: "", Hand: func(m *ice.Message, arg ...string) {
data := m.Optionv(ice.MSG_USERDATA)
kit.Fetch(kit.Value(data, "action.value"), func(key string, value string) { m.Option(key, value) })
m.Cmdy(TALK, kit.Parse(nil, "", kit.Split(m.Option(kit.SSH_CMD))...))
m.Cmd(SEND, m.Option(APP_ID), CHAT_ID, m.Option(OPEN_CHAT_ID),
m.Option(wiki.TITLE)+" "+m.Option(kit.SSH_CMD), m.Result())
}},
}, Hand: func(m *ice.Message, c *ice.Context, key string, arg ...string) {
if m.Options(OPEN_CHAT_ID) {
if m.Cmdy(TALK, strings.TrimSpace(m.Option("text_without_at_bot"))); len(m.Resultv()) > 0 {
m.Cmd(SEND, m.Option(APP_ID), m.Option(OPEN_CHAT_ID), m.Result())
}
} else {
m.Cmd(DUTY, m.Option(APP_ID), m.Option(kit.MDB_TYPE), kit.Formats(m.Optionv(ice.MSG_USERDATA)))
}
}},
}})
}

25
misc/lark/rand.go Normal file
View File

@ -0,0 +1,25 @@
package lark
import (
"math/rand"
"strings"
ice "github.com/shylinux/icebergs"
kit "github.com/shylinux/toolkits"
)
const RAND = "rand"
func init() {
Index.Merge(&ice.Context{Commands: map[string]*ice.Command{
RAND: {Name: "rand", Help: "随机", Hand: func(m *ice.Message, c *ice.Context, key string, arg ...string) {
msg := m.Cmd(GROUP, m.Option(APP_ID), EMPLOYEE, m.Option(OPEN_CHAT_ID))
list := msg.Appendv(kit.MDB_NAME)
if strings.Contains(m.Option(CONTENT), "誰") {
m.Echo(strings.Replace(m.Option(CONTENT), "誰", list[rand.Intn(len(list))], 1))
return
}
m.Echo(list[rand.Intn(len(list))])
}},
}})
}

68
misc/lark/send.go Normal file
View File

@ -0,0 +1,68 @@
package lark
import (
"strings"
ice "github.com/shylinux/icebergs"
"github.com/shylinux/icebergs/base/aaa"
"github.com/shylinux/icebergs/base/web"
kit "github.com/shylinux/toolkits"
)
func _send_text(m *ice.Message, form map[string]interface{}, arg ...string) bool {
switch len(arg) {
case 0:
case 1:
kit.Value(form, "msg_type", "text")
kit.Value(form, "content.text", arg[0])
if strings.TrimSpace(arg[0]) == "" {
return false
}
default:
if len(arg) == 2 && strings.TrimSpace(arg[1]) == "" {
return false
}
content := []interface{}{}
line := []interface{}{}
for _, v := range arg[1:] {
if v == "\n" {
content, line = append(content, line), []interface{}{}
continue
}
line = append(line, map[string]interface{}{"tag": "text", "text": v + " "})
}
content = append(content, line)
kit.Value(form, "msg_type", "post")
kit.Value(form, "content.post", map[string]interface{}{
"zh_cn": map[string]interface{}{"title": arg[0], CONTENT: content},
})
}
return true
}
const (
CONTENT = "content"
)
const SEND = "send"
func init() {
Index.Merge(&ice.Context{Commands: map[string]*ice.Command{
SEND: {Name: "send appid [chat_id|open_id|user_id|email] target [title] text", Help: "消息", Hand: func(m *ice.Message, c *ice.Context, key string, arg ...string) {
form := kit.Dict(CONTENT, kit.Dict())
appid, arg := arg[0], arg[1:]
switch arg[0] {
case CHAT_ID, OPEN_ID, USER_ID, aaa.EMAIL:
form[arg[0]], arg = arg[1], arg[2:]
default:
form[CHAT_ID], arg = arg[0], arg[1:]
}
if _send_text(m, form, arg...) {
msg := _lark_post(m, appid, "/open-apis/message/v4/send/", web.SPIDE_DATA, kit.Format(form))
m.Push("time", m.Time())
m.Push("message_id", msg.Append("data.message_id"))
}
}},
}})
}

49
misc/lark/sso.go Normal file
View File

@ -0,0 +1,49 @@
package lark
import (
ice "github.com/shylinux/icebergs"
"github.com/shylinux/icebergs/base/aaa"
"github.com/shylinux/icebergs/base/mdb"
"github.com/shylinux/icebergs/base/web"
kit "github.com/shylinux/toolkits"
)
const SSO = "sso"
func init() {
Index.Merge(&ice.Context{Commands: map[string]*ice.Command{
"/sso": {Name: "/sso", Help: "网页", Hand: func(m *ice.Message, c *ice.Context, key string, arg ...string) {
if m.Option(ice.MSG_USERNAME) != "" { // 默认主页
m.RenderIndex(web.SERVE, ice.VOLCANOS)
return
}
home := kit.MergeURL2(m.Option(ice.MSG_USERWEB), "/chat/lark/sso")
if m.Option(kit.MDB_CODE) != "" { // 登录成功
msg := m.Cmd(web.SPIDE, LARK, "/open-apis/authen/v1/access_token", "grant_type", "authorization_code",
kit.MDB_CODE, m.Option(kit.MDB_CODE), "app_access_token", m.Cmdx(APP, TOKEN, m.Cmd(APP).Append(APPID)))
// 创建会话
m.Option(aaa.USERNAME, msg.Append("data.open_id"))
web.RenderCookie(m, aaa.SessCreate(m, m.Option(aaa.USERNAME)))
m.RenderRedirect(kit.Select(home, m.Option(kit.MDB_BACK)))
// 更新用户
msg = m.Cmd(EMPLOYEE, m.Option(aaa.USERNAME))
m.Cmd(aaa.USER, mdb.MODIFY, aaa.USERZONE, LARK, aaa.USERNICK, msg.Append(kit.MDB_NAME),
aaa.AVATAR, msg.Append("avatar_url"), aaa.GENDER, kit.Select("女", "男", msg.Append(aaa.GENDER) == "1"),
aaa.COUNTRY, msg.Append(aaa.COUNTRY), aaa.CITY, msg.Append(aaa.CITY),
aaa.MOBILE, msg.Append(aaa.MOBILE),
)
return
}
if back := m.R.Header.Get("Referer"); back != "" {
home = kit.MergeURL(home, kit.MDB_BACK, back)
}
// 登录页面
m.RenderRedirect(kit.MergeURL2(m.Conf(APP, kit.Keym(LARK)), "/open-apis/authen/v1/index"),
"redirect_uri", home, APP_ID, m.Cmd(APP).Append(APPID))
}},
}})
}

29
misc/lark/talk.go Normal file
View File

@ -0,0 +1,29 @@
package lark
import (
"strings"
ice "github.com/shylinux/icebergs"
"github.com/shylinux/icebergs/base/aaa"
kit "github.com/shylinux/toolkits"
)
const TALK = "talk"
func init() {
Index.Merge(&ice.Context{Commands: map[string]*ice.Command{
TALK: {Name: "talk text", Help: "聊天", Hand: func(m *ice.Message, c *ice.Context, key string, arg ...string) {
cmds := kit.Split(strings.Join(arg, " "))
if aaa.UserLogin(m, m.Option(OPEN_ID), ""); !m.Right(cmds) {
if aaa.UserLogin(m, m.Option(OPEN_CHAT_ID), ""); !m.Right(cmds) {
m.Cmd(DUTY, m.Option(APP_ID), m.Option(OPEN_CHAT_ID), m.Option("text_without_at_bot"))
m.Cmd(HOME)
return // 没有权限
}
}
// 执行命令
m.Cmdy(cmds)
}},
}})
}

View File

@ -718,8 +718,9 @@ func (m *Message) cmd(arg ...interface{}) *Message {
return m return m
} }
ok := false
run := func(msg *Message, ctx *Context, cmd *Command, key string, arg ...string) { run := func(msg *Message, ctx *Context, cmd *Command, key string, arg ...string) {
if cbs != nil { if ok = true; cbs != nil {
msg.Option(list[0]+".cb", cbs) msg.Option(list[0]+".cb", cbs)
} }
for k, v := range opts { for k, v := range opts {
@ -744,8 +745,8 @@ func (m *Message) cmd(arg ...interface{}) *Message {
} }
// 系统命令 // 系统命令
if m.Warn(!m.Hand, ErrNotFound, list) { if m.Warn(!ok, ErrNotFound, list) {
return m.Set(MSG_RESULT).Cmd("cli.system", list) return m.Set(MSG_RESULT).Cmdy("cli.system", list)
} }
return m return m
} }