mirror of https://github.com/mindoc-org/mindoc.git
Merge branch 'master' into new-beego-path
commit
272316f7b4
|
@ -34,17 +34,17 @@ import (
|
|||
// RegisterDataBase 注册数据库
|
||||
func RegisterDataBase() {
|
||||
logs.Info("正在初始化数据库配置.")
|
||||
dbadapter,_ := web.AppConfig.String("db_adapter")
|
||||
dbadapter, _ := web.AppConfig.String("db_adapter")
|
||||
orm.DefaultTimeLoc = time.Local
|
||||
orm.DefaultRowsLimit = -1
|
||||
|
||||
if strings.EqualFold(dbadapter, "mysql") {
|
||||
host,_ := web.AppConfig.String("db_host")
|
||||
host, _ := web.AppConfig.String("db_host")
|
||||
database, _ := web.AppConfig.String("db_database")
|
||||
username,_ := web.AppConfig.String("db_username")
|
||||
password,_ := web.AppConfig.String("db_password")
|
||||
username, _ := web.AppConfig.String("db_username")
|
||||
password, _ := web.AppConfig.String("db_password")
|
||||
|
||||
timezone,_ := web.AppConfig.String("timezone")
|
||||
timezone, _ := web.AppConfig.String("timezone")
|
||||
location, err := time.LoadLocation(timezone)
|
||||
if err == nil {
|
||||
orm.DefaultTimeLoc = location
|
||||
|
@ -52,7 +52,7 @@ func RegisterDataBase() {
|
|||
logs.Error("加载时区配置信息失败,请检查是否存在 ZONEINFO 环境变量->", err)
|
||||
}
|
||||
|
||||
port,_ := web.AppConfig.String("db_port")
|
||||
port, _ := web.AppConfig.String("db_port")
|
||||
|
||||
dataSource := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=true&loc=%s", username, password, host, port, database, url.QueryEscape(timezone))
|
||||
|
||||
|
@ -63,7 +63,7 @@ func RegisterDataBase() {
|
|||
|
||||
} else if strings.EqualFold(dbadapter, "sqlite3") {
|
||||
|
||||
database,_ := web.AppConfig.String("db_database")
|
||||
database, _ := web.AppConfig.String("db_database")
|
||||
if strings.HasPrefix(database, "./") {
|
||||
database = filepath.Join(conf.WorkingDirectory, string(database[1:]))
|
||||
}
|
||||
|
@ -327,6 +327,7 @@ func ResolveCommand(args []string) {
|
|||
web.BConfig.WebConfig.StaticDir["/static"] = filepath.Join(conf.WorkingDirectory, "static")
|
||||
web.BConfig.WebConfig.StaticDir["/uploads"] = uploads
|
||||
web.BConfig.WebConfig.ViewsPath = conf.WorkingDir("views")
|
||||
web.BConfig.WebConfig.Session.SessionCookieSameSite = http.SameSiteDefaultMode
|
||||
|
||||
fonts := conf.WorkingDir("static", "fonts")
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ runmode = "${MINDOC_RUN_MODE||dev}"
|
|||
sessionon = true
|
||||
sessionname = mindoc_id
|
||||
copyrequestbody = true
|
||||
enablexsrf = "${MINDOC_ENABLE_XSRF||true}"
|
||||
|
||||
#系统完整URL(http://doc.iminho.me),如果该项不设置,会从请求头中获取地址。
|
||||
baseurl="${MINDOC_BASE_URL}"
|
||||
|
@ -209,6 +210,20 @@ log_level="${MINDOC_LOG_LEVEL||Alert}"
|
|||
# 是否异步生成日志,默认是 true
|
||||
log_is_async="${MINDOC_LOG_IS_ASYNC||TRUE}"
|
||||
|
||||
##########钉钉应用相关配置##############
|
||||
|
||||
# 企业钉钉ID
|
||||
dingtalk_corpid="${MINDOC_DINGTALK_CORPID}"
|
||||
|
||||
# 钉钉AppKey
|
||||
dingtalk_app_key="${MINDOC_DINGTALK_APPKEY}"
|
||||
|
||||
# 钉钉AppSecret
|
||||
dingtalk_app_secret="${MINDOC_DINGTALK_APPSECRET}"
|
||||
|
||||
# 钉钉登录默认只读账号
|
||||
dingtalk_tmp_reader="${MINDOC_DINGTALK_READER}"
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -9,11 +9,13 @@ import (
|
|||
"html/template"
|
||||
|
||||
"github.com/beego/beego/v2/adapter/logs"
|
||||
"github.com/beego/beego/v2/server/web"
|
||||
"github.com/lifei6671/gocaptcha"
|
||||
"github.com/mindoc-org/mindoc/conf"
|
||||
"github.com/mindoc-org/mindoc/mail"
|
||||
"github.com/mindoc-org/mindoc/models"
|
||||
"github.com/mindoc-org/mindoc/utils"
|
||||
"github.com/mindoc-org/mindoc/utils/dingtalk"
|
||||
)
|
||||
|
||||
// AccountController 用户登录与注册
|
||||
|
@ -31,8 +33,12 @@ func (c *AccountController) referer() string {
|
|||
|
||||
func (c *AccountController) Prepare() {
|
||||
c.BaseController.Prepare()
|
||||
c.EnableXSRF = true
|
||||
c.EnableXSRF = web.AppConfig.DefaultBool("enablexsrf", true)
|
||||
c.Data["xsrfdata"] = template.HTML(c.XSRFFormHTML())
|
||||
c.Data["corpID"],_ = web.AppConfig.String("dingtalk_corpid")
|
||||
if !c.EnableXSRF {
|
||||
return
|
||||
}
|
||||
if c.Ctx.Input.IsPost() {
|
||||
token := c.Ctx.Input.Query("_xsrf")
|
||||
if token == "" {
|
||||
|
@ -132,6 +138,60 @@ func (c *AccountController) Login() {
|
|||
}
|
||||
}
|
||||
|
||||
// 钉钉登录
|
||||
func (c *AccountController) DingTalkLogin() {
|
||||
c.Prepare()
|
||||
|
||||
code := c.GetString("dingtalk_code")
|
||||
if code == "" {
|
||||
c.JsonResult(500, "获取身份信息失败", nil)
|
||||
}
|
||||
|
||||
appKey, _ := web.AppConfig.String("dingtalk_app_key")
|
||||
appSecret, _ := web.AppConfig.String("dingtalk_app_secret")
|
||||
tmpReader, _ := web.AppConfig.String("dingtalk_tmp_reader")
|
||||
|
||||
if appKey == "" || appSecret == "" || tmpReader == "" {
|
||||
c.JsonResult(500, "未开启钉钉自动登录功能", nil)
|
||||
c.StopRun()
|
||||
}
|
||||
|
||||
dingtalkAgent := dingtalk.NewDingTalkAgent(appSecret, appKey)
|
||||
err := dingtalkAgent.GetAccesstoken()
|
||||
if err != nil {
|
||||
logs.Warn("获取钉钉临时Token失败 ->", err)
|
||||
c.JsonResult(500, "自动登录失败", nil)
|
||||
c.StopRun()
|
||||
}
|
||||
|
||||
userid, err := dingtalkAgent.GetUserIDByCode(code)
|
||||
if err != nil {
|
||||
logs.Warn("钉钉自动登录失败 ->", err)
|
||||
c.JsonResult(500, "自动登录失败", nil)
|
||||
c.StopRun()
|
||||
}
|
||||
|
||||
username, avatar, err := dingtalkAgent.GetUserNameAndAvatarByUserID(userid)
|
||||
if err != nil {
|
||||
logs.Warn("钉钉自动登录失败 ->", err)
|
||||
c.JsonResult(500, "自动登录失败", nil)
|
||||
c.StopRun()
|
||||
}
|
||||
|
||||
member, err := models.NewMember().TmpLogin(tmpReader)
|
||||
if err == nil {
|
||||
member.LastLoginTime = time.Now()
|
||||
_ = member.Update("last_login_time")
|
||||
member.Account = username
|
||||
if avatar != "" {
|
||||
member.Avatar = avatar
|
||||
}
|
||||
|
||||
c.SetMember(*member)
|
||||
}
|
||||
c.JsonResult(0, "ok", username)
|
||||
}
|
||||
|
||||
// 登录成功后的操作,如重定向到原始请求页面
|
||||
func (c *AccountController) LoggedIn(isPost bool) interface{} {
|
||||
|
||||
|
|
2
go.mod
2
go.mod
|
@ -5,7 +5,7 @@ go 1.12
|
|||
require (
|
||||
github.com/PuerkitoBio/goquery v1.4.1
|
||||
github.com/andybalholm/cascadia v1.2.0 // indirect
|
||||
github.com/beego/beego/v2 v2.0.2-0.20210322114547-10ea897525a5 // indirect
|
||||
github.com/beego/beego/v2 v2.0.2-0.20210322114547-10ea897525a5
|
||||
github.com/boombuler/barcode v1.0.0
|
||||
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b // indirect
|
||||
github.com/howeyc/fsnotify v0.9.0
|
||||
|
|
8
go.sum
8
go.sum
|
@ -11,9 +11,6 @@ github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGn
|
|||
github.com/alicebob/miniredis v2.5.0+incompatible/go.mod h1:8HZjEj4yU0dwhYHky+DxYx+6BMjkBbe5ONFIF1MXffk=
|
||||
github.com/andybalholm/cascadia v1.2.0 h1:vuRCkM5Ozh/BfmsaTm26kbjm0mIOM3yS5Ek/F5h18aE=
|
||||
github.com/andybalholm/cascadia v1.2.0/go.mod h1:YCyR8vOZT9aZ1CHEd8ap0gMVm2aFgxBp0T0eFw1RUQY=
|
||||
github.com/beego/beego/v2 v2.0.0/go.mod h1:8zyHi1FnWO1mZLwTn62aKRIZF/aIKvkCBB2JYs+eqQI=
|
||||
github.com/beego/beego/v2 v2.0.1 h1:07a7Z0Ok5vbqyqh+q53sDPl9LdhKh0ZDy3gbyGrhFnE=
|
||||
github.com/beego/beego/v2 v2.0.1/go.mod h1:8zyHi1FnWO1mZLwTn62aKRIZF/aIKvkCBB2JYs+eqQI=
|
||||
github.com/beego/beego/v2 v2.0.2-0.20210322114547-10ea897525a5 h1:i0swsv6hmoF6pkeG2S/dvOWwOKFPGDKhrmTlWH6I1nM=
|
||||
github.com/beego/beego/v2 v2.0.2-0.20210322114547-10ea897525a5/go.mod h1:JlRUJ/NVNygorqjyt7/lQ8R++KSE0qXvxeIfbnIUd7Q=
|
||||
github.com/beego/goyaml2 v0.0.0-20130207012346-5545475820dd/go.mod h1:1b+Y/CofkYwXMUU0OhQqGvsY2Bvgr4j6jfT699wyZKQ=
|
||||
|
@ -37,11 +34,8 @@ github.com/coreos/etcd v3.3.25+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc
|
|||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/couchbase/go-couchbase v0.0.0-20200519150804-63f3cdb75e0d/go.mod h1:TWI8EKQMs5u5jLKW/tsb9VwauIrMIxQG1r5fMsswK5U=
|
||||
github.com/couchbase/go-couchbase v0.0.0-20210126152612-8e416c37c8ef/go.mod h1:+/bddYDxXsf9qt0xpDUtRR47A2GjaXmGGAqQ/k3GJ8A=
|
||||
github.com/couchbase/gomemcached v0.0.0-20200526233749-ec430f949808/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c=
|
||||
github.com/couchbase/gomemcached v0.1.2-0.20210126151728-840240974836/go.mod h1:mxliKQxOv84gQ0bJWbI+w9Wxdpt9HjDvgW9MjCym5Vo=
|
||||
github.com/couchbase/goutils v0.0.0-20180530154633-e865a1461c8a/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs=
|
||||
github.com/couchbase/goutils v0.0.0-20201030094643-5e82bb967e67/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs=
|
||||
github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
|
@ -216,7 +210,6 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl
|
|||
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
|
@ -268,7 +261,6 @@ golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtn
|
|||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20201211185031-d93e913c1a58 h1:1Bs6RVeBFtLZ8Yi1Hk07DiOqzvwLD/4hln4iahvFlag=
|
||||
golang.org/x/tools v0.0.0-20201211185031-d93e913c1a58/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
|
|
@ -19,6 +19,8 @@ var (
|
|||
ErrorMemberPasswordError = errors.New("用户密码错误")
|
||||
//ErrorMemberAuthMethodInvalid 不支持此认证方式
|
||||
ErrMemberAuthMethodInvalid = errors.New("不支持此认证方式")
|
||||
//ErrHTTPServerFail
|
||||
ErrHTTPServerFail = errors.New("系统内部异常")
|
||||
//ErrLDAPConnect 无法连接到LDAP服务器
|
||||
ErrLDAPConnect = errors.New("无法连接到LDAP服务器")
|
||||
//ErrLDAPFirstBind 第一次LDAP绑定失败
|
||||
|
|
|
@ -105,6 +105,17 @@ func (m *Member) Login(account string, password string) (*Member, error) {
|
|||
return member, ErrorMemberPasswordError
|
||||
}
|
||||
|
||||
// TmpLogin 用于钉钉临时登录
|
||||
func (m *Member) TmpLogin(account string) (*Member, error) {
|
||||
o := orm.NewOrm()
|
||||
member := &Member{}
|
||||
err := o.Raw("select * from md_members where account = ? and status = 0 limit 1;", account).QueryRow(member)
|
||||
if err != nil {
|
||||
return member, ErrorMemberPasswordError
|
||||
}
|
||||
return member, nil
|
||||
}
|
||||
|
||||
//ldapLogin 通过LDAP登陆
|
||||
func (m *Member) ldapLogin(account string, password string) (*Member, error) {
|
||||
if web.AppConfig.DefaultBool("ldap_enable", false) {
|
||||
|
@ -187,14 +198,14 @@ func (m *Member) httpLogin(account, password string) (*Member, error) {
|
|||
resp, err := http.PostForm(urlStr, val)
|
||||
if err != nil {
|
||||
logs.Error("通过接口登录失败 -> ", urlStr, account, err)
|
||||
return nil, err
|
||||
return nil, ErrHTTPServerFail
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
logs.Error("读取接口返回值失败 -> ", urlStr, account, err)
|
||||
return nil, err
|
||||
return nil, ErrHTTPServerFail
|
||||
}
|
||||
logs.Info("HTTP 登录接口返回数据 ->", string(body))
|
||||
|
||||
|
@ -202,7 +213,7 @@ func (m *Member) httpLogin(account, password string) (*Member, error) {
|
|||
|
||||
if err := json.Unmarshal(body, &result); err != nil {
|
||||
logs.Error("解析接口返回值失败 -> ", urlStr, account, string(body))
|
||||
return nil, errors.New("解析接口返回值失败")
|
||||
return nil, ErrHTTPServerFail
|
||||
}
|
||||
|
||||
if code, ok := result["errcode"]; !ok || code.(float64) != 200 {
|
||||
|
@ -210,7 +221,7 @@ func (m *Member) httpLogin(account, password string) (*Member, error) {
|
|||
if msg, ok := result["message"]; ok {
|
||||
return nil, errors.New(msg.(string))
|
||||
}
|
||||
return nil, errors.New("接口返回值格式不正确")
|
||||
return nil, ErrHTTPServerFail
|
||||
}
|
||||
if m.MemberId <= 0 {
|
||||
member := NewMember()
|
||||
|
|
|
@ -205,16 +205,16 @@ func (m *TeamMember) FindNotJoinMemberByAccount(teamId int, account string, limi
|
|||
}
|
||||
o := orm.NewOrm()
|
||||
|
||||
sql := `select member.member_id,member.account,team.team_member_id
|
||||
sql := `select member.member_id,member.account,member.real_name,team.team_member_id
|
||||
from md_members as member
|
||||
left join md_team_member as team on team.team_id = ? and member.member_id = team.member_id
|
||||
where member.account like ? AND team_member_id IS NULL
|
||||
where member.account like ? or member.real_name like ? AND team_member_id IS NULL
|
||||
order by member.member_id desc
|
||||
limit ?;`
|
||||
|
||||
members := make([]*Member, 0)
|
||||
|
||||
_, err := o.Raw(sql, teamId, "%"+account+"%", limit).QueryRows(&members)
|
||||
_, err := o.Raw(sql, teamId, "%"+account+"%", "%"+account+"%", limit).QueryRows(&members)
|
||||
|
||||
if err != nil {
|
||||
logs.Error("查询团队用户时出错 ->", err)
|
||||
|
@ -227,7 +227,7 @@ limit ?;`
|
|||
for _, member := range members {
|
||||
item := KeyValueItem{}
|
||||
item.Id = member.MemberId
|
||||
item.Text = member.Account
|
||||
item.Text = member.Account + "[" + member.RealName + "]"
|
||||
items = append(items, item)
|
||||
}
|
||||
result.Result = items
|
||||
|
|
|
@ -1,146 +1,147 @@
|
|||
package routers
|
||||
|
||||
import (
|
||||
"github.com/beego/beego/v2/adapter"
|
||||
"github.com/beego/beego/v2/server/web"
|
||||
"github.com/mindoc-org/mindoc/controllers"
|
||||
)
|
||||
|
||||
func init() {
|
||||
adapter.Router("/", &controllers.HomeController{}, "*:Index")
|
||||
web.Router("/", &controllers.HomeController{}, "*:Index")
|
||||
|
||||
adapter.Router("/login", &controllers.AccountController{}, "*:Login")
|
||||
adapter.Router("/logout", &controllers.AccountController{}, "*:Logout")
|
||||
adapter.Router("/register", &controllers.AccountController{}, "*:Register")
|
||||
adapter.Router("/find_password", &controllers.AccountController{}, "*:FindPassword")
|
||||
adapter.Router("/valid_email", &controllers.AccountController{}, "post:ValidEmail")
|
||||
adapter.Router("/captcha", &controllers.AccountController{}, "*:Captcha")
|
||||
web.Router("/login", &controllers.AccountController{}, "*:Login")
|
||||
web.Router("/dingtalk_login", &controllers.AccountController{}, "*:DingTalkLogin")
|
||||
web.Router("/logout", &controllers.AccountController{}, "*:Logout")
|
||||
web.Router("/register", &controllers.AccountController{}, "*:Register")
|
||||
web.Router("/find_password", &controllers.AccountController{}, "*:FindPassword")
|
||||
web.Router("/valid_email", &controllers.AccountController{}, "post:ValidEmail")
|
||||
web.Router("/captcha", &controllers.AccountController{}, "*:Captcha")
|
||||
|
||||
adapter.Router("/manager", &controllers.ManagerController{}, "*:Index")
|
||||
adapter.Router("/manager/users", &controllers.ManagerController{}, "*:Users")
|
||||
adapter.Router("/manager/users/edit/:id", &controllers.ManagerController{}, "*:EditMember")
|
||||
adapter.Router("/manager/member/create", &controllers.ManagerController{}, "post:CreateMember")
|
||||
adapter.Router("/manager/member/delete", &controllers.ManagerController{}, "post:DeleteMember")
|
||||
adapter.Router("/manager/member/update-member-status", &controllers.ManagerController{}, "post:UpdateMemberStatus")
|
||||
adapter.Router("/manager/member/change-member-role", &controllers.ManagerController{}, "post:ChangeMemberRole")
|
||||
adapter.Router("/manager/books", &controllers.ManagerController{}, "*:Books")
|
||||
adapter.Router("/manager/books/edit/:key", &controllers.ManagerController{}, "*:EditBook")
|
||||
adapter.Router("/manager/books/delete", &controllers.ManagerController{}, "*:DeleteBook")
|
||||
web.Router("/manager", &controllers.ManagerController{}, "*:Index")
|
||||
web.Router("/manager/users", &controllers.ManagerController{}, "*:Users")
|
||||
web.Router("/manager/users/edit/:id", &controllers.ManagerController{}, "*:EditMember")
|
||||
web.Router("/manager/member/create", &controllers.ManagerController{}, "post:CreateMember")
|
||||
web.Router("/manager/member/delete", &controllers.ManagerController{}, "post:DeleteMember")
|
||||
web.Router("/manager/member/update-member-status", &controllers.ManagerController{}, "post:UpdateMemberStatus")
|
||||
web.Router("/manager/member/change-member-role", &controllers.ManagerController{}, "post:ChangeMemberRole")
|
||||
web.Router("/manager/books", &controllers.ManagerController{}, "*:Books")
|
||||
web.Router("/manager/books/edit/:key", &controllers.ManagerController{}, "*:EditBook")
|
||||
web.Router("/manager/books/delete", &controllers.ManagerController{}, "*:DeleteBook")
|
||||
|
||||
adapter.Router("/manager/comments", &controllers.ManagerController{}, "*:Comments")
|
||||
adapter.Router("/manager/setting", &controllers.ManagerController{}, "*:Setting")
|
||||
adapter.Router("/manager/books/token", &controllers.ManagerController{}, "post:CreateToken")
|
||||
adapter.Router("/manager/books/transfer", &controllers.ManagerController{}, "post:Transfer")
|
||||
adapter.Router("/manager/books/open", &controllers.ManagerController{}, "post:PrivatelyOwned")
|
||||
web.Router("/manager/comments", &controllers.ManagerController{}, "*:Comments")
|
||||
web.Router("/manager/setting", &controllers.ManagerController{}, "*:Setting")
|
||||
web.Router("/manager/books/token", &controllers.ManagerController{}, "post:CreateToken")
|
||||
web.Router("/manager/books/transfer", &controllers.ManagerController{}, "post:Transfer")
|
||||
web.Router("/manager/books/open", &controllers.ManagerController{}, "post:PrivatelyOwned")
|
||||
|
||||
adapter.Router("/manager/attach/list", &controllers.ManagerController{}, "*:AttachList")
|
||||
adapter.Router("/manager/attach/detailed/:id", &controllers.ManagerController{}, "*:AttachDetailed")
|
||||
adapter.Router("/manager/attach/delete", &controllers.ManagerController{}, "post:AttachDelete")
|
||||
adapter.Router("/manager/label/list", &controllers.ManagerController{}, "get:LabelList")
|
||||
adapter.Router("/manager/label/delete/:id", &controllers.ManagerController{}, "post:LabelDelete")
|
||||
web.Router("/manager/attach/list", &controllers.ManagerController{}, "*:AttachList")
|
||||
web.Router("/manager/attach/detailed/:id", &controllers.ManagerController{}, "*:AttachDetailed")
|
||||
web.Router("/manager/attach/delete", &controllers.ManagerController{}, "post:AttachDelete")
|
||||
web.Router("/manager/label/list", &controllers.ManagerController{}, "get:LabelList")
|
||||
web.Router("/manager/label/delete/:id", &controllers.ManagerController{}, "post:LabelDelete")
|
||||
|
||||
//adapter.Router("/manager/config", &controllers.ManagerController{}, "*:Config")
|
||||
//web.Router("/manager/config", &controllers.ManagerController{}, "*:Config")
|
||||
|
||||
adapter.Router("/manager/team", &controllers.ManagerController{}, "*:Team")
|
||||
adapter.Router("/manager/team/create", &controllers.ManagerController{}, "POST:TeamCreate")
|
||||
adapter.Router("/manager/team/edit", &controllers.ManagerController{}, "POST:TeamEdit")
|
||||
adapter.Router("/manager/team/delete", &controllers.ManagerController{}, "POST:TeamDelete")
|
||||
web.Router("/manager/team", &controllers.ManagerController{}, "*:Team")
|
||||
web.Router("/manager/team/create", &controllers.ManagerController{}, "POST:TeamCreate")
|
||||
web.Router("/manager/team/edit", &controllers.ManagerController{}, "POST:TeamEdit")
|
||||
web.Router("/manager/team/delete", &controllers.ManagerController{}, "POST:TeamDelete")
|
||||
|
||||
adapter.Router("/manager/team/member/list/:id", &controllers.ManagerController{}, "*:TeamMemberList")
|
||||
adapter.Router("/manager/team/member/add", &controllers.ManagerController{}, "POST:TeamMemberAdd")
|
||||
adapter.Router("/manager/team/member/delete", &controllers.ManagerController{}, "POST:TeamMemberDelete")
|
||||
adapter.Router("/manager/team/member/change_role", &controllers.ManagerController{}, "POST:TeamChangeMemberRole")
|
||||
adapter.Router("/manager/team/member/search", &controllers.ManagerController{}, "*:TeamSearchMember")
|
||||
web.Router("/manager/team/member/list/:id", &controllers.ManagerController{}, "*:TeamMemberList")
|
||||
web.Router("/manager/team/member/add", &controllers.ManagerController{}, "POST:TeamMemberAdd")
|
||||
web.Router("/manager/team/member/delete", &controllers.ManagerController{}, "POST:TeamMemberDelete")
|
||||
web.Router("/manager/team/member/change_role", &controllers.ManagerController{}, "POST:TeamChangeMemberRole")
|
||||
web.Router("/manager/team/member/search", &controllers.ManagerController{}, "*:TeamSearchMember")
|
||||
|
||||
adapter.Router("/manager/team/book/list/:id", &controllers.ManagerController{}, "*:TeamBookList")
|
||||
adapter.Router("/manager/team/book/add", &controllers.ManagerController{}, "POST:TeamBookAdd")
|
||||
adapter.Router("/manager/team/book/delete", &controllers.ManagerController{}, "POST:TeamBookDelete")
|
||||
adapter.Router("/manager/team/book/search", &controllers.ManagerController{}, "*:TeamSearchBook")
|
||||
web.Router("/manager/team/book/list/:id", &controllers.ManagerController{}, "*:TeamBookList")
|
||||
web.Router("/manager/team/book/add", &controllers.ManagerController{}, "POST:TeamBookAdd")
|
||||
web.Router("/manager/team/book/delete", &controllers.ManagerController{}, "POST:TeamBookDelete")
|
||||
web.Router("/manager/team/book/search", &controllers.ManagerController{}, "*:TeamSearchBook")
|
||||
|
||||
adapter.Router("/manager/itemsets", &controllers.ManagerController{}, "*:Itemsets")
|
||||
adapter.Router("/manager/itemsets/edit", &controllers.ManagerController{}, "post:ItemsetsEdit")
|
||||
adapter.Router("/manager/itemsets/delete", &controllers.ManagerController{}, "post:ItemsetsDelete")
|
||||
web.Router("/manager/itemsets", &controllers.ManagerController{}, "*:Itemsets")
|
||||
web.Router("/manager/itemsets/edit", &controllers.ManagerController{}, "post:ItemsetsEdit")
|
||||
web.Router("/manager/itemsets/delete", &controllers.ManagerController{}, "post:ItemsetsDelete")
|
||||
|
||||
adapter.Router("/setting", &controllers.SettingController{}, "*:Index")
|
||||
adapter.Router("/setting/password", &controllers.SettingController{}, "*:Password")
|
||||
adapter.Router("/setting/upload", &controllers.SettingController{}, "*:Upload")
|
||||
web.Router("/setting", &controllers.SettingController{}, "*:Index")
|
||||
web.Router("/setting/password", &controllers.SettingController{}, "*:Password")
|
||||
web.Router("/setting/upload", &controllers.SettingController{}, "*:Upload")
|
||||
|
||||
adapter.Router("/book", &controllers.BookController{}, "*:Index")
|
||||
adapter.Router("/book/:key/dashboard", &controllers.BookController{}, "*:Dashboard")
|
||||
adapter.Router("/book/:key/setting", &controllers.BookController{}, "*:Setting")
|
||||
adapter.Router("/book/:key/users", &controllers.BookController{}, "*:Users")
|
||||
adapter.Router("/book/:key/release", &controllers.BookController{}, "post:Release")
|
||||
adapter.Router("/book/:key/sort", &controllers.BookController{}, "post:SaveSort")
|
||||
adapter.Router("/book/:key/teams", &controllers.BookController{}, "*:Team")
|
||||
web.Router("/book", &controllers.BookController{}, "*:Index")
|
||||
web.Router("/book/:key/dashboard", &controllers.BookController{}, "*:Dashboard")
|
||||
web.Router("/book/:key/setting", &controllers.BookController{}, "*:Setting")
|
||||
web.Router("/book/:key/users", &controllers.BookController{}, "*:Users")
|
||||
web.Router("/book/:key/release", &controllers.BookController{}, "post:Release")
|
||||
web.Router("/book/:key/sort", &controllers.BookController{}, "post:SaveSort")
|
||||
web.Router("/book/:key/teams", &controllers.BookController{}, "*:Team")
|
||||
|
||||
adapter.Router("/book/create", &controllers.BookController{}, "*:Create")
|
||||
adapter.Router("/book/itemsets/search", &controllers.BookController{}, "*:ItemsetsSearch")
|
||||
web.Router("/book/create", &controllers.BookController{}, "*:Create")
|
||||
web.Router("/book/itemsets/search", &controllers.BookController{}, "*:ItemsetsSearch")
|
||||
|
||||
adapter.Router("/book/users/create", &controllers.BookMemberController{}, "post:AddMember")
|
||||
adapter.Router("/book/users/change", &controllers.BookMemberController{}, "post:ChangeRole")
|
||||
adapter.Router("/book/users/delete", &controllers.BookMemberController{}, "post:RemoveMember")
|
||||
adapter.Router("/book/users/import", &controllers.BookController{}, "post:Import")
|
||||
adapter.Router("/book/users/copy", &controllers.BookController{}, "post:Copy")
|
||||
web.Router("/book/users/create", &controllers.BookMemberController{}, "post:AddMember")
|
||||
web.Router("/book/users/change", &controllers.BookMemberController{}, "post:ChangeRole")
|
||||
web.Router("/book/users/delete", &controllers.BookMemberController{}, "post:RemoveMember")
|
||||
web.Router("/book/users/import", &controllers.BookController{}, "post:Import")
|
||||
web.Router("/book/users/copy", &controllers.BookController{}, "post:Copy")
|
||||
|
||||
adapter.Router("/book/setting/save", &controllers.BookController{}, "post:SaveBook")
|
||||
adapter.Router("/book/setting/open", &controllers.BookController{}, "post:PrivatelyOwned")
|
||||
adapter.Router("/book/setting/transfer", &controllers.BookController{}, "post:Transfer")
|
||||
adapter.Router("/book/setting/upload", &controllers.BookController{}, "post:UploadCover")
|
||||
adapter.Router("/book/setting/delete", &controllers.BookController{}, "post:Delete")
|
||||
web.Router("/book/setting/save", &controllers.BookController{}, "post:SaveBook")
|
||||
web.Router("/book/setting/open", &controllers.BookController{}, "post:PrivatelyOwned")
|
||||
web.Router("/book/setting/transfer", &controllers.BookController{}, "post:Transfer")
|
||||
web.Router("/book/setting/upload", &controllers.BookController{}, "post:UploadCover")
|
||||
web.Router("/book/setting/delete", &controllers.BookController{}, "post:Delete")
|
||||
|
||||
adapter.Router("/book/team/add", &controllers.BookController{}, "POST:TeamAdd")
|
||||
adapter.Router("/book/team/delete", &controllers.BookController{}, "POST:TeamDelete")
|
||||
adapter.Router("/book/team/search", &controllers.BookController{}, "*:TeamSearch")
|
||||
web.Router("/book/team/add", &controllers.BookController{}, "POST:TeamAdd")
|
||||
web.Router("/book/team/delete", &controllers.BookController{}, "POST:TeamDelete")
|
||||
web.Router("/book/team/search", &controllers.BookController{}, "*:TeamSearch")
|
||||
|
||||
//管理文章的路由
|
||||
adapter.Router("/manage/blogs", &controllers.BlogController{}, "*:ManageList")
|
||||
adapter.Router("/manage/blogs/setting/?:id", &controllers.BlogController{}, "*:ManageSetting")
|
||||
adapter.Router("/manage/blogs/edit/?:id", &controllers.BlogController{}, "*:ManageEdit")
|
||||
adapter.Router("/manage/blogs/delete", &controllers.BlogController{}, "post:ManageDelete")
|
||||
adapter.Router("/manage/blogs/upload", &controllers.BlogController{}, "post:Upload")
|
||||
adapter.Router("/manage/blogs/attach/:id", &controllers.BlogController{}, "post:RemoveAttachment")
|
||||
web.Router("/manage/blogs", &controllers.BlogController{}, "*:ManageList")
|
||||
web.Router("/manage/blogs/setting/?:id", &controllers.BlogController{}, "*:ManageSetting")
|
||||
web.Router("/manage/blogs/edit/?:id", &controllers.BlogController{}, "*:ManageEdit")
|
||||
web.Router("/manage/blogs/delete", &controllers.BlogController{}, "post:ManageDelete")
|
||||
web.Router("/manage/blogs/upload", &controllers.BlogController{}, "post:Upload")
|
||||
web.Router("/manage/blogs/attach/:id", &controllers.BlogController{}, "post:RemoveAttachment")
|
||||
|
||||
//读文章的路由
|
||||
adapter.Router("/blogs", &controllers.BlogController{}, "*:List")
|
||||
adapter.Router("/blog-attach/:id:int/:attach_id:int", &controllers.BlogController{}, "get:Download")
|
||||
adapter.Router("/blog-:id([0-9]+).html", &controllers.BlogController{}, "*:Index")
|
||||
web.Router("/blogs", &controllers.BlogController{}, "*:List")
|
||||
web.Router("/blog-attach/:id:int/:attach_id:int", &controllers.BlogController{}, "get:Download")
|
||||
web.Router("/blog-:id([0-9]+).html", &controllers.BlogController{}, "*:Index")
|
||||
|
||||
//模板相关接口
|
||||
adapter.Router("/api/template/get", &controllers.TemplateController{}, "get:Get")
|
||||
adapter.Router("/api/template/list", &controllers.TemplateController{}, "post:List")
|
||||
adapter.Router("/api/template/add", &controllers.TemplateController{}, "post:Add")
|
||||
adapter.Router("/api/template/remove", &controllers.TemplateController{}, "post:Delete")
|
||||
web.Router("/api/template/get", &controllers.TemplateController{}, "get:Get")
|
||||
web.Router("/api/template/list", &controllers.TemplateController{}, "post:List")
|
||||
web.Router("/api/template/add", &controllers.TemplateController{}, "post:Add")
|
||||
web.Router("/api/template/remove", &controllers.TemplateController{}, "post:Delete")
|
||||
|
||||
adapter.Router("/api/attach/remove/", &controllers.DocumentController{}, "post:RemoveAttachment")
|
||||
adapter.Router("/api/:key/edit/?:id", &controllers.DocumentController{}, "*:Edit")
|
||||
adapter.Router("/api/upload", &controllers.DocumentController{}, "post:Upload")
|
||||
adapter.Router("/api/:key/create", &controllers.DocumentController{}, "post:Create")
|
||||
adapter.Router("/api/:key/delete", &controllers.DocumentController{}, "post:Delete")
|
||||
adapter.Router("/api/:key/content/?:id", &controllers.DocumentController{}, "*:Content")
|
||||
adapter.Router("/api/:key/compare/:id", &controllers.DocumentController{}, "*:Compare")
|
||||
adapter.Router("/api/search/user/:key", &controllers.SearchController{}, "*:User")
|
||||
web.Router("/api/attach/remove/", &controllers.DocumentController{}, "post:RemoveAttachment")
|
||||
web.Router("/api/:key/edit/?:id", &controllers.DocumentController{}, "*:Edit")
|
||||
web.Router("/api/upload", &controllers.DocumentController{}, "post:Upload")
|
||||
web.Router("/api/:key/create", &controllers.DocumentController{}, "post:Create")
|
||||
web.Router("/api/:key/delete", &controllers.DocumentController{}, "post:Delete")
|
||||
web.Router("/api/:key/content/?:id", &controllers.DocumentController{}, "*:Content")
|
||||
web.Router("/api/:key/compare/:id", &controllers.DocumentController{}, "*:Compare")
|
||||
web.Router("/api/search/user/:key", &controllers.SearchController{}, "*:User")
|
||||
|
||||
adapter.Router("/history/get", &controllers.DocumentController{}, "get:History")
|
||||
adapter.Router("/history/delete", &controllers.DocumentController{}, "*:DeleteHistory")
|
||||
adapter.Router("/history/restore", &controllers.DocumentController{}, "*:RestoreHistory")
|
||||
web.Router("/history/get", &controllers.DocumentController{}, "get:History")
|
||||
web.Router("/history/delete", &controllers.DocumentController{}, "*:DeleteHistory")
|
||||
web.Router("/history/restore", &controllers.DocumentController{}, "*:RestoreHistory")
|
||||
|
||||
adapter.Router("/docs/:key", &controllers.DocumentController{}, "*:Index")
|
||||
adapter.Router("/docs/:key/:id", &controllers.DocumentController{}, "*:Read")
|
||||
adapter.Router("/docs/:key/search", &controllers.DocumentController{}, "post:Search")
|
||||
adapter.Router("/export/:key", &controllers.DocumentController{}, "*:Export")
|
||||
adapter.Router("/qrcode/:key.png", &controllers.DocumentController{}, "get:QrCode")
|
||||
web.Router("/docs/:key", &controllers.DocumentController{}, "*:Index")
|
||||
web.Router("/docs/:key/:id", &controllers.DocumentController{}, "*:Read")
|
||||
web.Router("/docs/:key/search", &controllers.DocumentController{}, "post:Search")
|
||||
web.Router("/export/:key", &controllers.DocumentController{}, "*:Export")
|
||||
web.Router("/qrcode/:key.png", &controllers.DocumentController{}, "get:QrCode")
|
||||
|
||||
adapter.Router("/attach_files/:key/:attach_id", &controllers.DocumentController{}, "get:DownloadAttachment")
|
||||
web.Router("/attach_files/:key/:attach_id", &controllers.DocumentController{}, "get:DownloadAttachment")
|
||||
|
||||
adapter.Router("/comment/create", &controllers.CommentController{}, "post:Create")
|
||||
adapter.Router("/comment/lists", &controllers.CommentController{}, "get:Lists")
|
||||
adapter.Router("/comment/index", &controllers.CommentController{}, "*:Index")
|
||||
web.Router("/comment/create", &controllers.CommentController{}, "post:Create")
|
||||
web.Router("/comment/lists", &controllers.CommentController{}, "get:Lists")
|
||||
web.Router("/comment/index", &controllers.CommentController{}, "*:Index")
|
||||
|
||||
adapter.Router("/search", &controllers.SearchController{}, "get:Index")
|
||||
web.Router("/search", &controllers.SearchController{}, "get:Index")
|
||||
|
||||
adapter.Router("/tag/:key", &controllers.LabelController{}, "get:Index")
|
||||
adapter.Router("/tags", &controllers.LabelController{}, "get:List")
|
||||
web.Router("/tag/:key", &controllers.LabelController{}, "get:Index")
|
||||
web.Router("/tags", &controllers.LabelController{}, "get:List")
|
||||
|
||||
adapter.Router("/items", &controllers.ItemsetsController{}, "get:Index")
|
||||
adapter.Router("/items/:key", &controllers.ItemsetsController{}, "get:List")
|
||||
web.Router("/items", &controllers.ItemsetsController{}, "get:Index")
|
||||
web.Router("/items/:key", &controllers.ItemsetsController{}, "get:List")
|
||||
|
||||
}
|
||||
|
|
|
@ -1037,6 +1037,24 @@ textarea{
|
|||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
.navbar-mobile {
|
||||
display: inline-block;
|
||||
padding: 10px 0;
|
||||
font-size: 14px;
|
||||
line-height: 30px;
|
||||
color: #563d7c;
|
||||
}
|
||||
.navbar-mobile a {
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.navbar-mobile {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,147 @@
|
|||
package dingtalk
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
// DingTalkAgent 用于钉钉交互
|
||||
type DingTalkAgent struct {
|
||||
AppSecret string
|
||||
AppKey string
|
||||
AccessToken string
|
||||
}
|
||||
|
||||
// NewDingTalkAgent 钉钉交互构造函数
|
||||
func NewDingTalkAgent(appSecret, appKey string) *DingTalkAgent {
|
||||
return &DingTalkAgent{
|
||||
AppSecret: appSecret,
|
||||
AppKey: appKey,
|
||||
}
|
||||
}
|
||||
|
||||
// GetUserIDByCode 通过临时code获取当前用户ID
|
||||
func (d *DingTalkAgent) GetUserIDByCode(code string) (string, error) {
|
||||
urlEndpoint, err := url.Parse("https://oapi.dingtalk.com/user/getuserinfo")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
query := url.Values{}
|
||||
query.Set("access_token", d.AccessToken)
|
||||
query.Set("code", code)
|
||||
|
||||
urlEndpoint.RawQuery = query.Encode()
|
||||
urlPath := urlEndpoint.String()
|
||||
|
||||
resp, err := http.Get(urlPath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// 解析钉钉返回数据
|
||||
var rdata map[string]interface{}
|
||||
err = json.Unmarshal(body, &rdata)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
errcode := rdata["errcode"].(float64)
|
||||
if errcode != 0 {
|
||||
return "", errors.New(fmt.Sprintf("登录错误: %.0f, %s", errcode, rdata["errmsg"].(string)))
|
||||
}
|
||||
|
||||
userid := rdata["userid"].(string)
|
||||
return userid, nil
|
||||
}
|
||||
|
||||
// GetUserNameAndAvatarByUserID 通过userid获取当前用户姓名和头像
|
||||
func (d *DingTalkAgent) GetUserNameAndAvatarByUserID(userid string) (string, string, error) {
|
||||
urlEndpoint, err := url.Parse("https://oapi.dingtalk.com/topapi/v2/user/get")
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
query := url.Values{}
|
||||
query.Set("access_token", d.AccessToken)
|
||||
|
||||
urlEndpoint.RawQuery = query.Encode()
|
||||
urlPath := urlEndpoint.String()
|
||||
|
||||
resp, err := http.PostForm(urlPath, url.Values{"userid": {userid}})
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
// 解析钉钉返回数据
|
||||
var rdata map[string]interface{}
|
||||
err = json.Unmarshal(body, &rdata)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
errcode := rdata["errcode"].(float64)
|
||||
if errcode != 0 {
|
||||
return "", "", errors.New(fmt.Sprintf("登录错误: %.0f, %s", errcode, rdata["errmsg"].(string)))
|
||||
}
|
||||
|
||||
userinfo := rdata["result"].(map[string]interface{})
|
||||
username := userinfo["name"].(string)
|
||||
avatar := userinfo["avatar"].(string)
|
||||
return username, avatar, nil
|
||||
}
|
||||
|
||||
// GetAccesstoken 获取钉钉请求Token
|
||||
func (d *DingTalkAgent) GetAccesstoken() (err error) {
|
||||
|
||||
url := fmt.Sprintf("https://oapi.dingtalk.com/gettoken?appkey=%s&appsecret=%s", d.AppKey, d.AppSecret)
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var i map[string]interface{}
|
||||
err = json.Unmarshal(body, &i)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if i["errcode"].(float64) == 0 {
|
||||
d.AccessToken = i["access_token"].(string)
|
||||
return nil
|
||||
}
|
||||
return errors.New("accesstoken获取错误:" + i["errmsg"].(string))
|
||||
}
|
||||
|
||||
func (d *DingTalkAgent) encodeSHA256(message string) string {
|
||||
// 钉钉签名算法实现
|
||||
h := hmac.New(sha256.New, []byte(d.AppSecret))
|
||||
h.Write([]byte(message))
|
||||
sum := h.Sum(nil) // 二进制流
|
||||
tmpMsg := base64.StdEncoding.EncodeToString(sum)
|
||||
|
||||
uv := url.Values{}
|
||||
uv.Add("0", tmpMsg)
|
||||
message = uv.Encode()[2:]
|
||||
|
||||
return message
|
||||
}
|
|
@ -86,6 +86,47 @@
|
|||
<!-- Include all compiled plugins (below), or include individual files as needed -->
|
||||
<script src="{{cdnjs "/static/bootstrap/js/bootstrap.min.js"}}" type="text/javascript"></script>
|
||||
<script src="{{cdnjs "/static/layer/layer.js"}}" type="text/javascript"></script>
|
||||
<script src="{{cdnjs "/static/js/dingtalk-jsapi.js"}}" type="text/javascript"></script>
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
if (dd.env.platform !== "notInDingTalk"){
|
||||
dd.ready(function() {
|
||||
dd.runtime.permission.requestAuthCode({
|
||||
corpId: {{ .corpID }} , // 企业id
|
||||
onSuccess: function (info) {
|
||||
var index = layer.load(1, {
|
||||
shade: [0.1, '#fff'] // 0.1 透明度的白色背景
|
||||
})
|
||||
|
||||
var formData = $("form").serializeArray()
|
||||
formData.push({"name": "dingtalk_code", "value": info.code})
|
||||
|
||||
$.ajax({
|
||||
url: "{{urlfor "AccountController.DingTalkLogin"}} ",
|
||||
data: formData,
|
||||
dataType: "json",
|
||||
type: "POST",
|
||||
complete: function(){
|
||||
layer.close(index)
|
||||
},
|
||||
success: function (res) {
|
||||
if (res.errcode !== 0) {
|
||||
layer.msg(res.message)
|
||||
} else {
|
||||
window.location = "{{ urlfor "HomeController.Index" }}"
|
||||
}
|
||||
},
|
||||
error: function (res) {
|
||||
layer.msg("发生异常")
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
})
|
||||
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
$("#account,#password,#code").on('focus', function () {
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
<div class="manual-list">
|
||||
{{range $index,$item := .Lists}}
|
||||
<div class="search-item">
|
||||
<div class="title">{{if eq $item.BlogStatus "password"}}<span class="label">密</span>{{end}} <a href="{{urlfor "BlogController.Index" ":id" $item.BlogId}}" title="{{$item.BlogTitle}}" target="_blank">{{$item.BlogTitle}}</a> </div>
|
||||
<div class="title">{{if eq $item.BlogStatus "password"}}<span class="label">密</span>{{end}} <a href="{{urlfor "BlogController.Index" ":id" $item.BlogId}}" title="{{$item.BlogTitle}}">{{$item.BlogTitle}}</a> </div>
|
||||
<div class="description">
|
||||
{{$item.BlogExcerpt}}
|
||||
</div>
|
||||
|
|
|
@ -30,6 +30,19 @@
|
|||
<link href="{{cdncss "/static/css/print.css" "version"}}" media="print" rel="stylesheet">
|
||||
|
||||
<script type="text/javascript">window.book={"identify":"{{.Model.Identify}}"};</script>
|
||||
<style>
|
||||
.btn-mobile {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 10px;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 840px) {
|
||||
.btn-mobile{
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="m-manual manual-mode-view manual-reader">
|
||||
|
@ -40,6 +53,7 @@
|
|||
<a href="{{urlfor "DocumentController.Index" ":key" .Model.Identify}}" title="{{.Model.BookName}}" class="book-title">{{.Model.BookName}}</a>
|
||||
<span style="font-size: 12px;font-weight: 100;"></span>
|
||||
</div>
|
||||
<a href="{{urlfor "HomeController.Index"}}" class="btn btn-default btn-mobile"> <i class="fa fa-home" aria-hidden="true"></i>首页</a>
|
||||
<div class="navbar-header pull-right manual-menu">
|
||||
<a href="javascript:window.print();" id="printSinglePage" class="btn btn-default" style="margin-right: 10px;"><i class="fa fa-print"></i> 打印</a>
|
||||
{{if gt .Member.MemberId 0}}
|
||||
|
|
|
@ -26,12 +26,12 @@
|
|||
<div class="list-item">
|
||||
<dl class="manual-item-standard">
|
||||
<dt>
|
||||
<a href="{{urlfor "DocumentController.Index" ":key" $item.Identify}}" title="{{$item.BookName}}-{{$item.CreateName}}" target="_blank">
|
||||
<a href="{{urlfor "DocumentController.Index" ":key" $item.Identify}}" title="{{$item.BookName}}-{{$item.CreateName}}">
|
||||
<img src="{{cdnimg $item.Cover}}" class="cover" alt="{{$item.BookName}}-{{$item.CreateName}}" onerror="this.src='{{cdnimg "static/images/book.jpg"}}';">
|
||||
</a>
|
||||
</dt>
|
||||
<dd>
|
||||
<a href="{{urlfor "DocumentController.Index" ":key" $item.Identify}}" class="name" title="{{$item.BookName}}-{{$item.CreateName}}" target="_blank">{{$item.BookName}}</a>
|
||||
<a href="{{urlfor "DocumentController.Index" ":key" $item.Identify}}" class="name" title="{{$item.BookName}}-{{$item.CreateName}}">{{$item.BookName}}</a>
|
||||
</dd>
|
||||
<dd>
|
||||
<span class="author">
|
||||
|
|
|
@ -29,6 +29,10 @@
|
|||
</form>
|
||||
</div>
|
||||
</nav>
|
||||
<div style="display: inline-block;" class="navbar-mobile">
|
||||
<a href="{{urlfor "HomeController.Index" }}" title="首页">首页</a>
|
||||
<a href="{{urlfor "BlogController.List" }}" title="文章">文章</a>
|
||||
</div>
|
||||
|
||||
<div class="btn-group dropdown-menu-right pull-right slidebar visible-xs-inline-block visible-sm-inline-block">
|
||||
<button class="btn btn-default dropdown-toggle hidden-lg" type="button" data-toggle="dropdown"><i class="fa fa-align-justify"></i></button>
|
||||
|
|
Loading…
Reference in New Issue