From 530b69c58ffe3acee444b7cb5930418cc63b22cc Mon Sep 17 00:00:00 2001
From: magicwind <2814461814@qq.com>
Date: Tue, 7 Jun 2022 14:03:11 +0800
Subject: [PATCH] feat: integrate Casdoor
---
conf/oauth.conf.example | 65 +--
controllers/AcountController.go | 611 +++----------------------
controllers/BaseController.go | 316 +++++++------
controllers/SettingController.go | 195 +-------
controllers/UserController.go | 1 +
controllers/token_jwt_key.pem | 29 ++
go.mod | 4 +-
go.sum | 369 ++++++++++++++-
models/member.go | 7 -
routers/web.go | 10 +-
views/account/bind.html | 135 ------
views/account/find_password_setp1.html | 112 -----
views/account/find_password_setp2.html | 125 -----
views/account/mail_template.html | 98 ----
views/setting/index.html | 219 ---------
views/setting/menu.html | 3 -
views/setting/password.html | 94 ----
views/widgets/header.html | 2 +-
18 files changed, 651 insertions(+), 1744 deletions(-)
create mode 100644 controllers/token_jwt_key.pem
delete mode 100644 views/account/bind.html
delete mode 100644 views/account/find_password_setp1.html
delete mode 100644 views/account/find_password_setp2.html
delete mode 100644 views/account/mail_template.html
delete mode 100644 views/setting/index.html
delete mode 100644 views/setting/password.html
diff --git a/conf/oauth.conf.example b/conf/oauth.conf.example
index e897adcd..10e399a4 100644
--- a/conf/oauth.conf.example
+++ b/conf/oauth.conf.example
@@ -1,57 +1,10 @@
-# 第三方登录配置
[oauth]
-
-##### Gitee(码云) ####
-# 申请地址(需要先登录):https://gitee.com/oauth/applications
-
-# 您的ClientId
-giteeClientId=
-
-# 您的ClientSecret
-giteeClientSecret=
-
-# 回调地址,把下面的bookstack.cn的域名换成你的即可
-giteeCallback=http://www.bookstack.cn/login/gitee
-
-# 下面这两项不要动
-giteeAccesstoken=https://gitee.com/oauth/token
-giteeUserInfo=https://gitee.com/api/v5/user
-
-
-
-######## GitHub ########
-# 申请地址(需要先登录你的GitHub):https://github.com/settings/developers
-
-# 您的ClientId
-githubClientId=
-
-# 您的ClientSecret
-githubClientSecret=
-
-# 回调地址,把下面的bookstack.cn的域名换成你的即可
-githubCallback=http://www.bookstack.cn/login/github
-
-# 下面这两项不要动
-githubAccesstoken=https://github.com/login/oauth/access_token
-githubUserInfo=https://api.github.com/user
-
-
-
-#### QQ ####
-# 申请地址(需要先登录你的QQ):https://connect.qq.com/manage.html
-
-#ClientId,即 APP ID
-qqClientId=
-
-#ClientSecret,即 APP Key
-qqClientSecret=
-
-# 回调地址,把下面的bookstack.cn的域名换成你的即可
-qqCallback=http://www.bookstack.cn/login/qq
-
-# 下面这三项不要动
-qqAccesstoken=https://graph.qq.com/oauth2.0/token
-qqOpenId=https://graph.qq.com/oauth2.0/me
-qqUserInfo=https://graph.qq.com/user/get_user_info
-
-### TODO 微信和微博登录,主要是我这边忘记了以前注册的个人开发者信息,当前没开发,后续会开发出来 ####
+######## casdoor ########
+# 先部署casdoor
+
+casdoorOrganization =
+casdoorApplication = "bookstack"
+casdoorEndpoint = http://localhost:8000
+clientId =
+clientSecret =
+redirectUrl = http://localhost:8181/login/callback
\ No newline at end of file
diff --git a/controllers/AcountController.go b/controllers/AcountController.go
index 5282b6cc..fc0c3f68 100644
--- a/controllers/AcountController.go
+++ b/controllers/AcountController.go
@@ -1,25 +1,21 @@
package controllers
import (
- "regexp"
- "strings"
- "time"
-
- "errors"
-
+ _ "embed"
"fmt"
-
"github.com/TruthHun/BookStack/conf"
"github.com/TruthHun/BookStack/models"
- "github.com/TruthHun/BookStack/oauth"
- "github.com/TruthHun/BookStack/utils"
"github.com/astaxie/beego"
"github.com/astaxie/beego/cache"
- "github.com/astaxie/beego/orm"
"github.com/astaxie/beego/utils/captcha"
+ "github.com/casdoor/casdoor-go-sdk/auth"
+ "strings"
//"github.com/lifei6671/gocaptcha"
)
+//go:embed token_jwt_key.pem
+var JwtPublicKey string
+
// AccountController 用户登录与注册.
type AccountController struct {
BaseController
@@ -28,576 +24,111 @@ type AccountController struct {
var cpt *captcha.Captcha
func init() {
+ InitAuthConfig()
// use beego cache system store the captcha data
fc := &cache.FileCache{CachePath: "./cache/captcha"}
cpt = captcha.NewWithFilter("/captcha/", fc)
}
-//第三方登录回调
-//封装一个内部调用的函数,loginByMemberId
-func (this *AccountController) Oauth() {
-
- var (
- nickname string //昵称
- avatar string //头像的http链接地址
- email string //邮箱地址
- username string //用户名
- tips string
- id interface{} //第三方的用户id,唯一识别码
- IsEmail bool //是否是使用邮箱注册
- captchaOn bool //是否开启了验证码
- )
-
- //如果开启了验证码
- if v, ok := this.Option["ENABLED_CAPTCHA"]; ok && strings.EqualFold(v, "true") {
- captchaOn = true
- this.Data["CaptchaOn"] = captchaOn
- }
-
- oauthLogin := false
- if v, ok := this.Option["LOGIN_QQ"]; ok && strings.EqualFold(v, "true") {
- this.Data["LoginQQ"] = true
- oauthLogin = true
- }
- if v, ok := this.Option["LOGIN_GITHUB"]; ok && strings.EqualFold(v, "true") {
- this.Data["LoginGitHub"] = true
- oauthLogin = true
- }
- if v, ok := this.Option["LOGIN_GITEE"]; ok && strings.EqualFold(v, "true") {
- this.Data["LoginGitee"] = true
- oauthLogin = true
- }
- this.Data["OauthLogin"] = oauthLogin
-
- oa := this.GetString(":oauth")
- code := this.GetString("code")
- switch oa {
- case "gitee":
- tips = `您正在使用【码云】登录`
- token, err := oauth.GetGiteeAccessToken(code)
- if err != nil {
- beego.Error(err)
- this.Abort("404")
- }
-
- info, err := oauth.GetGiteeUserInfo(token.AccessToken)
- if err != nil {
- beego.Error(err)
- this.Abort("404")
- }
-
- if info.Id > 0 {
- existInfo, _ := models.ModelGitee.GetUserByGiteeId(info.Id, "id", "member_id")
- if existInfo.MemberId > 0 { //直接登录
- err = this.loginByMemberId(existInfo.MemberId)
- if err != nil {
- beego.Error(err)
- this.Abort("404")
- }
- this.Redirect(beego.URLFor("HomeController.Index"), 302)
- return
- }
- if existInfo.Id == 0 { //原本不存在于数据库中的数据需要入库
- orm.NewOrm().Insert(&models.Gitee{GiteeUser: info})
- }
- nickname = info.Name
- username = info.Login
- avatar = info.AvatarURL
- email = info.Email
- id = info.Id
- } else {
- err = errors.New("获取gitee用户数据失败")
- beego.Error(err)
- this.Abort("404")
- }
- case "github":
- tips = `您正在使用【GitHub】登录`
- token, err := oauth.GetGithubAccessToken(code)
- if err != nil {
- beego.Error(err.Error())
- this.Abort("404")
- }
-
- info, err := oauth.GetGithubUserInfo(token.AccessToken)
- if err != nil {
- beego.Error(err.Error())
- this.Abort("404")
- }
-
- if info.Id > 0 {
- existInfo, _ := models.ModelGithub.GetUserByGithubId(info.Id, "id", "member_id")
- if existInfo.MemberId > 0 { //直接登录
- err = this.loginByMemberId(existInfo.MemberId)
- if err != nil {
- beego.Error(err.Error())
- this.Abort("404")
- }
- this.Redirect(beego.URLFor("HomeController.Index"), 302)
- return
- }
- if existInfo.Id == 0 { //原本不存在于数据库中的数据需要入库
- orm.NewOrm().Insert(&models.Github{GithubUser: info})
- }
- nickname = info.Name
- username = info.Login
- avatar = info.AvatarURL
- email = info.Email
- id = info.Id
- } else {
- err = errors.New("获取github用户数据失败")
- beego.Error(err.Error())
- this.Abort("404")
- }
-
- case "qq":
- tips = `您正在使用【QQ】登录`
- token, err := oauth.GetQQAccessToken(code)
- if err != nil {
- beego.Error(err)
- this.Abort("404")
- }
-
- openid, err := oauth.GetQQOpenId(token)
- if err != nil {
- beego.Error(err.Error())
- this.Abort("404")
- }
-
- info, err := oauth.GetQQUserInfo(token.AccessToken, openid)
- if err != nil {
- beego.Error(err.Error())
- this.Abort("404")
- }
-
- if info.Ret == 0 {
- existInfo, _ := models.ModelQQ.GetUserByOpenid(openid, "id", "member_id")
- if existInfo.MemberId > 0 { //直接登录
- err = this.loginByMemberId(existInfo.MemberId)
- if err != nil {
- beego.Error(err.Error())
- this.Abort("404")
- }
- this.Redirect(beego.URLFor("HomeController.Index"), 302)
- return
- }
+func InitAuthConfig() {
+ casdoorEndpoint := beego.AppConfig.String("oauth::casdoorEndpoint")
+ clientId := beego.AppConfig.String("oauth::clientId")
+ clientSecret := beego.AppConfig.String("oauth::clientSecret")
+ casdoorOrganization := beego.AppConfig.String("oauth::casdoorOrganization")
+ casdoorApplication := beego.AppConfig.String("oauth::casdoorApplication")
- if existInfo.Id == 0 { //原本不存在于数据库中的数据需要入库
- orm.NewOrm().Insert(&models.QQ{
- OpenId: openid,
- Name: info.Name,
- Gender: info.Gender,
- AvatarURL: info.AvatarURL,
- })
- }
- nickname = info.Name
- username = ""
- avatar = info.AvatarURL
- email = ""
- id = openid
- } else {
- err = errors.New(info.Msg)
- beego.Error(err)
- this.Abort("404")
- }
- default: //email
- IsEmail = true
- }
+ auth.InitConfig(casdoorEndpoint, clientId, clientSecret, JwtPublicKey, casdoorOrganization, casdoorApplication)
+}
- this.Data["IsEmail"] = IsEmail
- this.Data["Nickname"] = nickname
- this.Data["Avatar"] = avatar
- this.Data["Email"] = email
- this.Data["Username"] = username
- this.Data["AuthType"] = oa
- this.Data["SeoTitle"] = "完善信息"
- this.Data["Tips"] = tips
- this.Data["Id"] = id
- this.Data["GiteeClientId"] = beego.AppConfig.String("oauth::giteeClientId")
- this.Data["GiteeCallback"] = beego.AppConfig.String("oauth::giteeCallback")
- this.Data["GithubClientId"] = beego.AppConfig.String("oauth::githubClientId")
- this.Data["GithubCallback"] = beego.AppConfig.String("oauth::githubCallback")
- this.Data["QQClientId"] = beego.AppConfig.String("oauth::qqClientId")
- this.Data["QQCallback"] = beego.AppConfig.String("oauth::qqCallback")
- this.Data["RandomStr"] = time.Now().Unix()
- this.SetSession("auth", fmt.Sprintf("%v-%v", oa, id)) //存储标识,以标记是哪个用户,在完善用户信息的时候跟传递过来的auth和id进行校验
- this.TplName = "account/bind.html"
+// @Title Login
+func (c *BaseController) Login() {
+ redirectUrl := auth.GetSigninUrl(beego.AppConfig.String("oauth::redirectUrl"))
+ c.Redirect(redirectUrl, 302)
+}
+// @Title Signup
+func (c *BaseController) Signup() {
+ redirectUrl := auth.GetSignupUrl(true, beego.AppConfig.String("oauth::redirectUrl"))
+ c.Redirect(redirectUrl, 302)
}
-// Login 用户登录.
-func (this *AccountController) Login() {
+// @Title Callback
+// @Description sign in as a member
+func (c *BaseController) Callback() {
+
var (
- remember CookieRemember
- captchaOn bool //是否开启了验证码
+ nickname string //昵称
+ avatar string //头像的http链接地址
+ email string //邮箱地址
+ username string //用户名
)
- this.TplName = "account/login.html"
-
- //如果开启了验证码
- if v, ok := this.Option["ENABLED_CAPTCHA"]; ok && strings.EqualFold(v, "true") {
- captchaOn = true
- this.Data["CaptchaOn"] = captchaOn
- }
-
- oauthLogin := false
- if v, ok := this.Option["LOGIN_QQ"]; ok && strings.EqualFold(v, "true") {
- this.Data["LoginQQ"] = true
- oauthLogin = true
- }
- if v, ok := this.Option["LOGIN_GITHUB"]; ok && strings.EqualFold(v, "true") {
- this.Data["LoginGitHub"] = true
- oauthLogin = true
- }
- if v, ok := this.Option["LOGIN_GITEE"]; ok && strings.EqualFold(v, "true") {
- this.Data["LoginGitee"] = true
- oauthLogin = true
- }
- this.Data["OauthLogin"] = oauthLogin
-
- //如果Cookie中存在登录信息
- if cookie, ok := this.GetSecureCookie(conf.GetAppKey(), "login"); ok {
- if err := utils.Decode(cookie, &remember); err == nil {
- if err = this.loginByMemberId(remember.MemberId); err == nil {
- this.Redirect(beego.URLFor("HomeController.Index"), 302)
- return
- }
- }
- }
-
- if this.Ctx.Input.IsPost() {
- account := this.GetString("account")
- password := this.GetString("password")
-
- if captchaOn && !cpt.VerifyReq(this.Ctx.Request) {
- this.JsonResult(1, "验证码不正确")
- }
-
- member, err := models.NewMember().Login(account, password)
-
- //如果没有数据
- if err != nil {
- beego.Error("用户登录 =>", err)
- this.JsonResult(500, "账号或密码错误", nil)
- }
- member.LastLoginTime = time.Now()
- member.Update()
- this.SetMember(*member)
- remember.MemberId = member.MemberId
- remember.Account = member.Account
- remember.Time = time.Now()
- v, err := utils.Encode(remember)
- if err == nil {
- this.SetSecureCookie(conf.GetAppKey(), "login", v, 24*3600*365)
- }
- this.JsonResult(0, "ok")
- }
-
- this.Data["GiteeClientId"] = beego.AppConfig.String("oauth::giteeClientId")
- this.Data["GiteeCallback"] = beego.AppConfig.String("oauth::giteeCallback")
- this.Data["GithubClientId"] = beego.AppConfig.String("oauth::githubClientId")
- this.Data["GithubCallback"] = beego.AppConfig.String("oauth::githubCallback")
- this.Data["QQClientId"] = beego.AppConfig.String("oauth::qqClientId")
- this.Data["QQCallback"] = beego.AppConfig.String("oauth::qqCallback")
- this.Data["RandomStr"] = time.Now().Unix()
- this.GetSeoByPage("login", map[string]string{
- "title": "登录 - " + this.Sitename,
- "keywords": "登录," + this.Sitename,
- "description": this.Sitename + "专注于文档在线写作、协作、分享、阅读与托管,让每个人更方便地发布、分享和获得知识。",
- })
-}
-
-//用户注册.[移除用户注册,直接叫用户绑定]
-//注意:如果用户输入的账号密码跟现有的账号密码相一致,则表示绑定账号,否则表示注册新账号。
-func (this *AccountController) Bind() {
- var err error
- account := this.GetString("account")
- nickname := strings.TrimSpace(this.GetString("nickname"))
- password1 := this.GetString("password1")
- password2 := this.GetString("password2")
- email := this.GetString("email")
- oauthType := this.GetString("oauth")
- oauthId := this.GetString("id")
- avatar := this.GetString("avatar") //用户头像
- isbind, _ := this.GetInt("isbind", 0)
+ code := c.Input().Get("code")
+ state := c.Input().Get("state")
- ibind := func(oauthType string, oauthId, memberId interface{}) (err error) {
- //注册成功,绑定用户
- switch oauthType {
- case "gitee":
- err = models.ModelGitee.Bind(oauthId, memberId)
- case "github":
- err = models.ModelGithub.Bind(oauthId, memberId)
- case "qq":
- err = models.ModelQQ.Bind(oauthId, memberId)
- }
- return
+ token, err := auth.GetOAuthToken(code, state)
+ if err != nil {
+ beego.Error(err)
+ c.Abort("404")
}
- if oauthType != "email" {
- if auth, ok := this.GetSession("auth").(string); !ok || fmt.Sprintf("%v-%v", oauthType, oauthId) != auth {
- this.JsonResult(6005, "绑定信息有误,授权类型不符")
- }
- } else { //邮箱登录,如果开启了验证码,则对验证码进行校验
- if v, ok := this.Option["ENABLED_CAPTCHA"]; ok && strings.EqualFold(v, "true") {
- if !cpt.VerifyReq(this.Ctx.Request) {
- this.JsonResult(1, "验证码不正确")
- }
- }
+ claims, err := auth.ParseJwtToken(token.AccessToken)
+ if err != nil {
+ panic(err)
}
- member := models.NewMember()
-
- if isbind == 1 {
- if member, err = models.NewMember().Login(account, password1); err != nil || member.MemberId == 0 {
- beego.Error("绑定用户失败", err, member)
- this.JsonResult(1, "绑定用户失败,用户名或密码不正确")
- }
- } else {
- if password1 != password2 {
- this.JsonResult(6003, "登录密码与确认密码不一致")
- }
-
- if ok, err := regexp.MatchString(conf.RegexpAccount, account); account == "" || !ok || err != nil {
- this.JsonResult(6001, "用户名只能由英文字母数字组成,且在3-50个字符")
- }
- if l := strings.Count(password1, ""); password1 == "" || l > 50 || l < 6 {
- this.JsonResult(6002, "密码必须在6-50个字符之间")
- }
+ claims.AccessToken = token.AccessToken
+ c.SetSessionClaims(claims)
- if ok, err := regexp.MatchString(conf.RegexpEmail, email); !ok || err != nil || email == "" {
- this.JsonResult(6004, "邮箱格式不正确")
- }
- if l := strings.Count(nickname, "") - 1; l < 2 || l > 20 {
- this.JsonResult(6004, "用户昵称限制在2-20个字符")
- }
+ info := &claims.User
+ nickname = info.DisplayName
+ username = info.Name
+ avatar = info.Avatar
+ email = info.Email
- //出错或者用户不存在,则重新注册用户,否则直接登录
- member.Account = account
+ member, err := models.NewMember().FindByAccount(username)
+ if member.MemberId == 0 {
+ //用户不存在,则重新注册用户
+ member.Account = username
member.Nickname = nickname
- member.Password = password1
member.Role = conf.MemberGeneralRole
- member.Avatar = conf.GetDefaultAvatar()
+ member.Avatar = avatar
member.CreateAt = 0
member.Email = email
member.Status = 0
- if len(avatar) > 0 {
- member.Avatar = avatar
- }
if err := member.Add(); err != nil {
beego.Error(err)
- this.JsonResult(6006, err.Error())
- }
- }
- if err = this.loginByMemberId(member.MemberId); err != nil {
- beego.Error(err.Error())
- this.JsonResult(1, err.Error())
- }
-
- if err = ibind(oauthType, oauthId, member.MemberId); err != nil {
- beego.Error(err)
- this.JsonResult(0, "登录失败")
- }
-
- if oauthType == "email" {
- this.JsonResult(0, "注册成功")
- }
- this.JsonResult(0, "登录成功")
-}
-
-//找回密码.
-func (this *AccountController) FindPassword() {
-
- this.TplName = "account/find_password_setp1.html"
- mailConf := conf.GetMailConfig()
-
- if this.Ctx.Input.IsPost() {
-
- email := this.GetString("email")
-
- if email == "" {
- this.JsonResult(6005, "邮箱地址不能为空")
- }
- if !mailConf.EnableMail {
- this.JsonResult(6004, "未启用邮件服务")
- }
-
- //captcha := this.GetString("code")
- //如果开启了验证码
- //if v, ok := this.Option["ENABLED_CAPTCHA"]; ok && strings.EqualFold(v, "true") {
- // v, ok := this.GetSession(conf.CaptchaSessionName).(string)
- // if !ok || !strings.EqualFold(v, captcha) {
- // this.JsonResult(6001, "验证码不正确")
- // }
- //}
-
- if !cpt.VerifyReq(this.Ctx.Request) {
- this.JsonResult(6001, "验证码不正确")
- }
-
- member, err := models.NewMember().FindByFieldFirst("email", email)
- if err != nil {
- beego.Error(err)
- this.JsonResult(6006, "邮箱不存在")
- }
- if member.Status != 0 {
- this.JsonResult(6007, "账号已被禁用")
- }
- if member.AuthMethod == conf.AuthMethodLDAP {
- this.JsonResult(6011, "当前用户不支持找回密码")
- }
-
- count, err := models.NewMemberToken().FindSendCount(email, time.Now().Add(-1*time.Hour), time.Now())
-
- if err != nil {
- beego.Error(err)
- this.JsonResult(6008, "发送邮件失败")
- }
- if count > mailConf.MailNumber {
- this.JsonResult(6008, "发送次数太多,请稍候再试")
- }
-
- memberToken := models.NewMemberToken()
-
- memberToken.Token = string(utils.Krand(32, utils.KC_RAND_KIND_ALL))
- memberToken.Email = email
- memberToken.MemberId = member.MemberId
- memberToken.IsValid = false
- if _, err := memberToken.InsertOrUpdate(); err != nil {
- this.JsonResult(6009, "邮件发送失败")
- }
-
- data := map[string]interface{}{
- "SITE_NAME": this.Option["SITE_NAME"],
- "url": this.BaseUrl() + beego.URLFor("AccountController.FindPassword", "token", memberToken.Token, "mail", email),
- }
-
- body, err := this.ExecuteViewPathTemplate("account/mail_template.html", data)
- if err != nil {
- beego.Error(err)
- this.JsonResult(6003, "邮件发送失败")
- }
-
- if err = utils.SendMail(mailConf, "找回密码", email, body); err != nil {
- beego.Error(err)
- this.JsonResult(6003, "邮件发送失败")
- }
-
- this.JsonResult(0, "ok", this.BaseUrl()+beego.URLFor("AccountController.Login"))
- }
-
- this.GetSeoByPage("findpwd", map[string]string{
- "title": "找回密码 - " + this.Sitename,
- "keywords": "找回密码",
- "description": this.Sitename + "专注于文档在线写作、协作、分享、阅读与托管,让每个人更方便地发布、分享和获得知识。",
- })
-
- token := this.GetString("token")
- mail := this.GetString("mail")
-
- if token != "" && mail != "" {
- memberToken, err := models.NewMemberToken().FindByFieldFirst("token", token)
-
- if err != nil {
- beego.Error(err)
- this.Data["ErrorMessage"] = "邮件已失效"
- this.TplName = "errors/error.html"
- return
}
- subTime := memberToken.SendTime.Sub(time.Now())
-
- if !strings.EqualFold(memberToken.Email, mail) || subTime.Minutes() > float64(mailConf.MailExpired) || !memberToken.ValidTime.IsZero() {
- this.Data["ErrorMessage"] = "验证码已过期,请重新操作。"
- this.TplName = "errors/error.html"
- return
- }
- this.Data["Email"] = memberToken.Email
- this.Data["Token"] = memberToken.Token
- this.TplName = "account/find_password_setp2.html"
-
- }
-
-}
-
-//校验邮件并修改密码.
-func (this *AccountController) ValidEmail() {
- password1 := this.GetString("password1")
- password2 := this.GetString("password2")
- token := this.GetString("token")
- mail := this.GetString("mail")
-
- if password1 == "" {
- this.JsonResult(6001, "密码不能为空")
- }
- if l := strings.Count(password1, ""); l < 6 || l > 50 {
- this.JsonResult(6001, "密码不能为空且必须在6-50个字符之间")
- }
- if password2 == "" {
- this.JsonResult(6002, "确认密码不能为空")
- }
- if password1 != password2 {
- this.JsonResult(6003, "确认密码输入不正确")
- }
-
- if !cpt.VerifyReq(this.Ctx.Request) {
- this.JsonResult(6001, "验证码不正确")
}
- mailConf := conf.GetMailConfig()
- memberToken, err := models.NewMemberToken().FindByFieldFirst("token", token)
-
- if err != nil {
- beego.Error(err)
- this.JsonResult(6007, "邮件已失效")
- }
- subTime := memberToken.SendTime.Sub(time.Now())
-
- if !strings.EqualFold(memberToken.Email, mail) || subTime.Minutes() > float64(mailConf.MailExpired) || !memberToken.ValidTime.IsZero() {
-
- this.JsonResult(6008, "验证码已过期,请重新操作。")
- }
- member, err := models.NewMember().Find(memberToken.MemberId)
- if err != nil {
- beego.Error(err)
- this.JsonResult(6005, "用户不存在")
- }
- hash, err := utils.PasswordHash(password1)
-
- if err != nil {
- beego.Error(err)
- this.JsonResult(6006, "保存密码失败")
- }
-
- member.Password = hash
-
- err = member.Update("password")
- memberToken.ValidTime = time.Now()
- memberToken.IsValid = true
- memberToken.InsertOrUpdate()
-
- if err != nil {
- beego.Error(err)
- this.JsonResult(6006, "保存密码失败")
+ if err = c.loginByMemberId(member.MemberId); err != nil {
+ beego.Error(err.Error())
}
- this.JsonResult(0, "ok", this.BaseUrl()+beego.URLFor("AccountController.Login"))
+ c.Redirect(beego.URLFor("HomeController.Index"), 302)
}
-// Logout 退出登录.
-func (this *AccountController) Logout() {
- this.SetMember(models.Member{})
+// @Title Signout
+// @Description sign out the current member
+// @Success 200 {object} controllers.api_controller.Response The Response object
+// @router /signout [post]
+// @Tag Account API
+func (c *BaseController) Logout() {
- this.SetSecureCookie(conf.GetAppKey(), "login", "", -3600)
+ c.SetSessionClaims(nil)
+ c.SetMember(models.Member{})
- this.Redirect(beego.URLFor("AccountController.Login"), 302)
+ c.SetSecureCookie(conf.GetAppKey(), "login", "", -3600)
+ c.Redirect(beego.URLFor("HomeController.Index"), 302)
}
//记录笔记
-func (this *AccountController) Note() {
- docid, _ := this.GetInt("doc_id")
+func (c *AccountController) Note() {
+ docid, _ := c.GetInt("doc_id")
fmt.Println(docid)
- if strings.ToLower(this.Ctx.Request.Method) == "post" {
+ if strings.ToLower(c.Ctx.Request.Method) == "post" {
} else {
- this.Data["SeoTitle"] = "笔记"
- this.TplName = "account/note.html"
+ c.Data["SeoTitle"] = "笔记"
+ c.TplName = "account/note.html"
}
}
diff --git a/controllers/BaseController.go b/controllers/BaseController.go
index cd85aa03..869b8ef6 100644
--- a/controllers/BaseController.go
+++ b/controllers/BaseController.go
@@ -2,13 +2,13 @@ package controllers
import (
"bytes"
+ "encoding/gob"
"fmt"
+
"net/url"
"strconv"
"unicode/utf8"
- "github.com/TruthHun/BookStack/utils"
-
"encoding/json"
"io"
"strings"
@@ -22,8 +22,10 @@ import (
"github.com/PuerkitoBio/goquery"
"github.com/TruthHun/BookStack/conf"
"github.com/TruthHun/BookStack/models"
+ "github.com/TruthHun/BookStack/utils"
"github.com/astaxie/beego"
"github.com/astaxie/beego/orm"
+ "github.com/casdoor/casdoor-go-sdk/auth"
)
type BaseController struct {
@@ -46,8 +48,54 @@ type CookieRemember struct {
Time time.Time
}
-func (this *BaseController) refreshReferer() {
- referer := this.Ctx.Request.Header.Get("referer")
+func init() {
+ gob.Register(auth.Claims{})
+}
+
+func (c *BaseController) GetSessionClaims() *auth.Claims {
+ s := c.GetSession("user")
+ if s == nil {
+ return nil
+ }
+
+ claims := s.(auth.Claims)
+ return &claims
+}
+
+func (c *BaseController) SetSessionClaims(claims *auth.Claims) {
+ if claims == nil {
+ c.DelSession("user")
+ return
+ }
+
+ c.SetSession("user", *claims)
+}
+
+func (c *BaseController) refreshUser() {
+ //casdoor用户信息更新,需要同步
+ if c.GetSession("isUpdateUser") == 1 {
+ account := c.GetSessionClaims()
+ if account == nil {
+ c.Redirect(beego.URLFor("AccountController.Login"), 302)
+ }
+ user, err := auth.GetUser(account.Name)
+ if err != nil {
+ return
+ }
+ if member, err := models.NewMember().Find(c.Member.MemberId); err == nil {
+ member.Avatar = user.Avatar
+ member.Nickname = user.DisplayName
+ err = member.Update()
+ if err != nil {
+ c.JsonResult(60001, "更新用户信息失败")
+ }
+ }
+ c.SetSession("isUpdateUser", 0)
+ }
+}
+
+func (c *BaseController) refreshReferer() {
+ referer := c.Ctx.Request.Header.Get("referer")
if referer != "" {
referer, _ = url.QueryUnescape(referer)
referer = strings.ToLower(referer)
@@ -56,12 +104,12 @@ func (this *BaseController) refreshReferer() {
for _, item := range forbid {
item = strings.ToLower(strings.TrimSpace(item))
// 先判断是否带有非法关键字
- if item != "" && strings.Contains(referer, item) && !strings.HasSuffix(referer, strings.ToLower(this.Ctx.Request.RequestURI)) {
+ if item != "" && strings.Contains(referer, item) && !strings.HasSuffix(referer, strings.ToLower(c.Ctx.Request.RequestURI)) {
if u, err := url.Parse(referer); err == nil {
// 且referer的host与当前请求的host不是同一个,则进行302跳转以刷新过滤当前referer
- if strings.ToLower(u.Host) != strings.ToLower(this.Ctx.Request.Host) {
- this.Redirect(this.Ctx.Request.RequestURI, 302)
- this.StopRun()
+ if strings.ToLower(u.Host) != strings.ToLower(c.Ctx.Request.Host) {
+ c.Redirect(c.Ctx.Request.RequestURI, 302)
+ c.StopRun()
return
}
}
@@ -72,124 +120,124 @@ func (this *BaseController) refreshReferer() {
}
// Prepare 预处理.
-func (this *BaseController) Prepare() {
- this.refreshReferer()
-
- this.Data["Version"] = utils.Version
- this.IsMobile = utils.IsMobile(this.Ctx.Request.UserAgent())
- this.Data["IsMobile"] = this.IsMobile
- this.Member = models.NewMember() //初始化
- this.EnableAnonymous = false
- this.AllowRegister = true
- this.EnableDocumentHistory = 0
- this.OssDomain = strings.TrimRight(beego.AppConfig.String("oss::Domain"), "/ ")
- this.Data["OssDomain"] = this.OssDomain
- this.StaticDomain = strings.Trim(beego.AppConfig.DefaultString("static_domain", ""), "/")
- this.Data["StaticDomain"] = this.StaticDomain
+func (c *BaseController) Prepare() {
+ c.refreshReferer()
+
+ c.Data["Version"] = utils.Version
+ c.IsMobile = utils.IsMobile(c.Ctx.Request.UserAgent())
+ c.Data["IsMobile"] = c.IsMobile
+ c.Member = models.NewMember() //初始化
+ c.EnableAnonymous = false
+ c.AllowRegister = true
+ c.EnableDocumentHistory = 0
+ c.OssDomain = strings.TrimRight(beego.AppConfig.String("oss::Domain"), "/ ")
+ c.Data["OssDomain"] = c.OssDomain
+ c.StaticDomain = strings.Trim(beego.AppConfig.DefaultString("static_domain", ""), "/")
+ c.Data["StaticDomain"] = c.StaticDomain
//从session中获取用户信息
- if member, ok := this.GetSession(conf.LoginSessionName).(models.Member); ok && member.MemberId > 0 {
+ if member, ok := c.GetSession(conf.LoginSessionName).(models.Member); ok && member.MemberId > 0 {
m, _ := models.NewMember().Find(member.MemberId)
- this.Member = m
+ c.Member = m
} else {
//如果Cookie中存在登录信息,从cookie中获取用户信息
- if cookie, ok := this.GetSecureCookie(conf.GetAppKey(), "login"); ok {
+ if cookie, ok := c.GetSecureCookie(conf.GetAppKey(), "login"); ok {
var remember CookieRemember
err := utils.Decode(cookie, &remember)
if err == nil {
member, err := models.NewMember().Find(remember.MemberId)
if err == nil {
- this.SetMember(*member)
- this.Member = member
+ c.SetMember(*member)
+ c.Member = member
}
}
}
}
- if this.Member.RoleName == "" {
- this.Member.ResolveRoleName()
+ if c.Member.RoleName == "" {
+ c.Member.ResolveRoleName()
}
- this.Data["Member"] = this.Member
- this.Data["BaseUrl"] = this.BaseUrl()
- this.Data["IsSignedToday"] = false
- if this.Member.MemberId > 0 {
- this.Data["IsSignedToday"] = models.NewSign().IsSignToday(this.Member.MemberId)
+ c.Data["Member"] = c.Member
+ c.Data["BaseUrl"] = c.BaseUrl()
+ c.Data["IsSignedToday"] = false
+ if c.Member.MemberId > 0 {
+ c.Data["IsSignedToday"] = models.NewSign().IsSignToday(c.Member.MemberId)
}
if options, err := models.NewOption().All(); err == nil {
- this.Option = make(map[string]string, len(options))
+ c.Option = make(map[string]string, len(options))
for _, item := range options {
if item.OptionName == "SITE_NAME" {
- this.Sitename = item.OptionValue
+ c.Sitename = item.OptionValue
}
- this.Data[item.OptionName] = item.OptionValue
- this.Option[item.OptionName] = item.OptionValue
+ c.Data[item.OptionName] = item.OptionValue
+ c.Option[item.OptionName] = item.OptionValue
if strings.EqualFold(item.OptionName, "ENABLE_ANONYMOUS") && item.OptionValue == "true" {
- this.EnableAnonymous = true
+ c.EnableAnonymous = true
}
if strings.EqualFold(item.OptionName, "ENABLED_REGISTER") && item.OptionValue == "false" {
- this.AllowRegister = false
+ c.AllowRegister = false
}
if verNum, _ := strconv.Atoi(item.OptionValue); strings.EqualFold(item.OptionName, "ENABLE_DOCUMENT_HISTORY") && verNum > 0 {
- this.EnableDocumentHistory = verNum
+ c.EnableDocumentHistory = verNum
}
}
}
- if v, ok := this.Option["CLOSE_OPEN_SOURCE_LINK"]; ok {
- this.Data["CloseOpenSourceLink"] = v == "true"
+ if v, ok := c.Option["CLOSE_OPEN_SOURCE_LINK"]; ok {
+ c.Data["CloseOpenSourceLink"] = v == "true"
}
- if v, ok := this.Option["HIDE_TAG"]; ok {
- this.Data["HideTag"] = v == "true"
+ if v, ok := c.Option["HIDE_TAG"]; ok {
+ c.Data["HideTag"] = v == "true"
}
- if v, ok := this.Option["CLOSE_SUBMIT_ENTER"]; ok {
- this.Data["CloseSubmitEnter"] = v == "true"
+ if v, ok := c.Option["CLOSE_SUBMIT_ENTER"]; ok {
+ c.Data["CloseSubmitEnter"] = v == "true"
}
- this.Data["SiteName"] = this.Sitename
+ c.Data["SiteName"] = c.Sitename
// 默认显示创建书籍的入口
ShowCreateBookEntrance := false
- if this.Member.MemberId > 0 {
+ if c.Member.MemberId > 0 {
ShowCreateBookEntrance = true
if opt, err := models.NewOption().FindByKey("ALL_CAN_WRITE_BOOK"); err == nil {
- if opt.OptionValue == "false" && this.Member.Role == conf.MemberGeneralRole {
+ if opt.OptionValue == "false" && c.Member.Role == conf.MemberGeneralRole {
// 如果用户现在是普通用户,但是之前是作者或者之前有新建书籍书籍的权限并且创建了书籍,则也给用户显示入口
- ShowCreateBookEntrance = models.NewRelationship().HasRelatedBook(this.Member.MemberId)
+ ShowCreateBookEntrance = models.NewRelationship().HasRelatedBook(c.Member.MemberId)
}
}
}
- this.Data["ShowCreateBookEntrance"] = ShowCreateBookEntrance
+ c.Data["ShowCreateBookEntrance"] = ShowCreateBookEntrance
- if this.Member.MemberId == 0 {
- if this.EnableAnonymous == false && !this.NoNeedLoginRouter { // 不允许游客访问
+ if c.Member.MemberId == 0 {
+ if c.EnableAnonymous == false && !c.NoNeedLoginRouter { // 不允许游客访问
allowPaths := map[string]bool{
beego.URLFor("AccountController.Login"): true,
beego.URLFor("AccountController.Logout"): true,
beego.URLFor("AccountController.FindPassword"): true,
beego.URLFor("AccountController.ValidEmail"): true,
}
- if _, ok := allowPaths[this.Ctx.Request.URL.Path]; !ok {
- this.Redirect(beego.URLFor("AccountController.Login"), 302)
+ if _, ok := allowPaths[c.Ctx.Request.URL.Path]; !ok {
+ c.Redirect(beego.URLFor("AccountController.Login"), 302)
return
}
}
- if this.AllowRegister == false { // 不允许用户注册
+ if c.AllowRegister == false { // 不允许用户注册
denyPaths := map[string]bool{
// 第三方登录,如果是新注册的话,需要绑定信息,这里不让绑定信息就是不让注册
beego.URLFor("AccountController.Bind"): true,
// 禁止邮箱注册
beego.URLFor("AccountController.Oauth", ":oauth", "email"): true,
}
- if _, ok := denyPaths[this.Ctx.Request.URL.Path]; ok {
- this.Redirect("/login", 302)
+ if _, ok := denyPaths[c.Ctx.Request.URL.Path]; ok {
+ c.Redirect("/login", 302)
return
}
}
@@ -198,20 +246,20 @@ func (this *BaseController) Prepare() {
}
// SetMember 获取或设置当前登录用户信息,如果 MemberId 小于 0 则标识删除 Session
-func (this *BaseController) SetMember(member models.Member) {
+func (c *BaseController) SetMember(member models.Member) {
if member.MemberId <= 0 {
- this.DelSession(conf.LoginSessionName)
- this.DelSession("uid")
- this.DestroySession()
+ c.DelSession(conf.LoginSessionName)
+ c.DelSession("uid")
+ c.DestroySession()
} else {
- this.SetSession(conf.LoginSessionName, member)
- this.SetSession("uid", member.MemberId)
+ c.SetSession(conf.LoginSessionName, member)
+ c.SetSession("uid", member.MemberId)
}
}
// JsonResult 响应 json 结果
-func (this *BaseController) JsonResult(errCode int, errMsg string, data ...interface{}) {
+func (c *BaseController) JsonResult(errCode int, errMsg string, data ...interface{}) {
jsonData := make(map[string]interface{}, 3)
jsonData["errcode"] = errCode
jsonData["message"] = errMsg
@@ -223,29 +271,29 @@ func (this *BaseController) JsonResult(errCode int, errMsg string, data ...inter
if err != nil {
beego.Error(err)
}
- this.Ctx.ResponseWriter.Header().Set("Content-Type", "application/json; charset=utf-8")
+ c.Ctx.ResponseWriter.Header().Set("Content-Type", "application/json; charset=utf-8")
//this.Ctx.ResponseWriter.Header().Set("Cache-Control", "no-cache, no-store")//解决回退出现json的问题
//使用gzip原始,json数据会只有原本数据的10分之一左右
- if strings.Contains(strings.ToLower(this.Ctx.Request.Header.Get("Accept-Encoding")), "gzip") {
- this.Ctx.ResponseWriter.Header().Set("Content-Encoding", "gzip")
+ if strings.Contains(strings.ToLower(c.Ctx.Request.Header.Get("Accept-Encoding")), "gzip") {
+ c.Ctx.ResponseWriter.Header().Set("Content-Encoding", "gzip")
//gzip压缩
- w := gzip.NewWriter(this.Ctx.ResponseWriter)
+ w := gzip.NewWriter(c.Ctx.ResponseWriter)
defer w.Close()
w.Write(returnJSON)
w.Flush()
} else {
- io.WriteString(this.Ctx.ResponseWriter, string(returnJSON))
+ io.WriteString(c.Ctx.ResponseWriter, string(returnJSON))
}
- this.StopRun()
+ c.StopRun()
}
// ExecuteViewPathTemplate 执行指定的模板并返回执行结果.
-func (this *BaseController) ExecuteViewPathTemplate(tplName string, data interface{}) (string, error) {
+func (c *BaseController) ExecuteViewPathTemplate(tplName string, data interface{}) (string, error) {
var buf bytes.Buffer
- viewPath := this.ViewPath
+ viewPath := c.ViewPath
- if this.ViewPath == "" {
+ if c.ViewPath == "" {
viewPath = beego.BConfig.WebConfig.ViewsPath
}
@@ -256,33 +304,33 @@ func (this *BaseController) ExecuteViewPathTemplate(tplName string, data interfa
return buf.String(), nil
}
-func (this *BaseController) BaseUrl() string {
+func (c *BaseController) BaseUrl() string {
host := beego.AppConfig.String("sitemap_host")
if len(host) > 0 {
if strings.HasPrefix(host, "http://") || strings.HasPrefix(host, "https://") {
return host
}
- return this.Ctx.Input.Scheme() + "://" + host
+ return c.Ctx.Input.Scheme() + "://" + host
}
- return this.Ctx.Input.Scheme() + "://" + this.Ctx.Request.Host
+ return c.Ctx.Input.Scheme() + "://" + c.Ctx.Request.Host
}
//显示错误信息页面.
-func (this *BaseController) ShowErrorPage(errCode int, errMsg string) {
- this.TplName = "errors/error.html"
- this.Data["ErrorMessage"] = errMsg
- this.Data["ErrorCode"] = errCode
- this.StopRun()
+func (c *BaseController) ShowErrorPage(errCode int, errMsg string) {
+ c.TplName = "errors/error.html"
+ c.Data["ErrorMessage"] = errMsg
+ c.Data["ErrorCode"] = errCode
+ c.StopRun()
}
//根据页面获取seo
//@param page 页面标识
//@param defSeo 默认的seo的map,必须有title、keywords和description字段
-func (this *BaseController) GetSeoByPage(page string, defSeo map[string]string) {
+func (c *BaseController) GetSeoByPage(page string, defSeo map[string]string) {
var seo models.Seo
orm.NewOrm().QueryTable(models.TableSeo).Filter("Page", page).One(&seo)
- defSeo["sitename"] = this.Sitename
+ defSeo["sitename"] = c.Sitename
if seo.Id > 0 {
for k, v := range defSeo {
seo.Title = strings.Replace(seo.Title, fmt.Sprintf("{%v}", k), v, -1)
@@ -290,29 +338,29 @@ func (this *BaseController) GetSeoByPage(page string, defSeo map[string]string)
seo.Description = strings.Replace(seo.Description, fmt.Sprintf("{%v}", k), v, -1)
}
}
- this.Data["SeoTitle"] = seo.Title
- this.Data["SeoKeywords"] = seo.Keywords
- this.Data["SeoDescription"] = seo.Description
+ c.Data["SeoTitle"] = seo.Title
+ c.Data["SeoKeywords"] = seo.Keywords
+ c.Data["SeoDescription"] = seo.Description
}
//站点地图
-func (this *BaseController) Sitemap() {
- this.Data["SeoTitle"] = "站点地图 - " + this.Sitename
- page, _ := this.GetInt("page")
+func (c *BaseController) Sitemap() {
+ c.Data["SeoTitle"] = "站点地图 - " + c.Sitename
+ page, _ := c.GetInt("page")
listRows := 100
totalCount, docs := models.SitemapData(page, listRows)
if totalCount > 0 {
- html := utils.GetPagerHtml(this.Ctx.Request.RequestURI, page, listRows, int(totalCount))
- this.Data["PageHtml"] = html
+ html := utils.GetPagerHtml(c.Ctx.Request.RequestURI, page, listRows, int(totalCount))
+ c.Data["PageHtml"] = html
} else {
- this.Data["PageHtml"] = ""
+ c.Data["PageHtml"] = ""
}
//this.JsonResult(0, "aaa", docs)
- this.Data["Docs"] = docs
- this.TplName = "widgets/sitemap.html"
+ c.Data["Docs"] = docs
+ c.TplName = "widgets/sitemap.html"
}
-func (this *BaseController) loginByMemberId(memberId int) (err error) {
+func (c *BaseController) loginByMemberId(memberId int) (err error) {
member, err := models.NewMember().Find(memberId)
if member.MemberId == 0 {
return errors.New("用户不存在")
@@ -323,20 +371,20 @@ func (this *BaseController) loginByMemberId(memberId int) (err error) {
}
member.LastLoginTime = time.Now()
member.Update()
- this.SetMember(*member)
+ c.SetMember(*member)
var remember CookieRemember
remember.MemberId = member.MemberId
remember.Account = member.Account
remember.Time = time.Now()
v, err := utils.Encode(remember)
if err == nil {
- this.SetSecureCookie(conf.GetAppKey(), "login", v, 24*3600*365)
+ c.SetSecureCookie(conf.GetAppKey(), "login", v, 24*3600*365)
}
return err
}
//在markdown头部加上或者,即解析markdown中的ul>li>a链接作为目录
-func (this *BaseController) sortBySummary(bookIdentify, htmlStr string, bookId int) string {
+func (c *BaseController) sortBySummary(bookIdentify, htmlStr string, bookId int) string {
debug := beego.AppConfig.String("runmod") != "prod"
o := orm.NewOrm()
qs := o.QueryTable("md_documents").Filter("book_id", bookId)
@@ -450,7 +498,7 @@ func (this *BaseController) sortBySummary(bookIdentify, htmlStr string, bookId i
htmlStr, _ = doc.Find("body").Html()
if len(hrefs) > 0 { //如果有新创建的文档,则再调用一遍,用于处理排序
- htmlStr = this.replaceLinks(bookIdentify, htmlStr, true)
+ htmlStr = c.replaceLinks(bookIdentify, htmlStr, true)
}
return htmlStr
}
@@ -465,7 +513,7 @@ type Sort struct {
//替换链接
//如果是summary,则根据这个进行排序调整
-func (this *BaseController) replaceLinks(bookIdentify string, docHtml string, isSummary ...bool) string {
+func (c *BaseController) replaceLinks(bookIdentify string, docHtml string, isSummary ...bool) string {
var (
book models.Book
docs []models.Document
@@ -510,7 +558,7 @@ func (this *BaseController) replaceLinks(bookIdentify string, docHtml string, is
if newHtml, err := gq.Find("body").Html(); err == nil {
docHtml = newHtml
if len(isSummary) > 0 && isSummary[0] == true { //更新排序
- docHtml = this.sortBySummary(bookIdentify, docHtml, book.BookId) //更新排序
+ docHtml = c.sortBySummary(bookIdentify, docHtml, book.BookId) //更新排序
}
}
} else {
@@ -522,58 +570,58 @@ func (this *BaseController) replaceLinks(bookIdentify string, docHtml string, is
}
//内容采集
-func (this *BaseController) Crawl() {
- if this.Member.MemberId > 0 {
- if val, ok := this.GetSession("crawl").(string); ok && val == "1" {
- this.JsonResult(1, "您提交的上一次采集未完成,请稍后再提交新的内容采集")
+func (c *BaseController) Crawl() {
+ if c.Member.MemberId > 0 {
+ if val, ok := c.GetSession("crawl").(string); ok && val == "1" {
+ c.JsonResult(1, "您提交的上一次采集未完成,请稍后再提交新的内容采集")
}
- this.SetSession("crawl", "1")
- defer this.DelSession("crawl")
- urlStr := this.GetString("url")
- force, _ := this.GetBool("force") //是否是强力采集,强力采集,使用Chrome
- intelligence, _ := this.GetInt("intelligence") //是否是强力采集,强力采集,使用Chrome
- contType, _ := this.GetInt("type")
- diySel := this.GetString("diy")
+ c.SetSession("crawl", "1")
+ defer c.DelSession("crawl")
+ urlStr := c.GetString("url")
+ force, _ := c.GetBool("force") //是否是强力采集,强力采集,使用Chrome
+ intelligence, _ := c.GetInt("intelligence") //是否是强力采集,强力采集,使用Chrome
+ contType, _ := c.GetInt("type")
+ diySel := c.GetString("diy")
content, err := utils.CrawlHtml2Markdown(urlStr, contType, force, intelligence, diySel, []string{}, nil)
if err != nil {
- this.JsonResult(1, "采集失败:"+err.Error())
+ c.JsonResult(1, "采集失败:"+err.Error())
}
- this.JsonResult(0, "采集成功", content)
+ c.JsonResult(0, "采集成功", content)
}
- this.JsonResult(1, "请先登录再操作")
+ c.JsonResult(1, "请先登录再操作")
}
//关注或取消关注
-func (this *BaseController) SetFollow() {
+func (c *BaseController) SetFollow() {
var cancel bool
- if this.Member == nil || this.Member.MemberId == 0 {
- this.JsonResult(1, "请先登录")
+ if c.Member == nil || c.Member.MemberId == 0 {
+ c.JsonResult(1, "请先登录")
}
- uid, _ := this.GetInt(":uid")
- if uid == this.Member.MemberId {
- this.JsonResult(1, "自己不能关注自己")
+ uid, _ := c.GetInt(":uid")
+ if uid == c.Member.MemberId {
+ c.JsonResult(1, "自己不能关注自己")
}
- cancel, _ = new(models.Fans).FollowOrCancel(uid, this.Member.MemberId)
+ cancel, _ = new(models.Fans).FollowOrCancel(uid, c.Member.MemberId)
if cancel {
- this.JsonResult(0, "您已经成功取消了关注")
+ c.JsonResult(0, "您已经成功取消了关注")
}
- this.JsonResult(0, "您已经成功关注了Ta")
+ c.JsonResult(0, "您已经成功关注了Ta")
}
-func (this *BaseController) SignToday() {
- if this.Member == nil || this.Member.MemberId == 0 {
- this.JsonResult(1, "请先登录")
+func (c *BaseController) SignToday() {
+ if c.Member == nil || c.Member.MemberId == 0 {
+ c.JsonResult(1, "请先登录")
}
- reward, err := models.NewSign().Sign(this.Member.MemberId, false)
+ reward, err := models.NewSign().Sign(c.Member.MemberId, false)
if err != nil {
- this.JsonResult(1, "签到失败:"+err.Error())
+ c.JsonResult(1, "签到失败:"+err.Error())
}
- this.JsonResult(0, fmt.Sprintf("恭喜您,签到成功,奖励阅读时长 %v 秒", reward))
+ c.JsonResult(0, fmt.Sprintf("恭喜您,签到成功,奖励阅读时长 %v 秒", reward))
}
-func (this *BaseController) forbidGeneralRole() bool {
+func (c *BaseController) forbidGeneralRole() bool {
// 如果只有作者和管理员才能写作的话,那么已创建了书籍的普通用户无法将书籍转为公开或者是私密分享
- if this.Member.Role == conf.MemberGeneralRole && models.GetOptionValue("ALL_CAN_WRITE_BOOK", "true") != "true" {
+ if c.Member.Role == conf.MemberGeneralRole && models.GetOptionValue("ALL_CAN_WRITE_BOOK", "true") != "true" {
return true
}
return false
diff --git a/controllers/SettingController.go b/controllers/SettingController.go
index df3583f5..724517e7 100644
--- a/controllers/SettingController.go
+++ b/controllers/SettingController.go
@@ -3,21 +3,18 @@ package controllers
import (
"os"
"path/filepath"
- "strconv"
"strings"
"time"
- "github.com/TruthHun/BookStack/graphics"
- "github.com/TruthHun/BookStack/models/store"
-
"fmt"
"github.com/TruthHun/BookStack/conf"
"github.com/TruthHun/BookStack/models"
+ "github.com/TruthHun/BookStack/models/store"
"github.com/TruthHun/BookStack/utils"
"github.com/astaxie/beego"
- "github.com/astaxie/beego/logs"
"github.com/astaxie/beego/orm"
+ "github.com/casdoor/casdoor-go-sdk/auth"
)
type SettingController struct {
@@ -26,91 +23,14 @@ type SettingController struct {
//基本信息
func (this *SettingController) Index() {
- if this.Ctx.Input.IsPost() {
- email := strings.TrimSpace(this.GetString("email", ""))
- phone := strings.TrimSpace(this.GetString("phone"))
- wechatNO := strings.TrimSpace(this.GetString("wechat_no"))
- description := strings.TrimSpace(this.GetString("description"))
- nickname := strings.TrimSpace(this.GetString("nickname"))
- if email == "" {
- this.JsonResult(601, "邮箱不能为空")
- }
-
- if l := strings.Count(nickname, "") - 1; l < 2 || l > 20 {
- this.JsonResult(6004, "用户昵称限制在2-20个字符")
- }
-
- existMember := models.NewMember().FindByNickname(nickname, "member_id")
- if existMember.MemberId > 0 && this.Member.MemberId != existMember.MemberId {
- this.JsonResult(6004, "用户昵称已存在,请换一个")
- }
-
- member := this.Member
- member.Email = email
- member.Phone = phone
- member.WechatNO = wechatNO
- member.Description = description
- if err := member.Update(); err != nil {
- this.JsonResult(602, err.Error())
- }
- this.SetMember(*member)
- this.JsonResult(0, "ok")
- }
- this.Data["SeoTitle"] = "基本信息 - " + this.Sitename
- this.Data["SettingBasic"] = true
- this.TplName = "setting/index.html"
-}
-
-//修改密码
-func (this *SettingController) Password() {
-
- if this.Ctx.Input.IsPost() {
- if this.Member.AuthMethod == conf.AuthMethodLDAP {
- this.JsonResult(6009, "当前用户不支持修改密码")
- }
- password1 := this.GetString("password1")
- password2 := this.GetString("password2")
- password3 := this.GetString("password3")
- if password1 == "" {
- this.JsonResult(6003, "原密码不能为空")
- }
-
- if password2 == "" {
- this.JsonResult(6004, "新密码不能为空")
- }
-
- if count := strings.Count(password2, ""); count < 6 || count > 18 {
- this.JsonResult(6009, "密码必须在6-18字之间")
- }
-
- if password2 != password3 {
- this.JsonResult(6003, "确认密码不正确")
- }
-
- if ok, _ := utils.PasswordVerify(this.Member.Password, password1); !ok {
- this.JsonResult(6005, "原始密码不正确")
- }
-
- if password1 == password2 {
- this.JsonResult(6006, "新密码不能和原始密码相同")
- }
-
- pwd, err := utils.PasswordHash(password2)
- if err != nil {
- this.JsonResult(6007, "密码加密失败")
- }
-
- this.Member.Password = pwd
- if err := this.Member.Update(); err != nil {
- this.JsonResult(6008, err.Error())
- }
-
- this.JsonResult(0, "ok")
+ this.SetSession("isUpdateUser", 1)
+ account := this.GetSessionClaims()
+ if account == nil {
+ this.Redirect(beego.URLFor("AccountController.Login"), 302)
+ } else {
+ myProfileUrl := auth.GetMyProfileUrl(account.AccessToken)
+ this.Redirect(myProfileUrl, 302)
}
-
- this.Data["SettingPwd"] = true
- this.Data["SeoTitle"] = "修改密码 - " + this.Sitename
- this.TplName = "setting/password.html"
}
//收藏
@@ -225,100 +145,3 @@ func (this *SettingController) Qrcode() {
this.Data["Qrcode"] = new(models.Member).GetQrcodeByUid(this.Member.MemberId)
this.Data["SettingQrcode"] = true
}
-
-// Upload 上传图片
-func (this *SettingController) Upload() {
-
- file, moreFile, err := this.GetFile("image-file")
- if err != nil {
- logs.Error("", err.Error())
- this.JsonResult(500, "读取文件异常")
- }
- defer file.Close()
-
- ext := filepath.Ext(moreFile.Filename)
- if !strings.EqualFold(ext, ".png") && !strings.EqualFold(ext, ".jpg") && !strings.EqualFold(ext, ".gif") && !strings.EqualFold(ext, ".jpeg") {
- this.JsonResult(500, "不支持的图片格式")
- }
-
- x1, _ := strconv.ParseFloat(this.GetString("x"), 10)
- y1, _ := strconv.ParseFloat(this.GetString("y"), 10)
- w1, _ := strconv.ParseFloat(this.GetString("width"), 10)
- h1, _ := strconv.ParseFloat(this.GetString("height"), 10)
-
- x := int(x1)
- y := int(y1)
- width := int(w1)
- height := int(h1)
-
- // fmt.Println(x, x1, y, y1)
-
- fileName := strconv.FormatInt(time.Now().UnixNano(), 16)
-
- filePath := filepath.Join("uploads", time.Now().Format("2006/01"), fileName+ext)
-
- path := filepath.Dir(filePath)
-
- os.MkdirAll(path, os.ModePerm)
-
- err = this.SaveToFile("image-file", filePath)
-
- if err != nil {
- logs.Error("", err)
- this.JsonResult(500, "图片保存失败")
- }
-
- //剪切图片
- subImg, err := graphics.ImageCopyFromFile(filePath, x, y, width, height)
-
- if err != nil {
- logs.Error("ImageCopyFromFile => ", err)
- this.JsonResult(6001, "头像剪切失败")
- }
- os.Remove(filePath)
-
- filePath = filepath.Join("uploads", time.Now().Format("200601"), fileName+ext)
-
- err = graphics.ImageResizeSaveFile(subImg, 120, 120, filePath)
- err = graphics.SaveImage(filePath, subImg)
-
- if err != nil {
- logs.Error("保存文件失败 => ", err.Error())
- this.JsonResult(500, "保存文件失败")
- }
-
- url := "/" + strings.Replace(filePath, "\\", "/", -1)
- if strings.HasPrefix(url, "//") {
- url = string(url[1:])
- }
-
- if member, err := models.NewMember().Find(this.Member.MemberId); err == nil {
- avatar := member.Avatar
- member.Avatar = url
- err = member.Update()
- if err != nil {
- this.JsonResult(60001, "保存头像失败")
- }
- avatar = strings.TrimLeft(avatar, "./")
- if strings.HasPrefix(avatar, "uploads/") {
- os.Remove(avatar)
- }
- this.SetMember(*member)
- }
- switch utils.StoreType {
- case utils.StoreOss: //oss存储
- if err := store.ModelStoreOss.MoveToOss("."+url, strings.TrimLeft(url, "./"), true, false); err != nil {
- beego.Error(err.Error())
- } else {
- url = strings.TrimRight(beego.AppConfig.String("oss::Domain"), "/ ") + url + "/avatar"
- }
- case utils.StoreLocal: //本地存储
- if err := store.ModelStoreLocal.MoveToStore("."+url, strings.TrimLeft(url, "./")); err != nil {
- beego.Error(err.Error())
- } else {
- url = "/" + strings.TrimLeft(url, "./")
- }
- }
-
- this.JsonResult(0, "ok", url)
-}
diff --git a/controllers/UserController.go b/controllers/UserController.go
index 5d194d7d..1bca9902 100644
--- a/controllers/UserController.go
+++ b/controllers/UserController.go
@@ -49,6 +49,7 @@ func (this *UserController) Index() {
books, totalCount, _ := models.NewBook().FindToPager(page, pageSize, this.UcenterMember.MemberId, 0)
this.Data["Books"] = books
+ this.refreshUser()
if totalCount > 0 {
html := utils.NewPaginations(conf.RollPage, totalCount, pageSize, page, beego.URLFor("UserController.Index", ":username", this.UcenterMember.Account), "")
this.Data["PageHtml"] = html
diff --git a/controllers/token_jwt_key.pem b/controllers/token_jwt_key.pem
new file mode 100644
index 00000000..c2d6d5f5
--- /dev/null
+++ b/controllers/token_jwt_key.pem
@@ -0,0 +1,29 @@
+-----BEGIN CERTIFICATE-----
+MIIE+TCCAuGgAwIBAgIDAeJAMA0GCSqGSIb3DQEBCwUAMDYxHTAbBgNVBAoTFENh
+c2Rvb3IgT3JnYW5pemF0aW9uMRUwEwYDVQQDEwxDYXNkb29yIENlcnQwHhcNMjEx
+MDE1MDgxMTUyWhcNNDExMDE1MDgxMTUyWjA2MR0wGwYDVQQKExRDYXNkb29yIE9y
+Z2FuaXphdGlvbjEVMBMGA1UEAxMMQ2FzZG9vciBDZXJ0MIICIjANBgkqhkiG9w0B
+AQEFAAOCAg8AMIICCgKCAgEAsInpb5E1/ym0f1RfSDSSE8IR7y+lw+RJjI74e5ej
+rq4b8zMYk7HeHCyZr/hmNEwEVXnhXu1P0mBeQ5ypp/QGo8vgEmjAETNmzkI1NjOQ
+CjCYwUrasO/f/MnI1C0j13vx6mV1kHZjSrKsMhYY1vaxTEP3+VB8Hjg3MHFWrb07
+uvFMCJe5W8+0rKErZCKTR8+9VB3janeBz//zQePFVh79bFZate/hLirPK0Go9P1g
+OvwIoC1A3sarHTP4Qm/LQRt0rHqZFybdySpyWAQvhNaDFE7mTstRSBb/wUjNCUBD
+PTSLVjC04WllSf6Nkfx0Z7KvmbPstSj+btvcqsvRAGtvdsB9h62Kptjs1Yn7GAuo
+I3qt/4zoKbiURYxkQJXIvwCQsEftUuk5ew5zuPSlDRLoLByQTLbx0JqLAFNfW3g/
+pzSDjgd/60d6HTmvbZni4SmjdyFhXCDb1Kn7N+xTojnfaNkwep2REV+RMc0fx4Gu
+hRsnLsmkmUDeyIZ9aBL9oj11YEQfM2JZEq+RVtUx+wB4y8K/tD1bcY+IfnG5rBpw
+IDpS262boq4SRSvb3Z7bB0w4ZxvOfJ/1VLoRftjPbLIf0bhfr/AeZMHpIKOXvfz4
+yE+hqzi68wdF0VR9xYc/RbSAf7323OsjYnjjEgInUtRohnRgCpjIk/Mt2Kt84Kb0
+wn8CAwEAAaMQMA4wDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQsFAAOCAgEAn2lf
+DKkLX+F1vKRO/5gJ+Plr8P5NKuQkmwH97b8CS2gS1phDyNgIc4/LSdzuf4Awe6ve
+C06lVdWSIis8UPUPdjmT2uMPSNjwLxG3QsrimMURNwFlLTfRem/heJe0Zgur9J1M
+8haawdSdJjH2RgmFoDeE2r8NVRfhbR8KnCO1ddTJKuS1N0/irHz21W4jt4rxzCvl
+2nR42Fybap3O/g2JXMhNNROwZmNjgpsF7XVENCSuFO1jTywLaqjuXCg54IL7XVLG
+omKNNNcc8h1FCeKj/nnbGMhodnFWKDTsJcbNmcOPNHo6ixzqMy/Hqc+mWYv7maAG
+Jtevs3qgMZ8F9Qzr3HpUc6R3ZYYWDY/xxPisuKftOPZgtH979XC4mdf0WPnOBLqL
+2DJ1zaBmjiGJolvb7XNVKcUfDXYw85ZTZQ5b9clI4e+6bmyWqQItlwt+Ati/uFEV
+XzCj70B4lALX6xau1kLEpV9O1GERizYRz5P9NJNA7KoO5AVMp9w0DQTkt+LbXnZE
+HHnWKy8xHQKZF9sR7YBPGLs/Ac6tviv5Ua15OgJ/8dLRZ/veyFfGo2yZsI+hKVU5
+nCCJHBcAyFnm1hdvdwEdH33jDBjNB6ciotJZrf/3VYaIWSalADosHAgMWfXuWP+h
+8XKXmzlxuHbTMQYtZPDgspS5aK+S4Q9wb8RRAYo=
+-----END CERTIFICATE-----
diff --git a/go.mod b/go.mod
index 72a3f719..3b8e73eb 100644
--- a/go.mod
+++ b/go.mod
@@ -1,6 +1,6 @@
module github.com/TruthHun/BookStack
-go 1.13
+go 1.16
replace github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8 => github.com/ugorji/go v1.1.7
@@ -17,6 +17,7 @@ require (
github.com/astaxie/beego v1.12.0
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f // indirect
github.com/boombuler/barcode v1.0.0
+ github.com/casdoor/casdoor-go-sdk v0.4.1
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/disintegration/imaging v1.6.1
github.com/go-sql-driver/mysql v1.5.0
@@ -31,7 +32,6 @@ require (
github.com/stretchr/testify v1.6.1 // indirect
github.com/unknwon/com v1.0.1
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad // indirect
- golang.org/x/image v0.0.0-20190802002840-cff245a6509b // indirect
golang.org/x/net v0.0.0-20201224014010-6772e930b67b // indirect
golang.org/x/sys v0.0.0-20201223074533-0d417f636930 // indirect
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1 // indirect
diff --git a/go.sum b/go.sum
index 985cffae..fa20a549 100644
--- a/go.sum
+++ b/go.sum
@@ -1,15 +1,45 @@
-github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
+cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
+cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
+cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
+cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
+cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
+cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
+cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
+cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
+cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
+cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
+cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
+cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
+cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
+cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
+cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
+cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
+cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
+cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
+cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
+cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
+cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
+cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
+cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
+cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
+cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
+cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
+cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
+cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
+cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
+dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/OwnLocal/goes v1.0.0/go.mod h1:8rIFjBGTue3lCU0wplczcUgt9Gxgrkkrw7etMIcn8TM=
-github.com/PuerkitoBio/goquery v1.5.0 h1:uGvmFXOA73IKluu/F84Xd1tt/z07GYm8X49XKHP7EJk=
github.com/PuerkitoBio/goquery v1.5.0/go.mod h1:qD2PgZ9lccMbQlc7eEOjaeRlFQON7xY8kdmcsrnKqMg=
github.com/PuerkitoBio/goquery v1.6.0 h1:j7taAbelrdcsOlGeMenZxc2AWXD5fieT1/znArdnx94=
github.com/PuerkitoBio/goquery v1.6.0/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
github.com/TruthHun/converter v0.0.0-20180618131031-80268d67d7a8 h1:E+006K+eHyJkdvR1IPv8jFGA9zvuK47OxlNKoDxMvWM=
github.com/TruthHun/converter v0.0.0-20180618131031-80268d67d7a8/go.mod h1:bW/ArSdu0OB6XR3NcPdPBIEeGdQ1GLW9fQavW3Auy2A=
-github.com/TruthHun/gotil v0.0.0-20191003091818-17b80aad8a45 h1:o+hC+QvRJlpj6meIX4AC/LKi7UxdEWFs+6zOsLzGoBs=
-github.com/TruthHun/gotil v0.0.0-20191003091818-17b80aad8a45/go.mod h1:0V5BlPJa24R0PzuXVURUfjaQ8Z7cmqsVSW7ftuhesN0=
github.com/TruthHun/gotil v0.0.0-20210817134928-d2d642c3c7b7 h1:TL0LZ/cmjfX0sEsygVruVoJNGR9krd8UiTPlSg4nT+o=
github.com/TruthHun/gotil v0.0.0-20210817134928-d2d642c3c7b7/go.mod h1:i5tqOvH+rsm0voXHnKkzayNkWnv8L/F7wVv+mBdrAL0=
github.com/TruthHun/html2article v0.0.0-20180202140721-67d6ff09647b h1:JXD7vWKiJGRqkRuitwA8BxJVGr1yp2hQULQII7RaAXo=
@@ -20,9 +50,7 @@ github.com/alexcesaro/mail v0.0.0-20141015155039-29068ce49a17 h1:S0JNYJ6Gv0RGmbz
github.com/alexcesaro/mail v0.0.0-20141015155039-29068ce49a17/go.mod h1:WVybKoXJAI3a3TlXlkzIMWs3SmoF29WtmOgInQpL0Ps=
github.com/aliyun/aliyun-oss-go-sdk v2.1.0+incompatible h1:90Z2Cp7EqcbaYfVwVjmQoK8kgoFPz+doQlujcwe1BRg=
github.com/aliyun/aliyun-oss-go-sdk v2.1.0+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
-github.com/andybalholm/cascadia v1.0.0 h1:hOCXnnZ5A+3eVDX8pvgl4kofXv2ELss0bKcqRySc45o=
github.com/andybalholm/cascadia v1.0.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
-github.com/andybalholm/cascadia v1.1.0 h1:BuuO6sSfQNFRu1LppgbD25Hr2vLYW25JvxHs5zzsLTo=
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
github.com/andybalholm/cascadia v1.2.0 h1:vuRCkM5Ozh/BfmsaTm26kbjm0mIOM3yS5Ek/F5h18aE=
github.com/andybalholm/cascadia v1.2.0/go.mod h1:YCyR8vOZT9aZ1CHEd8ap0gMVm2aFgxBp0T0eFw1RUQY=
@@ -41,7 +69,15 @@ github.com/boombuler/barcode v1.0.0 h1:s1TvRnXwL2xJRaccrdcBQMZxq6X7DvsMogtmJeHDd
github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60=
github.com/casbin/casbin v1.7.0/go.mod h1:c67qKN6Oum3UF5Q1+BByfFxkwKvhwW57ITjqwtzR1KE=
+github.com/casdoor/casdoor-go-sdk v0.4.1 h1:rCvfmMlxLqSx05kFkDGJ6xh5w4/+mSKny8HA/8JA8Js=
+github.com/casdoor/casdoor-go-sdk v0.4.1/go.mod h1:MBed3ISHQfXTtoOCAk5T8l5lt4wFvsyynrw0awggydY=
+github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
+github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
+github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80=
+github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
@@ -60,47 +96,96 @@ github.com/disintegration/imaging v1.6.1/go.mod h1:xuIt+sRxDFrHS0drzXUlCJthkJ8k7
github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
github.com/elazarl/go-bindata-assetfs v1.0.0 h1:G/bYguwHIzWq9ZoyUQqrjTmJbbYn3j3CKKpKinvZLFk=
github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
-github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
+github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
+github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
-github.com/gin-contrib/cors v1.3.0 h1:PolezCc89peu+NgkIWt9OB01Kbzt6IP0J/JvkG6xxlg=
github.com/gin-contrib/cors v1.3.0/go.mod h1:artPvLlhkF7oG06nK8v3U8TNz6IeX+w1uzCSEId5/Vc=
-github.com/gin-contrib/gzip v0.0.1 h1:ezvKOL6jH+jlzdHNE4h9h8q8uMpDQjyl0NN0Jd7jozc=
github.com/gin-contrib/gzip v0.0.1/go.mod h1:fGBJBCdt6qCZuCAOwWuFhBB4OOq9EFqlo5dEaFhhu5w=
github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
-github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3 h1:t8FVkw33L+wilf2QiWkw0UV77qRpcH/JHPKGpKa2E8g=
github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
github.com/gin-gonic/gin v1.3.0/go.mod h1:7cKuhb5qV2ggCFctp2fJQ+ErvciLZrIeoOSOm6mUr7Y=
-github.com/gin-gonic/gin v1.4.0 h1:3tMoCCfM7ppqsR0ptz/wi1impNpT7/9wQtMZ8lr1mCQ=
github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM=
+github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
+github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
+github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-redis/redis v6.14.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
-github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/golang-jwt/jwt/v4 v4.1.0 h1:XUgk2Ex5veyVFVeLm0xhusUTQybEbexJXrvPNOKkSY0=
+github.com/golang-jwt/jwt/v4 v4.1.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
+github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
+github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
+github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
+github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
+github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
+github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
+github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
+github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
+github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
+github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.1 h1:JFrFEBb2xKufg6XkJsJr+WbKb4FQlURi5RUcBveYu9k=
+github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
+github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
+github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
+github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1ks85zJ1lfDGgIiMDuIptTOhJq+zKyg=
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
-github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
+github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
-github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
+github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
-github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
-github.com/jtolds/gls v4.2.1+incompatible h1:fSuqC+Gmlu6l/ZYAoZzx2pyucC8Xza35fpRVWLVmUEE=
+github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
+github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/kardianos/service v1.0.0 h1:HgQS3mFfOlyntWX8Oke98JcJLqt1DBcHR4kxShpYef0=
github.com/kardianos/service v1.0.0/go.mod h1:8CzDhVuCuugtsHyZoTvsOBuvonN/UDBvl0kH+BUxvbo=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
@@ -110,29 +195,25 @@ github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lifei6671/gocaptcha v0.0.0-20190301083731-c467a25bc100 h1:DkXBDLKHcTtca65BA9tZoFdWMZ9YJtNm5YyC36tKX2U=
github.com/lifei6671/gocaptcha v0.0.0-20190301083731-c467a25bc100/go.mod h1:jEGhhJ8Op4YifySgvIySNtK5vxJta0V8nwwu+1uoVmE=
-github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
-github.com/mattn/go-isatty v0.0.7 h1:UvyT9uN+3r7yLEYSlJsbQGdsaB/a0DlgWP3pql6iwOc=
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-sqlite3 v1.10.0 h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK860o=
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
-github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
-github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
-github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mssola/user_agent v0.5.0 h1:gRF7/x8cKt8qzAosYGsBNyirta+F8fvYDlJrgXws9AQ=
github.com/mssola/user_agent v0.5.0/go.mod h1:UFiKPVaShrJGW93n4uo8dpPdg1BSVpw2P9bneo0Mtp8=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
-github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday v2.0.0+incompatible h1:cBXrhZNUf9C+La9/YpS+UHpUT8YD6Td9ZMSU9APFcsk=
github.com/russross/blackfriday v2.0.0+incompatible/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
@@ -148,8 +229,10 @@ github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726/go.mod h1:3yhqj7WBBf
github.com/siddontang/ledisdb v0.0.0-20181029004158-becf5f38d373/go.mod h1:mF1DpOSOUiJRMR+FDqaqu3EBqrybQtrDDszLUZ6oxPg=
github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
+github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304 h1:Jpy1PXuP99tXNrhbq2BaPz9B+jNAvH1JPQQpG/9GCXY=
github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s=
+github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
@@ -161,6 +244,8 @@ github.com/ssdb/gossdb v0.0.0-20180723034631-88f6b59b84ec/go.mod h1:QBvMkMya+gXc
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/syndtr/goleveldb v0.0.0-20181127023241-353a9fca669c/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
@@ -171,51 +256,276 @@ github.com/unknwon/com v1.0.1 h1:3d1LTxD+Lnf3soQiD4Cp/0BRB+Rsa/+RTvz8GMMzIXs=
github.com/unknwon/com v1.0.1/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM=
github.com/wendal/errors v0.0.0-20130201093226-f66c77a7882b/go.mod h1:Q12BUT7DqIlHRmgv3RskH+UCM/4eqVMgI0EMmlSpAXc=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
+github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
+go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
+go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY=
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
+golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
+golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
+golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
+golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b h1:+qEpEAPhDZ1o0x3tHzZTQDArnOixOzGD9HUJfcg0mb4=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
+golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
+golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
+golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
+golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
+golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
+golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+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=
+golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201224014010-6772e930b67b h1:iFwSg7t5GZmB/Q5TjiEAsdoLDrdJRC1RiF2WhuV29Qw=
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c h1:pkQiBZBvdos9qq4wBAHqlzuZHEXo07pqV06ef90u1WI=
+golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201223074533-0d417f636930 h1:vRgIt+nup/B/BwIS0g2oC0haq0iqbV3ZA+u6+0TlNCo=
golang.org/x/sys v0.0.0-20201223074533-0d417f636930/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
+golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1 h1:NusfzzA6yGQ+ua51ck7E3omNUX/JuqbFSaRGqU8CcLI=
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/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-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
+golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
+golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
+golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+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=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
+google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
+google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
+google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
+google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
+google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
+google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc=
+google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
+google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
+google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
+google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
+google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
+google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
+google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
+google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
+google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
+google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
+google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
+google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
+google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
+google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
+google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
+google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
+google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
+google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
+google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
+google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d h1:TxyelI5cVkbREznMhfzycHdkp5cLA7DpE+GKjSslYhM=
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
gopkg.in/ldap.v2 v2.5.1 h1:wiu0okdNfjlBzg6UWvd1Hn8Y+Ux17/u/4nlk4CQr6tU=
@@ -224,4 +534,15 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
+honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
+honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
+rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
+rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
+rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
diff --git a/models/member.go b/models/member.go
index e19b9a5c..a831821a 100644
--- a/models/member.go
+++ b/models/member.go
@@ -169,10 +169,6 @@ func (m *Member) Add() error {
return errors.New("邮箱格式不正确")
}
- if l := strings.Count(m.Password, ""); l < 7 || l >= 50 {
- return errors.New("密码不能为空且必须在6-50个字符之间")
- }
-
cond := orm.NewCondition().Or("email", m.Email).Or("nickname", m.Nickname).Or("account", m.Account)
var one Member
if o.QueryTable(m.TableNameWithPrefix()).SetCond(cond).One(&one, "member_id", "nickname", "account", "email"); one.MemberId > 0 {
@@ -217,9 +213,6 @@ func (m *Member) Add() error {
func (m *Member) Update(cols ...string) error {
o := orm.NewOrm()
- if m.Email == "" {
- return errors.New("邮箱不能为空")
- }
if _, err := o.Update(m, cols...); err != nil {
return err
}
diff --git a/routers/web.go b/routers/web.go
index 5163d404..2bd8b212 100644
--- a/routers/web.go
+++ b/routers/web.go
@@ -16,13 +16,9 @@ func webRouter() {
beego.Router("/submit", &controllers.SubmitController{}, "post:Post")
beego.Router("/login", &controllers.AccountController{}, "*:Login")
- beego.Router("/login/:oauth", &controllers.AccountController{}, "*:Oauth")
+ beego.Router("/signup", &controllers.AccountController{}, "*:Signup")
+ beego.Router("/login/callback", &controllers.AccountController{}, "*:Callback")
beego.Router("/logout", &controllers.AccountController{}, "*:Logout")
- beego.Router("/bind", &controllers.AccountController{}, "post:Bind")
- beego.Router("/note", &controllers.AccountController{}, "get,post:Note")
- beego.Router("/find_password", &controllers.AccountController{}, "*:FindPassword")
- beego.Router("/valid_email", &controllers.AccountController{}, "post:ValidEmail")
- //beego.Router("/captcha", &controllers.AccountController{}, "*:Captcha")
beego.Router("/manager", &controllers.ManagerController{}, "*:Index")
beego.Router("/manager/users", &controllers.ManagerController{}, "*:Users")
@@ -73,8 +69,6 @@ func webRouter() {
beego.Router("/manager/del-tags", &controllers.ManagerController{}, "get:DelTags")
beego.Router("/setting", &controllers.SettingController{}, "*:Index")
- beego.Router("/setting/password", &controllers.SettingController{}, "*:Password")
- beego.Router("/setting/upload", &controllers.SettingController{}, "*:Upload")
beego.Router("/setting/star", &controllers.SettingController{}, "*:Star")
beego.Router("/setting/qrcode", &controllers.SettingController{}, "*:Qrcode")
diff --git a/views/account/bind.html b/views/account/bind.html
deleted file mode 100644
index 17374ba8..00000000
--- a/views/account/bind.html
+++ /dev/null
@@ -1,135 +0,0 @@
-
-
-
- {{template "widgets/head.html" .}}
-
-
-
-
-
-{{/**/}}
-
-{{/**/}}
-
-
-
-{{/*js直接写在这里了*/}}
-
-
-
\ No newline at end of file
diff --git a/views/account/find_password_setp1.html b/views/account/find_password_setp1.html
deleted file mode 100644
index b8978701..00000000
--- a/views/account/find_password_setp1.html
+++ /dev/null
@@ -1,112 +0,0 @@
-
-
-
- {{template "widgets/head.html" .}}
-
-
-
-
-{{template "widgets/footer.html" .}}
-
-
-
-
-
-
\ No newline at end of file
diff --git a/views/account/find_password_setp2.html b/views/account/find_password_setp2.html
deleted file mode 100644
index 4ae2360d..00000000
--- a/views/account/find_password_setp2.html
+++ /dev/null
@@ -1,125 +0,0 @@
-
-
-
-{{template "widgets/head.html" .}}
-
-
-
-
-{{template "widgets/footer.html" .}}
-
-
-
-
-
\ No newline at end of file
diff --git a/views/account/mail_template.html b/views/account/mail_template.html
deleted file mode 100644
index 875c1c6d..00000000
--- a/views/account/mail_template.html
+++ /dev/null
@@ -1,98 +0,0 @@
-
-
-
-
-
- 找回密码 - {{.SITE_NAME}}
-
-
-
-
-
-
-
-
-
-
您好:
-
-
您在 {{.SITE_NAME}} 提交了找回密码申请。
如果您没有提交修改密码的申请, 请忽略本邮件
-
-
- 请点击链接继续: {{.url}}
-
-
- 好的密码,不但应该容易记住,还要尽量符合以下强度标准:
-
- - 包含大小写字母、数字和符号
- - 不少于 10 位
- - 不包含生日、手机号码等易被猜出的信息
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/views/setting/index.html b/views/setting/index.html
deleted file mode 100644
index 9c9dd8d6..00000000
--- a/views/setting/index.html
+++ /dev/null
@@ -1,219 +0,0 @@
-
-
-
- {{template "widgets/head.html" .}}
-
-
-
-
-
-
- {{template "widgets/header.html" .}}
-
-
-
- {{template "setting/menu.html" .}}
-
-
-
-
-
-
-
-
-
-{{/**/}}
-
-{{/**/}}
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/views/setting/menu.html b/views/setting/menu.html
index a2bdce26..a46c2bff 100644
--- a/views/setting/menu.html
+++ b/views/setting/menu.html
@@ -1,9 +1,6 @@
{{else}}
-
注册
+
注册
登录
{{end}}