版本预发布

This commit is contained in:
孟帅
2023-02-08 20:29:34 +08:00
parent f11c7c5bf2
commit 2068d05c93
269 changed files with 16122 additions and 12075 deletions

View File

@@ -9,25 +9,26 @@ package admin
import (
"context"
"github.com/gogf/gf/v2/crypto/gmd5"
"github.com/gogf/gf/v2/encoding/gbase64"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gconv"
"github.com/gogf/gf/v2/util/grand"
"hotgo/api/backend/member"
"hotgo/internal/consts"
"hotgo/internal/dao"
"hotgo/internal/library/contexts"
"hotgo/internal/library/hgorm/handler"
"hotgo/internal/library/hgorm/hook"
"hotgo/internal/library/jwt"
"hotgo/internal/library/location"
"hotgo/internal/model"
"hotgo/internal/model/do"
"hotgo/internal/model/entity"
"hotgo/internal/model/input/adminin"
"hotgo/internal/model/input/sysin"
"hotgo/internal/service"
"hotgo/utility/encrypt"
"hotgo/utility/simple"
"hotgo/utility/tree"
"hotgo/utility/validate"
)
@@ -42,7 +43,148 @@ func init() {
service.RegisterAdminMember(NewAdminMember())
}
// UpdateProfile 更新会员资料
// UpdateCash 修改提现信息
func (s *sAdminMember) UpdateCash(ctx context.Context, in adminin.MemberUpdateCashInp) (err error) {
memberId := contexts.Get(ctx).User.Id
if memberId <= 0 {
err = gerror.New("获取用户信息失败!")
return
}
var memberInfo entity.AdminMember
if err = dao.AdminMember.Ctx(ctx).Where("id", memberId).Scan(&memberInfo); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return
}
if gmd5.MustEncryptString(in.Password+memberInfo.Salt) != memberInfo.PasswordHash {
err = gerror.New("登录密码不正确")
return
}
_, err = dao.AdminMember.Ctx(ctx).
Where("id", memberId).
Data(g.Map{
"cash": adminin.MemberCash{
Name: in.Name,
Account: in.Account,
PayeeCode: in.PayeeCode,
},
}).
Update()
return
}
// UpdateEmail 换绑邮箱
func (s *sAdminMember) UpdateEmail(ctx context.Context, in adminin.MemberUpdateEmailInp) (err error) {
memberId := contexts.Get(ctx).User.Id
if memberId <= 0 {
err = gerror.New("获取用户信息失败!")
return err
}
var memberInfo *entity.AdminMember
if err = dao.AdminMember.Ctx(ctx).Where("id", memberId).Scan(&memberInfo); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
if memberInfo == nil {
err = gerror.New("用户信息不存在")
return err
}
if memberInfo.Email == in.Email {
err = gerror.New("新旧邮箱不能一样")
return
}
if !validate.IsEmail(in.Email) {
err = gerror.New("邮箱地址不正确")
return
}
// 存在原绑定号码,需要进行验证
if memberInfo.Email != "" {
err = service.SysEmsLog().VerifyCode(ctx, sysin.VerifyEmsCodeInp{
Event: consts.EmsTemplateBind,
Email: memberInfo.Email,
Code: in.Code,
})
if err != nil {
return err
}
}
update := g.Map{
dao.AdminMember.Columns().Email: in.Email,
}
_, err = dao.AdminMember.Ctx(ctx).Where("id", memberId).Data(update).Update()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
return
}
// UpdateMobile 换绑手机号
func (s *sAdminMember) UpdateMobile(ctx context.Context, in adminin.MemberUpdateMobileInp) (err error) {
memberId := contexts.Get(ctx).User.Id
if memberId <= 0 {
err = gerror.New("获取用户信息失败!")
return err
}
var memberInfo *entity.AdminMember
if err = dao.AdminMember.Ctx(ctx).Where("id", memberId).Scan(&memberInfo); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
if memberInfo == nil {
err = gerror.New("用户信息不存在")
return err
}
if memberInfo.Mobile == in.Mobile {
err = gerror.New("新旧手机号不能一样")
return
}
if !validate.IsMobile(in.Mobile) {
err = gerror.New("手机号码不正确")
return
}
// 存在原绑定号码,需要进行验证
if memberInfo.Mobile != "" {
err = service.SysSmsLog().VerifyCode(ctx, sysin.VerifyCodeInp{
Event: consts.SmsTemplateBind,
Mobile: memberInfo.Mobile,
Code: in.Code,
})
if err != nil {
return err
}
}
update := g.Map{
dao.AdminMember.Columns().Mobile: in.Mobile,
}
_, err = dao.AdminMember.Ctx(ctx).Where("id", memberId).Data(update).Update()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
return
}
// UpdateProfile 更新用户资料
func (s *sAdminMember) UpdateProfile(ctx context.Context, in adminin.MemberUpdateProfileInp) (err error) {
memberId := contexts.Get(ctx).User.Id
if memberId <= 0 {
@@ -50,21 +192,28 @@ func (s *sAdminMember) UpdateProfile(ctx context.Context, in adminin.MemberUpdat
return err
}
var memberInfo entity.AdminMember
var memberInfo *entity.AdminMember
if err = dao.AdminMember.Ctx(ctx).Where("id", memberId).Scan(&memberInfo); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
_, err = dao.AdminMember.Ctx(ctx).
Where("id", memberId).
Data(g.Map{
"mobile": in.Mobile,
"email": in.Email,
"real_name": in.Realname,
}).
Update()
if memberInfo == nil {
err = gerror.New("用户信息不存在")
return err
}
update := g.Map{
dao.AdminMember.Columns().Avatar: in.Avatar,
dao.AdminMember.Columns().RealName: in.RealName,
dao.AdminMember.Columns().Qq: in.Qq,
dao.AdminMember.Columns().Birthday: in.Birthday,
dao.AdminMember.Columns().Sex: in.Sex,
dao.AdminMember.Columns().CityId: in.CityId,
dao.AdminMember.Columns().Address: in.Address,
}
_, err = dao.AdminMember.Ctx(ctx).Where("id", memberId).Data(update).Update()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
@@ -104,19 +253,25 @@ func (s *sAdminMember) UpdatePwd(ctx context.Context, in adminin.MemberUpdatePwd
// ResetPwd 重置密码
func (s *sAdminMember) ResetPwd(ctx context.Context, in adminin.MemberResetPwdInp) (err error) {
var (
memberInfo entity.AdminMember
memberInfo *entity.AdminMember
memberId = contexts.GetUserId(ctx)
)
if err = dao.AdminMember.Ctx(ctx).Where("id", in.Id).Scan(&memberInfo); err != nil {
if err = s.FilterAuthModel(ctx, memberId).Where("id", in.Id).Scan(&memberInfo); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
if memberInfo == nil {
err = gerror.New("用户信息不存在")
return err
}
if memberInfo.Pid != memberId && !s.VerifySuperId(ctx, memberId) {
err = gerror.New("操作非法")
return err
}
_, err = dao.AdminMember.Ctx(ctx).
_, err = s.FilterAuthModel(ctx, memberId).
Where("id", in.Id).
Data(g.Map{
"password_hash": gmd5.MustEncryptString(in.Password + memberInfo.Salt),
@@ -192,7 +347,7 @@ func (s *sAdminMember) Delete(ctx context.Context, in adminin.MemberDeleteInp) e
return gerror.New("获取用户信息失败!")
}
_, err := dao.AdminMember.Ctx(ctx).Where("id", in.Id).Where("pid", memberId).Delete()
_, err := s.FilterAuthModel(ctx, memberId).Where("id", in.Id).Delete()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
@@ -246,11 +401,7 @@ func (s *sAdminMember) Edit(ctx context.Context, in adminin.MemberEditInp) (err
}
// 权限验证
var mm = dao.AdminMember.Ctx(ctx).Where("id", in.Id)
if !s.VerifySuperId(ctx, opMemberId) {
mm = mm.Where("pid", opMemberId)
}
var mm = s.FilterAuthModel(ctx, opMemberId).Where("id", in.Id)
_, err = mm.Data(in).Update()
if err != nil {
return gerror.Wrap(err, consts.ErrorORM)
@@ -307,7 +458,7 @@ func (s *sAdminMember) MaxSort(ctx context.Context, in adminin.MemberMaxSortInp)
// View 获取信息
func (s *sAdminMember) View(ctx context.Context, in adminin.MemberViewInp) (res *adminin.MemberViewModel, err error) {
if err = dao.AdminMember.Ctx(ctx).Where("id", in.Id).Scan(&res); err != nil {
if err = s.FilterAuthModel(ctx, contexts.GetUserId(ctx)).Hook(hook.MemberInfo).Where("id", in.Id).Scan(&res); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return nil, err
}
@@ -317,10 +468,9 @@ func (s *sAdminMember) View(ctx context.Context, in adminin.MemberViewInp) (res
// List 获取列表
func (s *sAdminMember) List(ctx context.Context, in adminin.MemberListInp) (list []*adminin.MemberListModel, totalCount int, err error) {
g.Log().Printf(ctx, "in:%#v", in)
mod := dao.AdminMember.Ctx(ctx)
if in.Realname != "" {
mod = mod.WhereLike("real_name", "%"+in.Realname+"%")
mod := s.FilterAuthModel(ctx, contexts.GetUserId(ctx))
if in.RealName != "" {
mod = mod.WhereLike("real_name", "%"+in.RealName+"%")
}
if in.Username != "" {
mod = mod.WhereLike("username", "%"+in.Username+"%")
@@ -349,32 +499,11 @@ func (s *sAdminMember) List(ctx context.Context, in adminin.MemberListInp) (list
return list, totalCount, nil
}
if err = mod.Page(in.Page, in.PerPage).Order("id desc").Scan(&list); err != nil {
if err = mod.Hook(hook.MemberInfo).Page(in.Page, in.PerPage).Order("id desc").Scan(&list); err != nil {
return nil, 0, gerror.Wrap(err, consts.ErrorORM)
}
// 重写树入参
for i := 0; i < len(list); i++ {
// 部门
deptName, err := dao.AdminDept.Ctx(ctx).
Fields("name").
Where("id", list[i].DeptId).
Value()
if err != nil {
return nil, 0, gerror.Wrap(err, consts.ErrorORM)
}
list[i].DeptName = deptName.String()
// 角色
roleName, err := dao.AdminRole.Ctx(ctx).
Fields("name").
Where("id", list[i].RoleId).
Value()
if err != nil {
return nil, 0, gerror.Wrap(err, consts.ErrorORM)
}
list[i].RoleName = roleName.String()
// 岗位
posts, err := dao.AdminMemberPost.Ctx(ctx).
Fields("post_id").
@@ -414,27 +543,43 @@ func (s *sAdminMember) genTree(ctx context.Context, pid int64) (level int, newTr
}
// LoginMemberInfo 获取登录用户信息
func (s *sAdminMember) LoginMemberInfo(ctx context.Context, req *member.InfoReq) (res *adminin.MemberLoginModel, err error) {
identity := contexts.Get(ctx).User
if identity == nil {
func (s *sAdminMember) LoginMemberInfo(ctx context.Context) (res *adminin.LoginMemberInfoModel, err error) {
var memberId = contexts.GetUserId(ctx)
if memberId <= 0 {
err = gerror.New("用户身份异常,请重新登录!")
return
}
permissions, err := service.AdminMenu().LoginPermissions(ctx, identity.Id)
err = dao.AdminMember.Ctx(ctx).
Hook(hook.MemberInfo).
Where("id", memberId).
Scan(&res)
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return
}
res = &adminin.MemberLoginModel{
UserId: identity.Id,
Username: identity.Username,
RealName: identity.RealName,
Avatar: identity.Avatar,
Permissions: permissions,
Token: jwt.GetAuthorization(ghttp.RequestFromCtx(ctx)),
if res == nil {
err = gerror.New("用户不存在!")
return
}
// 细粒度权限
permissions, err := service.AdminMenu().LoginPermissions(ctx, memberId)
if err != nil {
return
}
res.Permissions = permissions
// 登录统计
stat, err := s.MemberLoginStat(ctx, adminin.MemberLoginStatInp{MemberId: memberId})
if err != nil {
return nil, err
}
res.MemberLoginStatModel = stat
res.Mobile = gstr.HideStr(res.Mobile, 40, `*`)
res.Email = gstr.HideStr(res.Email, 40, `*`)
return
}
@@ -443,11 +588,7 @@ func (s *sAdminMember) Login(ctx context.Context, in adminin.MemberLoginInp) (re
var (
roleInfo *entity.AdminRole
memberInfo *entity.AdminMember
identity *model.Identity
timestamp = gtime.Timestamp()
expires = g.Cfg().MustGet(ctx, "jwt.expires", 1).Int64()
exp = gconv.Int64(timestamp) + expires
lastIp = location.GetClientIp(ghttp.RequestFromCtx(ctx))
)
err = dao.AdminMember.Ctx(ctx).Where("username", in.Username).Scan(&memberInfo)
@@ -465,18 +606,13 @@ func (s *sAdminMember) Login(ctx context.Context, in adminin.MemberLoginInp) (re
return
}
// 解密密码
password, err := gbase64.Decode([]byte(in.Password))
err = simple.CheckPassword(in.Password, memberInfo.Salt, memberInfo.PasswordHash)
if err != nil {
return nil, err
}
password, err = encrypt.AesECBDecrypt(password, consts.RequestEncryptKey)
if err != nil {
return nil, err
return
}
if memberInfo.PasswordHash != gmd5.MustEncryptString(string(password)+memberInfo.Salt) {
err = gerror.New("用户密码不正确")
if memberInfo.Status != consts.StatusEnabled {
err = gerror.New("账号已被禁用")
return
}
@@ -494,27 +630,24 @@ func (s *sAdminMember) Login(ctx context.Context, in adminin.MemberLoginInp) (re
}
if roleInfo.Status != consts.StatusEnabled {
err = gerror.New("角色权限已被禁用")
err = gerror.New("角色已被禁用")
return
}
identity = &model.Identity{
Id: memberInfo.Id,
Pid: memberInfo.Pid,
DeptId: memberInfo.DeptId,
RoleId: roleInfo.Id,
RoleKey: roleInfo.Key,
Username: memberInfo.Username,
RealName: memberInfo.RealName,
Avatar: memberInfo.Avatar,
Email: memberInfo.Email,
Mobile: memberInfo.Mobile,
VisitCount: memberInfo.VisitCount,
LastTime: memberInfo.LastTime,
LastIp: lastIp,
Exp: exp,
Expires: expires,
App: consts.AppAdmin,
identity := &model.Identity{
Id: memberInfo.Id,
Pid: memberInfo.Pid,
DeptId: memberInfo.DeptId,
RoleId: roleInfo.Id,
RoleKey: roleInfo.Key,
Username: memberInfo.Username,
RealName: memberInfo.RealName,
Avatar: memberInfo.Avatar,
Email: memberInfo.Email,
Mobile: memberInfo.Mobile,
Exp: gtime.Timestamp() + expires,
Expires: expires,
App: consts.AppAdmin,
}
token, err := jwt.GenerateLoginToken(ctx, identity, false)
@@ -524,14 +657,10 @@ func (s *sAdminMember) Login(ctx context.Context, in adminin.MemberLoginInp) (re
}
// 更新登录信息
_, err = dao.AdminMember.Ctx(ctx).Data(do.AdminMember{
AuthKey: gmd5.MustEncryptString(token),
VisitCount: memberInfo.VisitCount + 1,
LastTime: timestamp,
LastIp: lastIp,
}).Where(do.AdminMember{
Id: memberInfo.Id,
}).Update()
_, err = dao.AdminMember.Ctx(ctx).
Data(do.AdminMember{AuthKey: gmd5.MustEncryptString(token)}).
Where(do.AdminMember{Id: memberInfo.Id}).
Update()
if err != nil {
err = gerror.New(err.Error())
@@ -539,17 +668,15 @@ func (s *sAdminMember) Login(ctx context.Context, in adminin.MemberLoginInp) (re
}
res = &adminin.MemberLoginModel{
UserId: identity.Id,
Username: identity.Username,
RealName: identity.RealName,
Avatar: identity.Avatar,
Token: token,
Id: identity.Id,
Token: token,
Expires: expires,
}
return res, nil
}
// RoleMemberList 获取角色下的会员列表
// RoleMemberList 获取角色下的用户列表
func (s *sAdminMember) RoleMemberList(ctx context.Context, in adminin.RoleMemberListInp) (list []*adminin.MemberListModel, totalCount int, err error) {
mod := dao.AdminMember.Ctx(ctx)
if in.Role > 0 {
@@ -594,7 +721,7 @@ func (s *sAdminMember) Status(ctx context.Context, in adminin.MemberStatusInp) (
// 修改
in.UpdatedAt = gtime.Now()
_, err = dao.AdminMember.Ctx(ctx).Where("id", in.Id).Data("status", in.Status).Update()
_, err = s.FilterAuthModel(ctx, contexts.GetUserId(ctx)).Where("id", in.Id).Data("status", in.Status).Update()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
@@ -603,7 +730,7 @@ func (s *sAdminMember) Status(ctx context.Context, in adminin.MemberStatusInp) (
return nil
}
// GetIdByCode 通过邀请码获取会员ID
// GetIdByCode 通过邀请码获取用户ID
func (s *sAdminMember) GetIdByCode(ctx context.Context, in adminin.GetIdByCodeInp) (res *adminin.GetIdByCodeModel, err error) {
if err = dao.AdminMember.Ctx(ctx).
Fields("invite_code").
@@ -615,3 +742,53 @@ func (s *sAdminMember) GetIdByCode(ctx context.Context, in adminin.GetIdByCodeIn
return res, nil
}
// Select 获取可选的用户选项
func (s *sAdminMember) Select(ctx context.Context, in adminin.MemberSelectInp) (res []*adminin.MemberSelectModel, err error) {
err = dao.AdminMember.Ctx(ctx).
Fields("id as value,real_name as label,username,avatar").
Handler(handler.FilterAuthWithField("id")).
Scan(&res)
if err != nil {
return nil, gerror.Wrap(err, consts.ErrorORM)
}
return res, nil
}
func (s *sAdminMember) FilterAuthModel(ctx context.Context, memberId int64) *gdb.Model {
m := dao.AdminMember.Ctx(ctx)
if !s.VerifySuperId(ctx, memberId) {
m = m.Where("id <> ?", memberId)
}
return m.Handler(handler.FilterAuthWithField("id"))
}
// MemberLoginStat 用户登录统计
func (s *sAdminMember) MemberLoginStat(ctx context.Context, in adminin.MemberLoginStatInp) (res *adminin.MemberLoginStatModel, err error) {
var models *entity.SysLoginLog
err = dao.SysLoginLog.Ctx(ctx).
Fields("login_at,login_ip").
Where("member_id", in.MemberId).
Where("status", consts.StatusEnabled).
Scan(&models)
if err != nil {
return nil, err
}
res = new(adminin.MemberLoginStatModel)
if models == nil {
return
}
res.LastLoginAt = models.LoginAt
res.LastLoginIp = models.LoginIp
res.LoginCount, err = dao.SysLoginLog.Ctx(ctx).
Where("member_id", in.MemberId).
Where("status", consts.StatusEnabled).Count()
if err != nil {
return nil, err
}
return
}

View File

@@ -39,7 +39,7 @@ func (s *sAdminMemberPost) UpdatePostIds(ctx context.Context, member_id int64, p
PostId: post_ids[i],
})
if err != nil {
err = gerror.Wrap(err, "插入会员岗位失败")
err = gerror.Wrap(err, "插入用户岗位失败")
return err
}
}
@@ -47,7 +47,7 @@ func (s *sAdminMemberPost) UpdatePostIds(ctx context.Context, member_id int64, p
return nil
}
// GetMemberByIds 获取指定会员的岗位ids
// GetMemberByIds 获取指定用户的岗位ids
func (s *sAdminMemberPost) GetMemberByIds(ctx context.Context, member_id int64) (post_ids []int64, err error) {
var list []*entity.AdminMemberPost
err = dao.AdminMemberPost.Ctx(ctx).

View File

@@ -23,6 +23,7 @@ import (
"hotgo/internal/model/entity"
"hotgo/internal/model/input/adminin"
"hotgo/internal/service"
"hotgo/utility/convert"
"hotgo/utility/tree"
)
@@ -369,13 +370,8 @@ func (s *sAdminMenu) GetMenuList(ctx context.Context, memberId int64) (lists rol
return
}
// LoginPermissions 获取登录成功后的细权限
func (s *sAdminMenu) LoginPermissions(ctx context.Context, memberId int64) (lists []*adminin.MemberLoginPermissions, err error) {
// 空跑
lists = append(lists, &adminin.MemberLoginPermissions{
Value: "value",
})
// LoginPermissions 获取登录成功后的细粒度权限
func (s *sAdminMenu) LoginPermissions(ctx context.Context, memberId int64) (lists adminin.MemberLoginPermissions, err error) {
type Permissions struct {
Permissions string `json:"permissions"`
}
@@ -401,17 +397,18 @@ func (s *sAdminMenu) LoginPermissions(ctx context.Context, memberId int64) (list
return lists, err
}
// 无权限
if len(allPermissions) == 0 {
lists = append(lists, "value")
return
}
for _, v := range allPermissions {
for _, p := range gstr.Explode(`,`, v.Permissions) {
lists = append(lists, &adminin.MemberLoginPermissions{
Value: p,
})
lists = append(lists, p)
}
}
lists = convert.UniqueSliceString(lists)
return
}

View File

@@ -8,17 +8,22 @@ package admin
import (
"context"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/util/gconv"
"hotgo/internal/consts"
"hotgo/internal/dao"
"hotgo/internal/library/contexts"
"hotgo/internal/library/hgorm/handler"
"hotgo/internal/model/entity"
"hotgo/internal/model/input/adminin"
"hotgo/internal/model/input/form"
"hotgo/internal/service"
"hotgo/internal/websocket"
"hotgo/utility/charset"
"hotgo/utility/simple"
"hotgo/utility/validate"
"strings"
)
type sAdminNotice struct{}
@@ -31,9 +36,14 @@ func init() {
service.RegisterAdminNotice(NewAdminNotice())
}
// Model Orm模型
func (s *sAdminNotice) Model(ctx context.Context, option ...*handler.Option) *gdb.Model {
return handler.Model(dao.AdminNotice.Ctx(ctx), option...)
}
// Delete 删除
func (s *sAdminNotice) Delete(ctx context.Context, in adminin.NoticeDeleteInp) error {
_, err := dao.AdminNotice.Ctx(ctx).Where("id", in.Id).Delete()
_, err := s.Model(ctx).Where("id", in.Id).Delete()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
@@ -44,44 +54,64 @@ func (s *sAdminNotice) Delete(ctx context.Context, in adminin.NoticeDeleteInp) e
// Edit 修改/新增
func (s *sAdminNotice) Edit(ctx context.Context, in adminin.NoticeEditInp) (err error) {
var member = contexts.Get(ctx).User
if member == nil {
err = gerror.New("获取用户信息失败!")
return
}
if in.Title == "" {
err = gerror.New("标题不能为空")
return err
return
}
if in.Type == consts.NoticeTypeLetter && len(in.Receiver) == 0 {
err = gerror.New("私信类型必须选择接收人")
return
}
// 检查选项接收人是否合法
if in.Type == consts.NoticeTypeLetter {
count, _ := dao.AdminMember.Ctx(ctx).Handler(handler.FilterAuthWithField("id")).WhereIn("id", in.Receiver).Count()
if count != len(in.Receiver) {
err = gerror.New("接收人不合法")
return
}
in.SenderAvatar = member.Avatar
}
// 修改
in.UpdatedAt = gtime.Now()
if in.Id > 0 {
_, err = dao.AdminNotice.Ctx(ctx).Where("id", in.Id).Data(in).Update()
in.UpdatedBy = member.Id
_, err = s.Model(ctx).Where("id", in.Id).Data(in).Update()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
return nil
}
// 新增
in.CreatedBy = member.Id
in.CreatedAt = gtime.Now()
_, err = dao.AdminNotice.Ctx(ctx).Data(in).Insert()
in.Id, err = s.Model(ctx, &handler.Option{FilterAuth: false}).Data(in).InsertAndGetId()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
// 推送通知
memberIds := charset.SplitMemberIds(in.Receiver, ",")
response := &websocket.WResponse{
Event: "notice",
Data: in,
}
simple.SafeGo(ctx, func(ctx context.Context) {
if len(memberIds) == 0 {
websocket.SendToAll(response)
} else {
for _, memberId := range memberIds {
websocket.SendToUser(memberId, response)
if in.Type == consts.NoticeTypeLetter {
for _, receiverId := range in.Receiver {
websocket.SendToUser(receiverId, response)
}
} else {
websocket.SendToAll(response)
}
})
@@ -106,8 +136,7 @@ func (s *sAdminNotice) Status(ctx context.Context, in adminin.NoticeStatusInp) (
}
// 修改
in.UpdatedAt = gtime.Now()
_, err = dao.AdminNotice.Ctx(ctx).Where("id", in.Id).Data("status", in.Status).Update()
_, err = s.Model(ctx).Where("id", in.Id).Data("status", in.Status).Update()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
@@ -119,19 +148,17 @@ func (s *sAdminNotice) Status(ctx context.Context, in adminin.NoticeStatusInp) (
// MaxSort 最大排序
func (s *sAdminNotice) MaxSort(ctx context.Context, in adminin.NoticeMaxSortInp) (*adminin.NoticeMaxSortModel, error) {
var res adminin.NoticeMaxSortModel
if in.Id > 0 {
if err := dao.AdminNotice.Ctx(ctx).Where("id", in.Id).Order("sort desc").Scan(&res); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return nil, err
}
if err := s.Model(ctx).Order("sort desc").Scan(&res); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return nil, err
}
res.Sort = res.Sort + 10
res.Sort = form.DefaultMaxSort(ctx, res.Sort)
return &res, nil
}
// View 获取指定字典类型信息
func (s *sAdminNotice) View(ctx context.Context, in adminin.NoticeViewInp) (res *adminin.NoticeViewModel, err error) {
if err = dao.AdminNotice.Ctx(ctx).Where("id", in.Id).Scan(&res); err != nil {
if err = s.Model(ctx).Where("id", in.Id).Scan(&res); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return nil, err
}
@@ -141,19 +168,26 @@ func (s *sAdminNotice) View(ctx context.Context, in adminin.NoticeViewInp) (res
// List 获取列表
func (s *sAdminNotice) List(ctx context.Context, in adminin.NoticeListInp) (list []*adminin.NoticeListModel, totalCount int, err error) {
mod := dao.AdminNotice.Ctx(ctx)
var memberId = contexts.GetUserId(ctx)
if memberId <= 0 {
err = gerror.New("获取用户信息失败!")
return
}
mod := s.Model(ctx)
// 访问路径
if in.Title != "" {
mod = mod.WhereLike("title", "%"+in.Title+"%")
}
// 模块
if in.Content != "" {
mod = mod.WhereLike("content", "%"+in.Content+"%")
}
// 请求方式
if in.Type > 0 {
mod = mod.Where("type", in.Type)
}
if in.Status > 0 {
mod = mod.Where("status", in.Status)
}
@@ -173,8 +207,291 @@ func (s *sAdminNotice) List(ctx context.Context, in adminin.NoticeListInp) (list
return list, totalCount, err
}
for k, v := range list {
list[k].ReceiveNum = len(strings.Split(v.Reader, ","))
for _, v := range list {
// 接收人头像组
if v.Type == consts.NoticeTypeLetter {
err = dao.AdminMember.Ctx(ctx).
Fields("real_name as name,avatar as src").
WhereIn("id", v.Receiver.Var().Int64s()).
Scan(&v.ReceiverGroup)
if err != nil {
return
}
}
if v.ReceiverGroup == nil || len(v.ReceiverGroup) == 0 {
v.ReceiverGroup = make([]form.AvatarGroup, 0)
}
// 阅读次数
v.ReadCount, err = dao.AdminNoticeRead.Ctx(ctx).Where("notice_id", v.Id).Sum("clicks")
if err != nil {
return
}
}
return list, totalCount, err
}
// PullMessages 拉取未读消息列表
func (s *sAdminNotice) PullMessages(ctx context.Context, in adminin.PullMessagesInp) (res *adminin.PullMessagesModel, err error) {
var memberId = contexts.GetUserId(ctx)
if memberId <= 0 {
err = gerror.New("获取用户信息失败!")
return
}
messageIds, err := s.messageIds(ctx, memberId)
if err != nil {
return
}
res = new(adminin.PullMessagesModel)
unread, err := s.UnreadCount(ctx, adminin.NoticeUnreadCountInp{MemberId: memberId, MessageIds: messageIds})
if err != nil {
return
}
if unread != nil {
res.NoticeUnreadCountModel = unread
}
if err = s.Model(ctx).WhereIn("id", messageIds).Limit(in.Limit).Order("id desc").Scan(&res.List); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return
}
for _, v := range res.List {
count, _ := dao.AdminNoticeRead.Ctx(ctx).Where("notice_id", v.Id).Where("member_id", memberId).Count()
if count > 0 {
v.IsRead = true
}
if v.Type == consts.NoticeTypeLetter {
val, err := dao.AdminMember.Ctx(ctx).Fields("avatar").Where("id", v.CreatedBy).Value()
if err == nil {
v.SenderAvatar = val.String()
}
}
}
return
}
// UnreadCount 获取所有类型消息的未读数量
func (s *sAdminNotice) UnreadCount(ctx context.Context, in adminin.NoticeUnreadCountInp) (res *adminin.NoticeUnreadCountModel, err error) {
if in.MemberId <= 0 {
if in.MemberId = contexts.GetUserId(ctx); in.MemberId <= 0 {
err = gerror.New("获取用户信息失败!")
return
}
}
if len(in.MessageIds) == 0 {
in.MessageIds, err = s.messageIds(ctx, in.MemberId)
if err != nil {
return
}
if len(in.MessageIds) == 0 {
return
}
}
stat := func(t int) (count int) {
all, err := dao.AdminNotice.Ctx(ctx).As("nr").
Where("type =? and id IN(?)", t, in.MessageIds).
Count()
if err != nil {
g.Log().Infof(ctx, "UnreadCount stat err:%+v", err)
return
}
if all == 0 {
return
}
read, err := dao.AdminNoticeRead.Ctx(ctx).As("nr").
LeftJoin("admin_notice n", "nr.notice_id=n.id").
Where("n.type = ? and n.id IN(?)", t, in.MessageIds).
Where("nr.member_id", in.MemberId).
Count()
if err != nil {
g.Log().Infof(ctx, "UnreadCount stat2 err:%+v", err)
return
}
count = all - read
return
}
res = new(adminin.NoticeUnreadCountModel)
res.NotifyCount = stat(consts.NoticeTypeNotify)
res.NoticeCount = stat(consts.NoticeTypeNotice)
res.LetterCount = stat(consts.NoticeTypeLetter)
return
}
// messageIds 获取我的消息所有的消息ID
func (s *sAdminNotice) messageIds(ctx context.Context, memberId int64) (ids []int64, err error) {
mod := s.Model(ctx, &handler.Option{FilterAuth: false}).
Fields("id").
Where("status", consts.StatusEnabled).
Where("(`type` IN(?) OR (`type` = ? and JSON_CONTAINS(`receiver`,'"+gconv.String(memberId)+"')))",
[]int{consts.NoticeTypeNotify, consts.NoticeTypeNotice}, consts.NoticeTypeLetter,
)
array, err := mod.Array()
if err != nil {
return nil, err
}
for _, v := range array {
ids = append(ids, v.Int64())
}
return
}
// UpRead 更新已读
func (s *sAdminNotice) UpRead(ctx context.Context, in adminin.NoticeUpReadInp) (err error) {
var (
data *entity.AdminNotice
memberId = contexts.GetUserId(ctx)
)
if memberId <= 0 {
err = gerror.New("获取用户信息失败!")
return
}
if err = dao.AdminNotice.Ctx(ctx).Where("id", in.Id).Scan(&data); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
if data == nil {
return gerror.New("公告不存在")
}
return s.updatedReadClicks(ctx, in.Id, memberId)
}
// ReadAll 已读全部
func (s *sAdminNotice) ReadAll(ctx context.Context, in adminin.NoticeReadAllInp) (err error) {
var memberId = contexts.GetUserId(ctx)
if memberId <= 0 {
err = gerror.New("获取用户信息失败!")
return
}
allMessageIds, err := s.messageIds(ctx, memberId)
if err != nil {
return
}
if len(allMessageIds) == 0 {
return
}
array, err := dao.AdminNotice.Ctx(ctx).
Fields("id").
Where("type = ? and id IN(?)", in.Type, allMessageIds).
Array()
if err != nil {
return
}
var messageIds []int64
for _, v := range array {
messageIds = append(messageIds, v.Int64())
}
array, err = dao.AdminNoticeRead.Ctx(ctx).As("nr").
Fields("nr.notice_id").
LeftJoin("admin_notice n", "nr.notice_id=n.id").
Where("n.type = ? and n.id IN(?)", in.Type, messageIds).
Where("nr.member_id", memberId).
Array()
if err != nil {
return
}
var readIds []int64
for _, v := range array {
readIds = append(readIds, v.Int64())
}
for _, messageId := range messageIds {
if !validate.InSliceInt64(readIds, messageId) {
if err = s.updatedReadClicks(ctx, messageId, memberId); err != nil {
return
}
}
}
return
}
// updatedReadClicks 更新公告已读次数
func (s *sAdminNotice) updatedReadClicks(ctx context.Context, noticeId, memberId int64) (err error) {
var (
models *entity.AdminNoticeRead
)
err = dao.AdminNoticeRead.Ctx(ctx).
Where(dao.AdminNoticeRead.Columns().NoticeId, noticeId).
Where(dao.AdminNoticeRead.Columns().MemberId, memberId).
Scan(&models)
if err != nil {
return
}
if models == nil {
_, err = dao.AdminNoticeRead.Ctx(ctx).Data(entity.AdminNoticeRead{NoticeId: noticeId, MemberId: memberId}).Insert()
return
}
_, err = dao.AdminNoticeRead.Ctx(ctx).Where(dao.AdminNoticeRead.Columns().Id, models.Id).Increment("clicks", 1)
return
}
// MessageList 我的消息列表
func (s *sAdminNotice) MessageList(ctx context.Context, in adminin.NoticeMessageListInp) (list []*adminin.NoticeMessageListModel, totalCount int, err error) {
var memberId = contexts.GetUserId(ctx)
if memberId <= 0 {
err = gerror.New("获取用户信息失败!")
return
}
allMessageIds, err := s.messageIds(ctx, memberId)
if err != nil {
return
}
if len(allMessageIds) == 0 {
return
}
mod := s.Model(ctx, &handler.Option{FilterAuth: false}).WhereIn("id", allMessageIds).Where("type", in.Type)
totalCount, err = mod.Count()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return list, totalCount, err
}
if totalCount == 0 {
return list, totalCount, nil
}
if err = mod.Page(in.Page, in.PerPage).Order("id desc").Scan(&list); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return list, totalCount, err
}
for _, v := range list {
count, _ := dao.AdminNoticeRead.Ctx(ctx).Where("notice_id", v.Id).Where("member_id", memberId).Count()
if count > 0 {
v.IsRead = true
}
if v.Type == consts.NoticeTypeLetter {
val, err := dao.AdminMember.Ctx(ctx).Fields("avatar").Where("id", v.CreatedBy).Value()
if err == nil {
v.SenderAvatar = val.String()
}
}
}
return list, totalCount, err
}

View File

@@ -27,6 +27,7 @@ import (
"hotgo/utility/convert"
"hotgo/utility/tree"
"sort"
"strconv"
)
type sAdminRole struct{}
@@ -60,7 +61,7 @@ func (s *sAdminRole) Verify(ctx context.Context, path, method string) bool {
}
ok, err := casbin.Enforcer.Enforce(user.RoleKey, path, method)
if err != nil {
g.Log().Warningf(ctx, "admin Verify Enforce err:%v", err)
g.Log().Warningf(ctx, "admin Verify Enforce err:%+v", err)
return false
}
@@ -86,6 +87,12 @@ func (s *sAdminRole) List(ctx context.Context, in adminin.RoleListInp) (list []g
return list, totalCount, err
}
for _, v := range models {
v.Label = v.Name
v.Value = v.Id
v.Key = strconv.FormatInt(v.Id, 10)
}
return tree.GenTree(gconv.SliceMap(models)), totalCount, err
}
@@ -104,7 +111,7 @@ func (s *sAdminRole) GetName(ctx context.Context, RoleId int64) (name string, er
return roleName.String(), nil
}
// GetMemberList 获取指定会员的岗位列表
// GetMemberList 获取指定用户的岗位列表
func (s *sAdminRole) GetMemberList(ctx context.Context, RoleId int64) (list []*adminin.RoleListModel, err error) {
err = dao.AdminRole.Ctx(ctx).
Where("id", RoleId).

View File

@@ -18,6 +18,7 @@ import (
"hotgo/internal/dao"
"hotgo/internal/library/contexts"
"hotgo/internal/library/hgorm"
"hotgo/internal/library/hgorm/handler"
"hotgo/internal/model/input/adminin"
"hotgo/internal/model/input/form"
"hotgo/internal/service"
@@ -37,13 +38,13 @@ func init() {
}
// Model Orm模型
func (s *sAdminTest) Model(ctx context.Context) *gdb.Model {
return dao.Test.Ctx(ctx)
func (s *sAdminTest) Model(ctx context.Context, option ...*handler.Option) *gdb.Model {
return handler.Model(dao.Test.Ctx(ctx), option...)
}
// List 获取列表
func (s *sAdminTest) List(ctx context.Context, in adminin.TestListInp) (list []*adminin.TestListModel, totalCount int, err error) {
mod := dao.Test.Ctx(ctx)
mod := s.Model(ctx)
if in.Title != "" {
mod = mod.WhereLike(dao.Test.Columns().Title, "%"+in.Title+"%")
@@ -98,11 +99,11 @@ func (s *sAdminTest) List(ctx context.Context, in adminin.TestListInp) (list []*
totalCount, err = mod.Clone().Count(1)
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return list, totalCount, err
return
}
if totalCount == 0 {
return list, totalCount, nil
return
}
////关联表select
@@ -113,28 +114,27 @@ func (s *sAdminTest) List(ctx context.Context, in adminin.TestListInp) (list []*
fields, err := hgorm.GenSelect(ctx, adminin.TestListModel{}, dao.Test)
if err != nil {
return nil, 0, err
return
}
if err = mod.Fields(fields).Handler(hgorm.HandlerFilterAuth, hgorm.HandlerForceCache).Page(in.Page, in.PerPage).OrderAsc(dao.Test.Columns().Sort).OrderDesc(dao.Test.Columns().Id).Scan(&list); err != nil {
if err = mod.Fields(fields).Handler(handler.FilterAuth, handler.ForceCache).Page(in.Page, in.PerPage).OrderAsc(dao.Test.Columns().Sort).OrderDesc(dao.Test.Columns().Id).Scan(&list); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return list, totalCount, err
return
}
return list, totalCount, err
return
}
// Export 导出
func (s *sAdminTest) Export(ctx context.Context, in adminin.TestListInp) (err error) {
list, totalCount, err := s.List(ctx, in)
if err != nil {
return err
return
}
// 字段的排序是依据tags的字段顺序如果你不想使用默认的排序方式可以直接定义 tags = []string{"字段名称", "字段名称2", ...}
tags, err := convert.GetEntityDescTags(adminin.TestExportModel{})
if err != nil {
return err
return
}
var (
@@ -143,10 +143,10 @@ func (s *sAdminTest) Export(ctx context.Context, in adminin.TestListInp) (err er
exports []adminin.TestExportModel
)
err = gconv.Scan(list, &exports)
if err != nil {
return err
if err = gconv.Scan(list, &exports); err != nil {
return
}
if err = excel.ExportByStructs(ctx, tags, exports, fileName, sheetName); err != nil {
return
}
@@ -156,70 +156,51 @@ func (s *sAdminTest) Export(ctx context.Context, in adminin.TestListInp) (err er
// Edit 修改/新增
func (s *sAdminTest) Edit(ctx context.Context, in adminin.TestEditInp) (err error) {
if err = hgorm.IsUnique(ctx, dao.Test, g.Map{dao.Test.Columns().Qq: in.Qq}, "QQ号码已存在请换一个", in.Id); err != nil {
if err != nil {
return err
}
return
}
// 修改
if in.Id > 0 {
in.UpdatedBy = contexts.GetUserId(ctx)
_, err = dao.Test.Ctx(ctx).Where(dao.Test.Columns().Id, in.Id).Data(in).Update()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
return nil
_, err = s.Model(ctx).Where(dao.Test.Columns().Id, in.Id).Data(in).Update()
return
}
// 新增
in.CreatedBy = contexts.GetUserId(ctx)
_, err = dao.Test.Ctx(ctx).Data(in).Insert()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
return nil
_, err = s.Model(ctx, &handler.Option{FilterAuth: false}).Data(in).Insert()
return
}
// Delete 删除
func (s *sAdminTest) Delete(ctx context.Context, in adminin.TestDeleteInp) (err error) {
_, err = dao.Test.Ctx(ctx).Where(dao.Test.Columns().Id, in.Id).Delete()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
return nil
_, err = s.Model(ctx).Where(dao.Test.Columns().Id, in.Id).Delete()
return
}
// Status 更新状态
func (s *sAdminTest) Status(ctx context.Context, in adminin.TestStatusInp) (err error) {
if in.Id <= 0 {
err = gerror.New("ID不能为空")
return err
return
}
if in.Status <= 0 {
err = gerror.New("状态不能为空")
return err
return
}
if !validate.InSliceInt(consts.StatusMap, in.Status) {
err = gerror.New("状态不正确")
return err
return
}
// 修改
_, err = dao.Test.Ctx(ctx).Where(dao.Test.Columns().Id, in.Id).Data(dao.Test.Columns().Status, in.Status).Update()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
return nil
_, err = s.Model(ctx).Where(dao.Test.Columns().Id, in.Id).Data(g.Map{
dao.Test.Columns().Status: in.Status,
dao.Test.Columns().UpdatedBy: contexts.GetUserId(ctx),
}).Update()
return
}
// Switch 更新开关状态
@@ -231,36 +212,34 @@ func (s *sAdminTest) Switch(ctx context.Context, in adminin.TestSwitchInp) (err
if !validate.InSliceString(fields, in.Key) {
err = gerror.New("开关键名不在白名单")
return err
return
}
// 修改
_, err = dao.Test.Ctx(ctx).Where(dao.Test.Columns().Id, in.Id).Data(in.Key, in.Value).Update()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
return nil
_, err = s.Model(ctx).Where(dao.Test.Columns().Id, in.Id).Data(g.Map{
in.Key: in.Value,
dao.Test.Columns().UpdatedBy: contexts.GetUserId(ctx),
}).Update()
return
}
// MaxSort 最大排序
func (s *sAdminTest) MaxSort(ctx context.Context, in adminin.TestMaxSortInp) (res *adminin.TestMaxSortModel, err error) {
if err = dao.Test.Ctx(ctx).Fields(dao.Test.Columns().Sort).OrderDesc(dao.Test.Columns().Sort).Scan(&res); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return nil, err
return
}
res.Sort = res.Sort + g.Cfg().MustGet(ctx, "hotgo.admin.maxSortIncrement").Int()
return res, nil
if res == nil {
res = new(adminin.TestMaxSortModel)
}
res.Sort = form.DefaultMaxSort(ctx, res.Sort)
return
}
// View 获取指定字典类型信息
func (s *sAdminTest) View(ctx context.Context, in adminin.TestViewInp) (res *adminin.TestViewModel, err error) {
if err = dao.Test.Ctx(ctx).Where(dao.Test.Columns().Id, in.Id).Scan(&res); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return nil, err
}
return res, nil
err = s.Model(ctx).Where(dao.Test.Columns().Id, in.Id).Scan(&res)
return
}

View File

@@ -205,8 +205,6 @@ func (s *sCommonUpload) UploadUCloud(ctx context.Context, conf *model.UploadConf
return nil, err
}
g.Log().Warningf(ctx, "ras:%+v", string(req.LastResponseBody))
attachment, err := service.SysAttachment().Add(ctx, meta, fullPath, consts.UploadDriveUCloud)
if err != nil {
return nil, err

View File

@@ -14,8 +14,8 @@ import (
"hotgo/internal/service"
)
// GlobalLog 访问日志
func (s *sHook) GlobalLog(r *ghttp.Request) {
// AccessLog 访问日志
func (s *sHook) AccessLog(r *ghttp.Request) {
var (
ctx = r.Context()
)
@@ -31,7 +31,7 @@ func (s *sHook) GlobalLog(r *ghttp.Request) {
go func() {
if err := service.SysLog().AutoLog(ctx); err != nil {
g.Log().Info(ctx, "GlobalLog AutoLog err:", err)
g.Log().Info(ctx, "hook AccessLog err:", err)
}
}()
}

View File

@@ -0,0 +1,80 @@
package hook
import (
"context"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/os/gctx"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/os/gtimer"
"hotgo/internal/library/contexts"
"sync"
"time"
)
type visitor struct {
lastSeen *gtime.Time
}
var (
visitors = make(map[int64]*visitor)
mtx sync.Mutex
)
// Run a background goroutine to remove old entries from the visitors map.
func init() {
go cleanupVisitors()
}
// Every minute check the map for visitors that haven't been seen for
// more than 3 minutes and delete the entries.
func cleanupVisitors() {
gtimer.AddSingleton(gctx.New(), time.Minute, func(ctx context.Context) {
mtx.Lock()
for memberId, v := range visitors {
if gtime.Now().Sub(v.lastSeen) > 3*time.Minute {
delete(visitors, memberId)
}
}
mtx.Unlock()
})
}
func allow(memberId int64) bool {
mtx.Lock()
defer mtx.Unlock()
v, exists := visitors[memberId]
if !exists {
visitors[memberId] = &visitor{gtime.Now()}
return true
}
if gtime.Now().Sub(v.lastSeen) > time.Second*3 {
v.lastSeen = gtime.Now()
return true
}
return false
}
// LastActive 更新用户最后活跃
func (s *sHook) LastActive(r *ghttp.Request) {
var (
ctx = r.Context()
memberId = contexts.GetUserId(ctx)
)
if memberId == 0 {
return
}
if allow(memberId) {
_, err := g.Model("admin_member").Ctx(ctx).
Where("id", memberId).
Data(g.Map{"last_active_at": gtime.Now()}).
Update()
if err != nil {
g.Log().Warningf(ctx, "hook LastActive err:%+v, memberId:%v", err, memberId)
}
}
}

View File

@@ -42,7 +42,7 @@ func (s *sMiddleware) AdminAuth(r *ghttp.Request) {
// 验证路由访问权限
if !service.AdminRole().Verify(ctx, path, r.Method) {
g.Log().Warningf(ctx, "AdminAuth fail path:%+v, GetRoleKey:%+v, r.Method:%+v", path, contexts.GetRoleKey(ctx), r.Method)
g.Log().Debugf(ctx, "AdminAuth fail path:%+v, GetRoleKey:%+v, r.Method:%+v", path, contexts.GetRoleKey(ctx), r.Method)
response.JsonExit(r, gcode.CodeSecurityReason.Code(), "你没有访问权限!")
return
}

View File

@@ -151,22 +151,19 @@ func inspectAuth(r *ghttp.Request, appName string) error {
// 保存到上下文
if user != nil {
customCtx.User = &model.Identity{
Id: user.Id,
Pid: user.Pid,
DeptId: user.DeptId,
RoleId: user.RoleId,
RoleKey: user.RoleKey,
Username: user.Username,
RealName: user.RealName,
Avatar: user.Avatar,
Email: user.Email,
Mobile: user.Mobile,
VisitCount: user.VisitCount,
LastTime: user.LastTime,
LastIp: user.LastIp,
Exp: user.Exp,
Expires: user.Expires,
App: user.App,
Id: user.Id,
Pid: user.Pid,
DeptId: user.DeptId,
RoleId: user.RoleId,
RoleKey: user.RoleKey,
Username: user.Username,
RealName: user.RealName,
Avatar: user.Avatar,
Email: user.Email,
Mobile: user.Mobile,
Exp: user.Exp,
Expires: user.Expires,
App: user.App,
}
}
contexts.SetUser(ctx, customCtx.User)

View File

@@ -0,0 +1,36 @@
package middleware
import (
"fmt"
"github.com/gogf/gf/v2/errors/gcode"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/text/gstr"
"hotgo/internal/library/location"
"hotgo/internal/library/response"
)
// Develop 开发工具白名单过滤
func (s *sMiddleware) Develop(r *ghttp.Request) {
ips := g.Cfg().MustGet(r.Context(), "hggen.allowedIPs").Strings()
if len(ips) == 0 {
response.JsonExit(r, gcode.CodeNotSupported.Code(), "请配置生成白名单!")
}
if !gstr.InArray(ips, "*") {
cuIp := location.GetClientIp(r)
ok := false
for _, ip := range ips {
if ip == cuIp {
ok = true
break
}
}
if !ok {
response.JsonExit(r, gcode.CodeNotSupported.Code(), fmt.Sprintf("当前IP[%s]没有配置生成白名单!", cuIp))
}
}
r.Middleware.Next()
}

View File

@@ -96,6 +96,19 @@ func (s *sSysConfig) GetSmtp(ctx context.Context) (conf *model.EmailConfig, err
return conf, nil
}
// GetBasic 获取基础配置
func (s *sSysConfig) GetBasic(ctx context.Context) (conf *model.BasicConfig, err error) {
models, err := s.GetConfigByGroup(ctx, sysin.GetConfigInp{Group: "basic"})
if err != nil {
return nil, err
}
if err = gconv.Struct(models.List, &conf); err != nil {
return nil, err
}
return conf, nil
}
// GetLoadSSL 获取本地日志配置
func (s *sSysConfig) GetLoadSSL(ctx context.Context) (conf *model.SSLConfig, err error) {
if err = g.Cfg().MustGet(ctx, "hotgo.ssl").Struct(&conf); err != nil {

View File

@@ -8,14 +8,15 @@ package sys
import (
"context"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gctx"
"github.com/gogf/gf/v2/os/gtime"
"hotgo/internal/consts"
"hotgo/internal/crons"
"hotgo/internal/dao"
"hotgo/internal/model/entity"
"hotgo/internal/model/input/form"
"hotgo/internal/model/input/sysin"
"hotgo/internal/service"
"hotgo/utility/validate"
@@ -33,10 +34,7 @@ func init() {
}
func (s *sSysCron) StartCron(ctx context.Context) {
var (
list []*entity.SysCron
)
var list []*entity.SysCron
if err := dao.SysCron.Ctx(ctx).
Where("status", consts.StatusEnabled).
Order("sort asc,id desc").
@@ -49,17 +47,30 @@ func (s *sSysCron) StartCron(ctx context.Context) {
g.Log().Fatalf(ctx, "定时任务启动失败, err . %v", err)
return
}
}
// Delete 删除
func (s *sSysCron) Delete(ctx context.Context, in sysin.CronDeleteInp) error {
_, err := dao.SysCron.Ctx(ctx).Where("id", in.Id).Delete()
if err != nil {
func (s *sSysCron) Delete(ctx context.Context, in sysin.CronDeleteInp) (err error) {
var models *entity.SysCron
if err = dao.SysCron.Ctx(ctx).Where("id", in.Id).Scan(&models); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
return
}
if models == nil {
err = gerror.New("定时任务不存在或已被删除")
return
}
err = g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) (err error) {
_, err = dao.SysCron.Ctx(ctx).Where("id", in.Id).Delete()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
return crons.Delete(models)
})
return nil
}
@@ -67,34 +78,30 @@ func (s *sSysCron) Delete(ctx context.Context, in sysin.CronDeleteInp) error {
func (s *sSysCron) Edit(ctx context.Context, in sysin.CronEditInp) (err error) {
if in.Name == "" {
err = gerror.New("标题不能为空")
return err
return
}
// 修改
in.UpdatedAt = gtime.Now()
if in.Id > 0 {
_, err = dao.SysCron.Ctx(ctx).Where("id", in.Id).Data(in).Update()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
err = g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) (err error) {
_, err = dao.SysCron.Ctx(ctx).Where("id", in.Id).Data(in).Update()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
return nil
return crons.RefreshStatus(&in.SysCron)
})
return
}
// 新增
in.CreatedAt = gtime.Now()
_, err = dao.SysCron.Ctx(ctx).Data(in).Insert()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
return nil
return
}
// Status 更新部门状态
func (s *sSysCron) Status(ctx context.Context, in sysin.CronStatusInp) (err error) {
if in.Id <= 0 {
err = gerror.New("ID不能为空")
return err
@@ -110,36 +117,46 @@ func (s *sSysCron) Status(ctx context.Context, in sysin.CronStatusInp) (err erro
return err
}
// 修改
in.UpdatedAt = gtime.Now()
_, err = dao.SysCron.Ctx(ctx).Where("id", in.Id).Data("status", in.Status).Update()
if err != nil {
var models *entity.SysCron
if err = dao.SysCron.Ctx(ctx).Where("id", in.Id).Scan(&models); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
return
}
return nil
if models == nil {
err = gerror.New("定时任务不存在")
return
}
err = g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) (err error) {
_, err = dao.SysCron.Ctx(ctx).Where("id", in.Id).Data("status", in.Status).Update()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
models.Status = in.Status
return crons.RefreshStatus(models)
})
return
}
// MaxSort 最大排序
func (s *sSysCron) MaxSort(ctx context.Context, in sysin.CronMaxSortInp) (*sysin.CronMaxSortModel, error) {
var res sysin.CronMaxSortModel
if in.Id > 0 {
if err := dao.SysCron.Ctx(ctx).Where("id", in.Id).Order("sort desc").Scan(&res); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return nil, err
}
func (s *sSysCron) MaxSort(ctx context.Context, in sysin.CronMaxSortInp) (res *sysin.CronMaxSortModel, err error) {
if err = dao.SysCron.Ctx(ctx).Where("id", in.Id).Order("sort desc").Scan(&res); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return nil, err
}
if res == nil {
res = new(sysin.CronMaxSortModel)
}
res.Sort = res.Sort + 10
return &res, nil
res.Sort = form.DefaultMaxSort(ctx, res.Sort)
return res, nil
}
// View 获取指定字典类型信息
func (s *sSysCron) View(ctx context.Context, in sysin.CronViewInp) (res *sysin.CronViewModel, err error) {
if err = dao.SysCron.Ctx(ctx).Where("id", in.Id).Scan(&res); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return nil, err
@@ -152,12 +169,10 @@ func (s *sSysCron) View(ctx context.Context, in sysin.CronViewInp) (res *sysin.C
func (s *sSysCron) List(ctx context.Context, in sysin.CronListInp) (list []*sysin.CronListModel, totalCount int, err error) {
mod := dao.SysCron.Ctx(ctx)
// 访问路径
if in.Name != "" {
mod = mod.WhereLike("name", "%"+in.Name+"%")
}
// 请求方式
if in.Status > 0 {
mod = mod.Where("status", in.Status)
}
@@ -180,7 +195,6 @@ func (s *sSysCron) List(ctx context.Context, in sysin.CronListInp) (list []*sysi
for _, v := range list {
v.GroupName, _ = dao.SysCronGroup.GetName(ctx, v.GroupId)
}
return list, totalCount, err
}
@@ -197,6 +211,5 @@ func (s *sSysCron) OnlineExec(ctx context.Context, in sysin.OnlineExecInp) (err
}
newCtx := context.WithValue(gctx.New(), consts.ContextKeyCronArgs, strings.Split(data.Params, consts.CronSplitStr))
return crons.Once(newCtx, data)
}

View File

@@ -3,8 +3,8 @@
// @Copyright Copyright (c) 2023 HotGo CLI
// @Author Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
// @AutoGenerate Version 2.1.0
// @AutoGenerate Date 2023-01-18 15:19:42
// @AutoGenerate Version 2.1.2
// @AutoGenerate Date 2023-02-08 17:47:32
//
package sys
@@ -15,6 +15,7 @@ import (
"hotgo/internal/dao"
"hotgo/internal/library/contexts"
"hotgo/internal/library/hgorm"
"hotgo/internal/library/hgorm/handler"
"hotgo/internal/model/input/form"
"hotgo/internal/model/input/sysin"
"hotgo/internal/service"
@@ -39,14 +40,14 @@ func init() {
service.RegisterSysCurdDemo(NewSysCurdDemo())
}
// Model 生成演示Orm模型
func (s *sSysCurdDemo) Model(ctx context.Context) *gdb.Model {
return dao.SysGenCurdDemo.Ctx(ctx)
// Model 生成演示ORM模型
func (s *sSysCurdDemo) Model(ctx context.Context, option ...*handler.Option) *gdb.Model {
return handler.Model(dao.SysGenCurdDemo.Ctx(ctx), option...)
}
// List 获取生成演示列表
func (s *sSysCurdDemo) List(ctx context.Context, in sysin.CurdDemoListInp) (list []*sysin.CurdDemoListModel, totalCount int, err error) {
mod := dao.SysGenCurdDemo.Ctx(ctx)
mod := s.Model(ctx)
// 查询ID
if in.Id > 0 {
@@ -77,36 +78,37 @@ func (s *sSysCurdDemo) List(ctx context.Context, in sysin.CurdDemoListInp) (list
totalCount, err = mod.Clone().Count(1)
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return list, totalCount, err
return
}
if totalCount == 0 {
return list, totalCount, nil
return
}
//关联表select
fields, err := hgorm.GenJoinSelect(ctx, sysin.CurdDemoListModel{}, dao.SysGenCurdDemo, []*hgorm.Join{
{Dao: dao.TestCategory, Alias: "testCategory"},
})
if err = mod.Fields(fields).Handler(hgorm.HandlerFilterAuth).Page(in.Page, in.PerPage).OrderAsc(dao.SysGenCurdDemo.Columns().Sort).OrderDesc(dao.SysGenCurdDemo.Columns().Id).Scan(&list); err != nil {
if err = mod.Fields(fields).Page(in.Page, in.PerPage).OrderAsc(dao.SysGenCurdDemo.Columns().Sort).OrderDesc(dao.SysGenCurdDemo.Columns().Id).Scan(&list); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return list, totalCount, err
return
}
return list, totalCount, err
return
}
// Export 导出生成演示
func (s *sSysCurdDemo) Export(ctx context.Context, in sysin.CurdDemoListInp) (err error) {
list, totalCount, err := s.List(ctx, in)
if err != nil {
return err
return
}
// 字段的排序是依据tags的字段顺序如果你不想使用默认的排序方式可以直接定义 tags = []string{"字段名称", "字段名称2", ...}
tags, err := convert.GetEntityDescTags(sysin.CurdDemoExportModel{})
if err != nil {
return err
return
}
var (
@@ -115,13 +117,11 @@ func (s *sSysCurdDemo) Export(ctx context.Context, in sysin.CurdDemoListInp) (er
exports []sysin.CurdDemoExportModel
)
err = gconv.Scan(list, &exports)
if err != nil {
return err
}
if err = excel.ExportByStructs(ctx, tags, exports, fileName, sheetName); err != nil {
if err = gconv.Scan(list, &exports); err != nil {
return
}
err = excel.ExportByStructs(ctx, tags, exports, fileName, sheetName)
return
}
@@ -130,7 +130,7 @@ func (s *sSysCurdDemo) Edit(ctx context.Context, in sysin.CurdDemoEditInp) (err
// 修改
if in.Id > 0 {
in.UpdatedBy = contexts.GetUserId(ctx)
_, err = dao.SysGenCurdDemo.Ctx(ctx).
_, err = s.Model(ctx).
FieldsEx(
dao.SysGenCurdDemo.Columns().Id,
dao.SysGenCurdDemo.Columns().CreatedBy,
@@ -138,85 +138,70 @@ func (s *sSysCurdDemo) Edit(ctx context.Context, in sysin.CurdDemoEditInp) (err
dao.SysGenCurdDemo.Columns().DeletedAt,
).
Where(dao.SysGenCurdDemo.Columns().Id, in.Id).Data(in).Update()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
return nil
return
}
// 新增
in.CreatedBy = contexts.GetUserId(ctx)
_, err = dao.SysGenCurdDemo.Ctx(ctx).
_, err = s.Model(ctx, &handler.Option{FilterAuth: false}).
FieldsEx(
dao.SysGenCurdDemo.Columns().Id,
dao.SysGenCurdDemo.Columns().UpdatedBy,
dao.SysGenCurdDemo.Columns().DeletedAt,
).
Data(in).Insert()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
return
}
// Delete 删除生成演示
func (s *sSysCurdDemo) Delete(ctx context.Context, in sysin.CurdDemoDeleteInp) (err error) {
_, err = dao.SysGenCurdDemo.Ctx(ctx).Where(dao.SysGenCurdDemo.Columns().Id, in.Id).Delete()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
return nil
_, err = s.Model(ctx).Where(dao.SysGenCurdDemo.Columns().Id, in.Id).Delete()
return
}
// MaxSort 获取生成演示最大排序
func (s *sSysCurdDemo) MaxSort(ctx context.Context, in sysin.CurdDemoMaxSortInp) (res *sysin.CurdDemoMaxSortModel, err error) {
if err = dao.SysGenCurdDemo.Ctx(ctx).Fields(dao.SysGenCurdDemo.Columns().Sort).OrderDesc(dao.SysGenCurdDemo.Columns().Sort).Scan(&res); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return nil, err
return
}
res.Sort = res.Sort + g.Cfg().MustGet(ctx, "hotgo.admin.maxSortIncrement").Int()
return res, nil
if res == nil {
res = new(sysin.CurdDemoMaxSortModel)
}
res.Sort = form.DefaultMaxSort(ctx, res.Sort)
return
}
// View 获取生成演示指定信息
func (s *sSysCurdDemo) View(ctx context.Context, in sysin.CurdDemoViewInp) (res *sysin.CurdDemoViewModel, err error) {
if err = dao.SysGenCurdDemo.Ctx(ctx).Where(dao.SysGenCurdDemo.Columns().Id, in.Id).Scan(&res); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return nil, err
}
return res, nil
err = s.Model(ctx).Where(dao.SysGenCurdDemo.Columns().Id, in.Id).Scan(&res)
return
}
// Status 更新生成演示状态
func (s *sSysCurdDemo) Status(ctx context.Context, in sysin.CurdDemoStatusInp) (err error) {
if in.Id <= 0 {
err = gerror.New("ID不能为空")
return err
return
}
if in.Status <= 0 {
err = gerror.New("状态不能为空")
return err
return
}
if !validate.InSliceInt(consts.StatusMap, in.Status) {
err = gerror.New("状态不正确")
return err
return
}
_, err = dao.SysGenCurdDemo.Ctx(ctx).Where(dao.SysGenCurdDemo.Columns().Id, in.Id).Data(dao.SysGenCurdDemo.Columns().Status, in.Status).Update()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
return nil
_, err = s.Model(ctx).Where(dao.SysGenCurdDemo.Columns().Id, in.Id).Data(g.Map{
dao.SysGenCurdDemo.Columns().Status: in.Status,
dao.SysGenCurdDemo.Columns().UpdatedBy: contexts.GetUserId(ctx),
}).Update()
return
}
// Switch 更新生成演示开关
@@ -229,14 +214,12 @@ func (s *sSysCurdDemo) Switch(ctx context.Context, in sysin.CurdDemoSwitchInp) (
if !validate.InSliceString(fields, in.Key) {
err = gerror.New("开关键名不在白名单")
return err
return
}
_, err = dao.SysGenCurdDemo.Ctx(ctx).Where(dao.SysGenCurdDemo.Columns().Id, in.Id).Data(in.Key, in.Value).Update()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
return nil
_, err = s.Model(ctx).Where(dao.SysGenCurdDemo.Columns().Id, in.Id).Data(g.Map{
in.Key: in.Value,
dao.SysGenCurdDemo.Columns().UpdatedBy: contexts.GetUserId(ctx),
}).Update()
return
}

View File

@@ -0,0 +1,443 @@
// Package sys
// @Link https://github.com/bufanyun/hotgo
// @Copyright Copyright (c) 2022 HotGo CLI
// @Author Ms <133814250@qq.com>
// @License https://github.com/bufanyun/hotgo/blob/master/LICENSE
//
package sys
import (
"context"
"fmt"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/os/gview"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/grand"
"hotgo/internal/consts"
"hotgo/internal/dao"
"hotgo/internal/library/contexts"
"hotgo/internal/library/ems"
"hotgo/internal/library/location"
"hotgo/internal/model"
"hotgo/internal/model/entity"
"hotgo/internal/model/input/sysin"
"hotgo/internal/service"
"hotgo/utility/charset"
"hotgo/utility/useragent"
"hotgo/utility/validate"
"time"
)
type sSysEmsLog struct{}
func NewSysEmsLog() *sSysEmsLog {
return &sSysEmsLog{}
}
func init() {
service.RegisterSysEmsLog(NewSysEmsLog())
}
// Delete 删除
func (s *sSysEmsLog) Delete(ctx context.Context, in sysin.EmsLogDeleteInp) error {
_, err := dao.SysEmsLog.Ctx(ctx).Where("id", in.Id).Delete()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
return nil
}
// Edit 修改/新增
func (s *sSysEmsLog) Edit(ctx context.Context, in sysin.EmsLogEditInp) (err error) {
if in.Ip == "" {
err = gerror.New("ip不能为空")
return err
}
// 修改
if in.Id > 0 {
_, err = dao.SysEmsLog.Ctx(ctx).Where("id", in.Id).Data(in).Update()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
return nil
}
// 新增
_, err = dao.SysEmsLog.Ctx(ctx).Data(in).Insert()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
return nil
}
// Status 更新部门状态
func (s *sSysEmsLog) Status(ctx context.Context, in sysin.EmsLogStatusInp) (err error) {
if in.Id <= 0 {
err = gerror.New("ID不能为空")
return err
}
if in.Status <= 0 {
err = gerror.New("状态不能为空")
return err
}
if !validate.InSliceInt(consts.StatusMap, in.Status) {
err = gerror.New("状态不正确")
return err
}
// 修改
_, err = dao.SysEmsLog.Ctx(ctx).Where("id", in.Id).Data("status", in.Status).Update()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
return nil
}
// View 获取指定字典类型信息
func (s *sSysEmsLog) View(ctx context.Context, in sysin.EmsLogViewInp) (res *sysin.EmsLogViewModel, err error) {
if err = dao.SysEmsLog.Ctx(ctx).Where("id", in.Id).Scan(&res); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return nil, err
}
return res, nil
}
// List 获取列表
func (s *sSysEmsLog) List(ctx context.Context, in sysin.EmsLogListInp) (list []*sysin.EmsLogListModel, totalCount int, err error) {
mod := dao.SysEmsLog.Ctx(ctx)
if in.Status > 0 {
mod = mod.Where("status", in.Status)
}
totalCount, err = mod.Count()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return list, totalCount, err
}
if totalCount == 0 {
return list, totalCount, nil
}
if err = mod.Page(in.Page, in.PerPage).Order("id desc").Scan(&list); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return list, totalCount, err
}
return list, totalCount, err
}
// Send 发送邮件
func (s *sSysEmsLog) Send(ctx context.Context, in sysin.SendEmsInp) (err error) {
var models *entity.SysEmsLog
if err = dao.SysEmsLog.Ctx(ctx).Where("event", in.Event).Where("email", in.Email).Scan(&models); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
config, err := service.SysConfig().GetSmtp(ctx)
if err != nil {
return err
}
in.Template, err = s.GetTemplate(ctx, in.Event, config)
if err != nil {
return err
}
err = s.AllowSend(ctx, models, config)
if err != nil {
return err
}
if consts.IsCodeEmsTemplate(in.Event) && in.Code == "" {
in.Code = grand.Digits(4)
}
view, err := s.newView(ctx, in, config)
if err != nil {
return err
}
if in.TplData == nil {
in.TplData = make(g.Map)
}
switch in.Event {
// 富文本
case consts.EmsTemplateText:
if in.Content == "" {
err = gerror.New("富文本类型邮件内容不能为空")
return
}
in.TplData["content"] = in.Content
in.Content, err = view.Parse(ctx, in.Template, in.TplData)
if err != nil {
return err
}
// 验证码、重置密码类
default:
in.Content, err = view.Parse(ctx, in.Template, in.TplData)
if err != nil {
return err
}
}
subject, ok := consts.EmsSubjectMap[in.Event]
if !ok {
subject = "HotGo"
}
err = ems.Send(config, in.Email, subject, in.Content)
if err != nil {
return err
}
var data = new(entity.SysEmsLog)
data.Event = in.Event
data.Email = in.Email
data.Content = in.Content
data.Code = in.Code
data.Ip = location.GetClientIp(ghttp.RequestFromCtx(ctx))
data.Status = consts.EmsStatusNotUsed
data.CreatedAt = gtime.Now()
data.UpdatedAt = gtime.Now()
_, err = dao.SysEmsLog.Ctx(ctx).Data(data).Insert()
if err != nil {
return err
}
return nil
}
func (s *sSysEmsLog) newView(ctx context.Context, in sysin.SendEmsInp, config *model.EmailConfig) (view *gview.View, err error) {
view = gview.New()
err = view.SetConfig(gview.Config{
Delimiters: g.Cfg().MustGet(ctx, "viewer.delimiters").Strings(),
})
if err != nil {
return
}
// 富文本为自定义内容,可能不需要变量
if in.Event == consts.EmsTemplateText {
return
}
var (
username string
user = contexts.GetUser(ctx)
request = ghttp.RequestFromCtx(ctx)
ip = location.GetClientIp(request)
)
loc, err := location.GetLocation(ctx, ip)
if err != nil {
return
}
if loc == nil {
loc = new(location.IpLocationData)
}
cityLabel, err := location.ParseRegion(ctx, loc.ProvinceCode, loc.CityCode, 0)
if err != nil {
return
}
basic, err := service.SysConfig().GetBasic(ctx)
if err != nil {
return
}
if basic == nil {
basic = new(model.BasicConfig)
basic.Name = "HotGo"
basic.Domain = "https://hotgo.facms.cn"
basic.Logo = "http://bufanyun.cn-bj.ufileos.com/haoka/attachment/images/2023-02-04/cq9kf7s66jt7hkpvbh.png"
basic.SystemOpen = true
}
if user != nil {
username = user.Username
}
// 公共变量
view.Assigns(gview.Params{
"code": in.Code, // 验证码
"expires": config.CodeExpire / 60, // 验证码有效期(分钟)
"username": username, // 发送者用户名
"name": basic.Name, // 网站名称
"logo": basic.Logo, // 网站logo
"domain": basic.Domain, // 网站域名
"github": "https://github.com/bufanyun/hotgo", // github
"os": useragent.GetOs(request.Header.Get("User-Agent")), // 发送者操作系统
"ip": gstr.HideStr(ip, 30, `*`), // 发送者IP
"cityLabel": cityLabel, // IP归属地
})
// 重置密码
if in.Event == consts.EmsTemplateResetPwd {
var (
passwordResetLink string
resetToken = charset.RandomCreateBytes(32)
)
if user != nil {
switch user.App {
// 后台用户
case consts.AppAdmin:
_, err = g.Model("admin_member").Ctx(ctx).Where("id", user.Id).Data(g.Map{"password_reset_token": resetToken}).Update()
if err != nil {
return
}
passwordResetLink = fmt.Sprintf("%s/admin/passwordReset?token=%s", basic.Domain, resetToken)
// 前台用户
case consts.AppApi:
// ...
}
}
view.Assign("passwordResetLink", passwordResetLink)
}
return
}
// GetTemplate 获取指定邮件模板
func (s *sSysEmsLog) GetTemplate(ctx context.Context, template string, config *model.EmailConfig) (val string, err error) {
if template == "" {
return "", gerror.New("模板不能为空")
}
if config == nil {
config, err = service.SysConfig().GetSmtp(ctx)
if err != nil {
return "", err
}
}
if len(config.Template) == 0 {
return "", gerror.New("管理员还没有配置任何模板!")
}
for _, v := range config.Template {
if v.Key == template {
return v.Value, nil
}
}
return
}
// AllowSend 是否允许发送
func (s *sSysEmsLog) AllowSend(ctx context.Context, models *entity.SysEmsLog, config *model.EmailConfig) (err error) {
if models == nil {
return nil
}
// 富文本事件不限制
if models.Event == consts.EmsTemplateText {
return nil
}
if config == nil {
config, err = service.SysConfig().GetSmtp(ctx)
if err != nil {
return err
}
}
if gtime.Now().Before(models.CreatedAt.Add(time.Second * time.Duration(config.MinInterval))) {
return gerror.New("发送频繁,请稍后再试!")
}
if config.MaxIpLimit > 0 {
count, err := dao.SysEmsLog.NowDayCount(ctx, models.Event, models.Email)
if err != nil {
return err
}
if count >= config.MaxIpLimit {
return gerror.New("今天发送短信过多,请次日后再试!")
}
}
return
}
// VerifyCode 效验验证码
func (s *sSysEmsLog) VerifyCode(ctx context.Context, in sysin.VerifyEmsCodeInp) (err error) {
if in.Event == "" {
return gerror.New("事件不能为空")
}
if in.Email == "" {
return gerror.New("邮箱不能为空")
}
if in.Event == consts.EmsTemplateResetPwd || in.Event == consts.EmsTemplateText {
return gerror.Newf("事件类型无需验证:%v", in.Event)
}
config, err := service.SysConfig().GetSmtp(ctx)
if err != nil {
return err
}
var (
models *entity.SysEmsLog
)
if err = dao.SysEmsLog.Ctx(ctx).Where("event", in.Event).Where("email", in.Email).Order("id desc").Scan(&models); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
if models == nil {
return gerror.New("验证码错误")
}
if models.Times >= 10 {
return gerror.New("验证码错误次数过多,请重新发送!")
}
if in.Event != consts.EmsTemplateCode {
if models.Status == consts.EmsStatusUsed {
return gerror.New("验证码已使用,请重新发送!")
}
}
if gtime.Now().After(models.CreatedAt.Add(time.Second * time.Duration(config.CodeExpire))) {
return gerror.New("验证码已过期,请重新发送")
}
if models.Code != in.Code {
_, err = dao.SysEmsLog.Ctx(ctx).Where("id", models.Id).Increment("times", 1)
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
return gerror.New("验证码错误!")
}
_, err = dao.SysEmsLog.Ctx(ctx).Where("id", models.Id).Data(g.Map{
"times": models.Times + 1,
"status": consts.EmsStatusUsed,
"updated_at": gtime.Now(),
}).Update()
if err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return err
}
return
}

View File

@@ -20,6 +20,7 @@ import (
"hotgo/internal/consts"
"hotgo/internal/dao"
"hotgo/internal/library/contexts"
"hotgo/internal/library/hgorm/hook"
"hotgo/internal/library/location"
"hotgo/internal/library/queue"
"hotgo/internal/model/entity"
@@ -54,7 +55,7 @@ func (s *sSysLog) Export(ctx context.Context, in sysin.LogListInp) (err error) {
ReqId string `json:"req_id" description:"对外id"`
TakeUpTime int64 `json:"take_up_time" description:"请求耗时"`
CreatedAt *gtime.Time `json:"created_at" description:"创建时间"`
MemberName string `json:"member_name"`
MemberName string `json:"memberName"`
Region string `json:"region"`
}
@@ -222,7 +223,7 @@ func (s *sSysLog) AnalysisLog(ctx context.Context) entity.SysLog {
// View 获取指定字典类型信息
func (s *sSysLog) View(ctx context.Context, in sysin.LogViewInp) (res *sysin.LogViewModel, err error) {
if err = dao.SysLog.Ctx(ctx).Where("id", in.Id).Scan(&res); err != nil {
if err = dao.SysLog.Ctx(ctx).Hook(hook.CityLabel).Where("id", in.Id).Scan(&res); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return nil, err
}

View File

@@ -13,12 +13,16 @@ import (
"github.com/gogf/gf/v2/encoding/gjson"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/os/gctx"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/util/gconv"
"hotgo/internal/consts"
"hotgo/internal/dao"
"hotgo/internal/library/hgorm"
"hotgo/internal/library/hgorm/handler"
"hotgo/internal/library/hgorm/hook"
"hotgo/internal/library/location"
"hotgo/internal/library/queue"
"hotgo/internal/model/entity"
"hotgo/internal/model/input/form"
@@ -89,18 +93,19 @@ func (s *sSysLoginLog) List(ctx context.Context, in sysin.LoginLogListInp) (list
{Dao: dao.SysLog, Alias: "sysLog"},
})
if err = mod.Fields(fields).Handler(hgorm.HandlerFilterAuth).Page(in.Page, in.PerPage).OrderDesc(dao.SysLoginLog.Columns().Id).Scan(&list); err != nil {
if err = mod.Fields(fields).Hook(hook.CityLabel).Handler(handler.FilterAuth).Page(in.Page, in.PerPage).OrderDesc(dao.SysLoginLog.Columns().Id).Scan(&list); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return list, totalCount, err
}
for _, v := range list {
// 获取省市编码对应的地区名称
region, err := dao.SysProvinces.GetRegion(ctx, v.SysLogProvinceId, v.SysLogCityId)
if err != nil {
return list, totalCount, err
}
v.Region = region
g.DumpWithType(v)
//// 获取省市编码对应的地区名称
//region, err := location.ParseRegion(ctx, v.SysLogProvinceId, v.SysLogCityId, 0)
//if err != nil {
// return list, totalCount, err
//}
//v.Region = region
v.Os = useragent.GetOs(v.SysLogUserAgent)
v.Browser = useragent.GetBrowser(v.SysLogUserAgent)
}
@@ -162,9 +167,10 @@ func (s *sSysLoginLog) View(ctx context.Context, in sysin.LoginLogViewInp) (res
func (s *sSysLoginLog) Push(ctx context.Context, in sysin.LoginLogPushInp) {
var models entity.SysLoginLog
models.ReqId = gctx.CtxId(ctx)
models.MemberId = in.Response.UserId
models.MemberId = in.Response.Id
models.Username = in.Input.Username
models.LoginAt = gtime.Now()
models.LoginIp = location.GetClientIp(ghttp.RequestFromCtx(ctx))
models.Status = consts.StatusEnabled
if in.Err != nil {
@@ -173,7 +179,7 @@ func (s *sSysLoginLog) Push(ctx context.Context, in sysin.LoginLogPushInp) {
}
models.Response = gjson.New(consts.NilJsonToString)
if in.Response != nil && in.Response.UserId > 0 {
if in.Response != nil && in.Response.Id > 0 {
models.Response = gjson.New(in.Response)
}

View File

@@ -16,6 +16,7 @@ import (
"hotgo/internal/dao"
"hotgo/internal/library/hgorm"
"hotgo/internal/model/entity"
"hotgo/internal/model/input/form"
"hotgo/internal/model/input/sysin"
"hotgo/internal/service"
"hotgo/utility/tree"
@@ -165,7 +166,7 @@ func (s *sSysProvinces) MaxSort(ctx context.Context, in sysin.ProvincesMaxSortIn
return nil, err
}
res.Sort = res.Sort + g.Cfg().MustGet(ctx, "hotgo.admin.maxSortIncrement").Int()
res.Sort = form.DefaultMaxSort(ctx, res.Sort)
return res, nil
}
@@ -258,3 +259,34 @@ func (s *sSysProvinces) UniqueId(ctx context.Context, in sysin.ProvincesUniqueId
return res, nil
}
// Select 省市区选项
func (s *sSysProvinces) Select(ctx context.Context, in sysin.ProvincesSelectInp) (res *sysin.ProvincesSelectModel, err error) {
res = new(sysin.ProvincesSelectModel)
mod := dao.SysProvinces.Ctx(ctx).
Fields("id as value, title as label, level").
Where("pid", in.Value)
if err = mod.Order("sort asc,id asc").Scan(&res.List); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return
}
for _, v := range res.List {
if in.DataType == "p" {
v.IsLeaf = true
continue
}
if in.DataType == "pc" && v.Level >= 2 {
v.IsLeaf = true
continue
}
if in.DataType == "pca" && v.Level >= 3 {
v.IsLeaf = true
continue
}
}
return
}

View File

@@ -16,6 +16,7 @@ import (
"hotgo/internal/consts"
"hotgo/internal/dao"
"hotgo/internal/library/hgorm"
"hotgo/internal/library/hgorm/handler"
"hotgo/internal/model/entity"
"hotgo/internal/model/input/form"
"hotgo/internal/model/input/sysin"
@@ -83,7 +84,7 @@ func (s *sSysServeLog) List(ctx context.Context, in sysin.ServeLogListInp) (list
fields, err := hgorm.GenJoinSelect(ctx, sysin.ServeLogListModel{}, dao.SysServeLog, []*hgorm.Join{
{Dao: dao.SysLog, Alias: "sysLog"},
})
if err = mod.Fields(fields).Handler(hgorm.HandlerFilterAuth).Page(in.Page, in.PerPage).OrderDesc(dao.SysServeLog.Columns().Id).Scan(&list); err != nil {
if err = mod.Fields(fields).Handler(handler.FilterAuth).Page(in.Page, in.PerPage).OrderDesc(dao.SysServeLog.Columns().Id).Scan(&list); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return list, totalCount, err
}

View File

@@ -143,7 +143,7 @@ func (s *sSysSmsLog) List(ctx context.Context, in sysin.SmsLogListInp) (list []*
return list, totalCount, nil
}
if err = mod.Page(int(in.Page), int(in.PerPage)).Order("id desc").Scan(&list); err != nil {
if err = mod.Page(in.Page, in.PerPage).Order("id desc").Scan(&list); err != nil {
err = gerror.Wrap(err, consts.ErrorORM)
return list, totalCount, err
}