diff --git a/app/admin/apis/member_proxy.go b/app/admin/apis/member_proxy.go index 1b952ea..c72a953 100644 --- a/app/admin/apis/member_proxy.go +++ b/app/admin/apis/member_proxy.go @@ -429,7 +429,7 @@ func (e MemberProxy) UserRenewal(c *gin.Context) { if err != nil { e.Logger.Error(err) - e.Error(500, nil, "server error") + e.Error(500, nil, err.Error()) return } @@ -469,3 +469,30 @@ func (e MemberProxy) ChangeAutoRenewal(c *gin.Context) { e.OK(nil, "success") } + +// 删除自己的代理 +func (e MemberProxy) DeleteMyProxy(c *gin.Context) { + req := dto.MemberProxyDeleteMyProxyReq{} + s := service.MemberProxy{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + + if err != nil { + e.Logger.Error(err) + e.Error(500, nil, "server error") + } + + userId := user.GetUserId(c) + err = s.DeleteMyProxy(&req, userId) + + if err != nil { + e.Logger.Error(err) + e.Error(500, nil, err.Error()) + return + } + + e.OK(nil, "success") +} diff --git a/app/admin/apis/sms_phone.go b/app/admin/apis/sms_phone.go index 3eb7a14..f00ecd5 100644 --- a/app/admin/apis/sms_phone.go +++ b/app/admin/apis/sms_phone.go @@ -377,3 +377,30 @@ func (e SmsPhone) CancelNumber(c *gin.Context) { e.OK(nil, "取消号码成功") } + +// 修改自动续费状态 +func (e SmsPhone) ChangeAutoRenew(c *gin.Context) { + req := dto.SmsPhoneChangeAutoRenewReq{} + s := service.SmsPhone{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + + userId := user.GetUserId(c) + + code := s.ChangeAutoRenew(&req, userId) + + if code != statuscode.Success { + e.Error(code, nil, statuscode.GetMsg(code, "zh")) + return + } + + e.OK(nil, "修改自动续费状态成功") +} diff --git a/app/admin/apis/sms_renewal_log.go b/app/admin/apis/sms_renewal_log.go new file mode 100644 index 0000000..132019a --- /dev/null +++ b/app/admin/apis/sms_renewal_log.go @@ -0,0 +1,192 @@ +package apis + +import ( + "fmt" + + "github.com/gin-gonic/gin" + "github.com/go-admin-team/go-admin-core/sdk/api" + "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth/user" + _ "github.com/go-admin-team/go-admin-core/sdk/pkg/response" + + "go-admin/app/admin/models" + "go-admin/app/admin/service" + "go-admin/app/admin/service/dto" + "go-admin/common/actions" +) + +type SmsRenewalLog struct { + api.Api +} + +// GetPage 获取短信续期记录列表 +// @Summary 获取短信续期记录列表 +// @Description 获取短信续期记录列表 +// @Tags 短信续期记录 +// @Param type query int64 false "类型 0-长效 1-短效" +// @Param pageSize query int false "页条数" +// @Param pageIndex query int false "页码" +// @Success 200 {object} response.Response{data=response.Page{list=[]models.SmsRenewalLog}} "{"code": 200, "data": [...]}" +// @Router /api/v1/sms-renewal-log [get] +// @Security Bearer +func (e SmsRenewalLog) GetPage(c *gin.Context) { + req := dto.SmsRenewalLogGetPageReq{} + s := service.SmsRenewalLog{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + + p := actions.GetPermissionFromContext(c) + list := make([]models.SmsRenewalLog, 0) + var count int64 + + err = s.GetPage(&req, p, &list, &count) + if err != nil { + e.Error(500, err, fmt.Sprintf("获取短信续期记录失败,\r\n失败信息 %s", err.Error())) + return + } + + e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功") +} + +// Get 获取短信续期记录 +// @Summary 获取短信续期记录 +// @Description 获取短信续期记录 +// @Tags 短信续期记录 +// @Param id path int false "id" +// @Success 200 {object} response.Response{data=models.SmsRenewalLog} "{"code": 200, "data": [...]}" +// @Router /api/v1/sms-renewal-log/{id} [get] +// @Security Bearer +func (e SmsRenewalLog) Get(c *gin.Context) { + req := dto.SmsRenewalLogGetReq{} + s := service.SmsRenewalLog{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + var object models.SmsRenewalLog + + p := actions.GetPermissionFromContext(c) + err = s.Get(&req, p, &object) + if err != nil { + e.Error(500, err, fmt.Sprintf("获取短信续期记录失败,\r\n失败信息 %s", err.Error())) + return + } + + e.OK( object, "查询成功") +} + +// Insert 创建短信续期记录 +// @Summary 创建短信续期记录 +// @Description 创建短信续期记录 +// @Tags 短信续期记录 +// @Accept application/json +// @Product application/json +// @Param data body dto.SmsRenewalLogInsertReq true "data" +// @Success 200 {object} response.Response "{"code": 200, "message": "添加成功"}" +// @Router /api/v1/sms-renewal-log [post] +// @Security Bearer +func (e SmsRenewalLog) Insert(c *gin.Context) { + req := dto.SmsRenewalLogInsertReq{} + s := service.SmsRenewalLog{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + // 设置创建人 + req.SetCreateBy(user.GetUserId(c)) + + err = s.Insert(&req) + if err != nil { + e.Error(500, err, fmt.Sprintf("创建短信续期记录失败,\r\n失败信息 %s", err.Error())) + return + } + + e.OK(req.GetId(), "创建成功") +} + +// Update 修改短信续期记录 +// @Summary 修改短信续期记录 +// @Description 修改短信续期记录 +// @Tags 短信续期记录 +// @Accept application/json +// @Product application/json +// @Param id path int true "id" +// @Param data body dto.SmsRenewalLogUpdateReq true "body" +// @Success 200 {object} response.Response "{"code": 200, "message": "修改成功"}" +// @Router /api/v1/sms-renewal-log/{id} [put] +// @Security Bearer +func (e SmsRenewalLog) Update(c *gin.Context) { + req := dto.SmsRenewalLogUpdateReq{} + s := service.SmsRenewalLog{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + req.SetUpdateBy(user.GetUserId(c)) + p := actions.GetPermissionFromContext(c) + + err = s.Update(&req, p) + if err != nil { + e.Error(500, err, fmt.Sprintf("修改短信续期记录失败,\r\n失败信息 %s", err.Error())) + return + } + e.OK( req.GetId(), "修改成功") +} + +// Delete 删除短信续期记录 +// @Summary 删除短信续期记录 +// @Description 删除短信续期记录 +// @Tags 短信续期记录 +// @Param data body dto.SmsRenewalLogDeleteReq true "body" +// @Success 200 {object} response.Response "{"code": 200, "message": "删除成功"}" +// @Router /api/v1/sms-renewal-log [delete] +// @Security Bearer +func (e SmsRenewalLog) Delete(c *gin.Context) { + s := service.SmsRenewalLog{} + req := dto.SmsRenewalLogDeleteReq{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + + // req.SetUpdateBy(user.GetUserId(c)) + p := actions.GetPermissionFromContext(c) + + err = s.Remove(&req, p) + if err != nil { + e.Error(500, err, fmt.Sprintf("删除短信续期记录失败,\r\n失败信息 %s", err.Error())) + return + } + e.OK( req.GetId(), "删除成功") +} diff --git a/app/admin/models/sms_phone.go b/app/admin/models/sms_phone.go index 02ebafb..a4bc886 100644 --- a/app/admin/models/sms_phone.go +++ b/app/admin/models/sms_phone.go @@ -24,6 +24,7 @@ type SmsPhone struct { ExpireTime *time.Time `json:"expireTime" gorm:"type:datetime;comment:过期时间"` Actived int `json:"actived" gorm:"type:tinyint;comment:是否激活(长期租赁如果第一次没接收到验证码 则不会激活号码) 1-未激活 2-已激活 3-已失效"` Price decimal.Decimal `json:"price" gorm:"type:decimal(10,2);comment:价格"` + AutoRenewal int `json:"autoRenewal" gorm:"type:tinyint;comment:是否自动续费 1-自动续费 2-手动续费"` models.ModelTime models.ControlBy } diff --git a/app/admin/models/sms_renewal_log.go b/app/admin/models/sms_renewal_log.go new file mode 100644 index 0000000..472adb5 --- /dev/null +++ b/app/admin/models/sms_renewal_log.go @@ -0,0 +1,35 @@ +package models + +import ( + "time" + + "go-admin/common/models" + + "github.com/shopspring/decimal" +) + +type SmsRenewalLog struct { + models.Model + + PhoneId int `json:"phoneId" gorm:"type:bigint;comment:号码id"` + Type int `json:"type" gorm:"type:tinyint;comment:类型 0-长效 1-短效"` + UserId int `json:"userId" gorm:"type:bigint;comment:用户id"` + Amount decimal.Decimal `json:"amount" gorm:"type:decimal(10,2);comment:扣费金额"` + BeforeTime time.Time `json:"beforeTime" gorm:"type:datetime;comment:续费前过期时间"` + Period int `json:"period" gorm:"type:int;comment:时间段"` + models.ModelTime + models.ControlBy +} + +func (SmsRenewalLog) TableName() string { + return "sms_renewal_log" +} + +func (e *SmsRenewalLog) Generate() models.ActiveRecord { + o := *e + return &o +} + +func (e *SmsRenewalLog) GetId() interface{} { + return e.Id +} diff --git a/app/admin/router/member_proxy.go b/app/admin/router/member_proxy.go index 2241a85..e42abcd 100644 --- a/app/admin/router/member_proxy.go +++ b/app/admin/router/member_proxy.go @@ -28,6 +28,8 @@ func registerMemberProxyRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMi r2.POST("reset-generate-proxy", api.ResetGenerateProxy) //重置流量代理账号 r2.POST("user-renewal", api.UserRenewal) //用户续费 r2.POST("change-auto-renewal", api.ChangeAutoRenewal) //修改自动续费 + + r2.DELETE("my", api.DeleteMyProxy) //删除我的代理 } r := v1.Group("/member-proxy").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole()) diff --git a/app/admin/router/sms_phone.go b/app/admin/router/sms_phone.go index e51484d..bc9898c 100644 --- a/app/admin/router/sms_phone.go +++ b/app/admin/router/sms_phone.go @@ -25,6 +25,7 @@ func registerSmsPhoneRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddl r1.POST("weakUp", api.WeakUp) // 新增号码 r1.DELETE("my-number", api.DeleteMyNumber) // 删除自己的号码 r1.PUT("cancel", api.CancelNumber) //取消号码 + r1.PUT("auto-renewal", api.ChangeAutoRenew) //修改自动续费状态 } r := v1.Group("/sms-phone").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole()) diff --git a/app/admin/router/sms_renewal_log.go b/app/admin/router/sms_renewal_log.go new file mode 100644 index 0000000..fdf0e3a --- /dev/null +++ b/app/admin/router/sms_renewal_log.go @@ -0,0 +1,27 @@ +package router + +import ( + "github.com/gin-gonic/gin" + jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth" + + "go-admin/app/admin/apis" + "go-admin/common/middleware" + "go-admin/common/actions" +) + +func init() { + routerCheckRole = append(routerCheckRole, registerSmsRenewalLogRouter) +} + +// registerSmsRenewalLogRouter +func registerSmsRenewalLogRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) { + api := apis.SmsRenewalLog{} + r := v1.Group("/sms-renewal-log").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole()) + { + r.GET("", actions.PermissionAction(), api.GetPage) + r.GET("/:id", actions.PermissionAction(), api.Get) + r.POST("", api.Insert) + r.PUT("/:id", actions.PermissionAction(), api.Update) + r.DELETE("", api.Delete) + } +} \ No newline at end of file diff --git a/app/admin/service/cliproxy_server.go b/app/admin/service/cliproxy_server.go index fb3b3d0..038180c 100644 --- a/app/admin/service/cliproxy_server.go +++ b/app/admin/service/cliproxy_server.go @@ -249,6 +249,47 @@ func (e *CliProxyService) GetUserIpList(page int, limit int, lang, code string) return resp.Data, nil } +// 续期静态ip +func (e *CliProxyService) Renewal(ip string, day int) error { + url := "/api/static/renewal" + key, err := e.GetKey() + + if err != nil { + e.Log.Errorf("获取key失败 %v", err) + return err + } + + headers, _ := GetHeaders() + client := httphelper.NewHTTPClient(10*time.Second, config.ExtConfig.CliproxyApiUrl, headers) + + var buf bytes.Buffer + writer := multipart.NewWriter(&buf) + // 添加字段 + _ = writer.WriteField("lang", "en") + _ = writer.WriteField("ip", ip) + _ = writer.WriteField("day", strconv.Itoa(day)) + _ = writer.WriteField("key", key) + + writer.Close() + resp := dto.CliProxyResultResp[dto.CliProxyUserListResp]{} + contentType := writer.FormDataContentType() + err = client.PostWithContentType(url, &buf, contentType, nil, &resp) + + if err != nil { + return err + } + if resp.Code != 0 { + if resp.Code == 300 { + e.Log.Errorf("key 失效 code:%d", resp.Code) + return errors.New("key 失效") + } + e.Log.Errorf("请求失败 params:%v err: %v", nil, resp.Msg) + return errors.New(resp.Msg) + } + + return nil +} + // 获取私钥 func (e *CliProxyService) GetKey() (string, error) { sysConfigService := SysConfig{Service: e.Service} @@ -264,6 +305,86 @@ func (e *CliProxyService) GetKey() (string, error) { return configResp.ConfigValue, nil } +// 获取token +func (e *CliProxyService) GetToken() (string, error) { + val, _ := redishelper.DefaultRedis.GetString(rediskey.CliProxyTokenPrefix) + + if val != "" { + resp := dto.CliProxySigninResp{} + sonic.UnmarshalString(val, &resp) + + if resp.Token != "" { + return resp.Token, nil + } + } + + resp, err := e.resetToken() + if err != nil { + return resp.Token, err + } + + return resp.Token, nil +} + +// 充值token +func (e *CliProxyService) resetToken() (dto.CliProxySigninResp, error) { + configService := SysConfig{} + configService.Orm = e.Orm + configService.Log = e.Log + configReq := dto.SysConfigByKeyReq{ + ConfigKey: "proxy_dash_email", + } + configResp := dto.GetSysConfigByKEYForServiceResp{} + passwordConfigReq := dto.SysConfigByKeyReq{ + ConfigKey: "proxy_dash_password", + } + passwordConfigResp := dto.GetSysConfigByKEYForServiceResp{} + if err := configService.GetWithKey(&configReq, &configResp); err != nil { + return dto.CliProxySigninResp{}, err + } + if err := configService.GetWithKey(&passwordConfigReq, &passwordConfigResp); err != nil { + return dto.CliProxySigninResp{}, err + } + + resp := dto.CliProxyResultResp[dto.CliProxySigninResp]{} + api := "/v1/signin" + headers, _ := GetHeaders() + client := httphelper.NewHTTPClient(10*time.Second, config.ExtConfig.CliproxyApiUrl, headers) + + var buf bytes.Buffer + writer := multipart.NewWriter(&buf) + // 添加字段 + _ = writer.WriteField("lang", "en") + _ = writer.WriteField("email", configResp.ConfigValue) + _ = writer.WriteField("pwd", passwordConfigResp.ConfigValue) + + writer.Close() + + contentType := writer.FormDataContentType() + err := client.PostWithContentType(api, &buf, contentType, nil, &resp) + + if err != nil { + return dto.CliProxySigninResp{}, err + } + + if resp.Code != 0 || resp.Data.Token == "" { + return dto.CliProxySigninResp{}, errors.New(resp.Msg) + } + + val, err := sonic.MarshalString(resp.Data) + + if err != nil { + return dto.CliProxySigninResp{}, err + } + + if val != "" { + if err := redishelper.DefaultRedis.SetString(rediskey.CliProxyTokenPrefix, val); err != nil { + return dto.CliProxySigninResp{}, err + } + } + return resp.Data, nil +} + // 获取线路 func (e *CliProxyService) GetTrafficServer(req *dto.MemberProxyGetTrafficServerReq) ([]dto.CliProxyTrafficServerResp, error) { api := "/v1/traffic/server" @@ -271,10 +392,10 @@ func (e *CliProxyService) GetTrafficServer(req *dto.MemberProxyGetTrafficServerR client := httphelper.NewHTTPClient(10*time.Second, config.ExtConfig.CliproxyApiUrl, headers) resp := dto.CliProxyResultResp[[]dto.CliProxyTrafficServerResp]{} - key, err := e.GetKey() + token, err := e.GetToken() if err != nil { - e.Log.Errorf("获取key失败 %v", err) + e.Log.Errorf("获取token失败 %v", err) return nil, err } @@ -282,7 +403,7 @@ func (e *CliProxyService) GetTrafficServer(req *dto.MemberProxyGetTrafficServerR writer := multipart.NewWriter(&buf) // 添加字段 _ = writer.WriteField("lang", "en") - _ = writer.WriteField("key", key) + _ = writer.WriteField("token", token) writer.Close() diff --git a/app/admin/service/dto/cliproxy.go b/app/admin/service/dto/cliproxy.go index 9e59d28..6edc3da 100644 --- a/app/admin/service/dto/cliproxy.go +++ b/app/admin/service/dto/cliproxy.go @@ -101,3 +101,7 @@ type MemberProxyChangeAutoRenewalReq struct { ProxyId int `json:"proxyId"` AutoRenewal bool `json:"autoRenewal"` } + +type MemberProxyDeleteMyProxyReq struct { + Id int `json:"id"` +} diff --git a/app/admin/service/dto/sms_phone.go b/app/admin/service/dto/sms_phone.go index e7d6f39..4fcce93 100644 --- a/app/admin/service/dto/sms_phone.go +++ b/app/admin/service/dto/sms_phone.go @@ -167,3 +167,8 @@ func (s *DeleteMyNumberReq) Validate() error { type SmsPhoneCancelNumberReq struct { Id int `json:"id" comment:"短信号码id"` } + +type SmsPhoneChangeAutoRenewReq struct { + Id int `json:"id" comment:"短信号码id"` + AutoRenew int `json:"autoRenew" comment:"是否自动续费 1-不自动续费 2-自动续费"` +} diff --git a/app/admin/service/dto/sms_renewal_log.go b/app/admin/service/dto/sms_renewal_log.go new file mode 100644 index 0000000..da59c8b --- /dev/null +++ b/app/admin/service/dto/sms_renewal_log.go @@ -0,0 +1,110 @@ +package dto + +import ( + "time" + + "go-admin/app/admin/models" + "go-admin/common/dto" + common "go-admin/common/models" + + "github.com/shopspring/decimal" +) + +type SmsRenewalLogGetPageReq struct { + dto.Pagination `search:"-"` + Type int64 `form:"type" search:"type:exact;column:type;table:sms_renewal_log" comment:"类型 0-长效 1-短效"` + SmsRenewalLogOrder +} + +type SmsRenewalLogOrder struct { + Id string `form:"idOrder" search:"type:order;column:id;table:sms_renewal_log"` + PhoneId string `form:"phoneIdOrder" search:"type:order;column:phone_id;table:sms_renewal_log"` + Type string `form:"typeOrder" search:"type:order;column:type;table:sms_renewal_log"` + UserId string `form:"userIdOrder" search:"type:order;column:user_id;table:sms_renewal_log"` + Amount string `form:"amountOrder" search:"type:order;column:amount;table:sms_renewal_log"` + BeforeTime string `form:"beforeTimeOrder" search:"type:order;column:before_time;table:sms_renewal_log"` + Period string `form:"periodOrder" search:"type:order;column:period;table:sms_renewal_log"` + CreatedAt string `form:"createdAtOrder" search:"type:order;column:created_at;table:sms_renewal_log"` + UpdatedAt string `form:"updatedAtOrder" search:"type:order;column:updated_at;table:sms_renewal_log"` + DeletedAt string `form:"deletedAtOrder" search:"type:order;column:deleted_at;table:sms_renewal_log"` + CreateBy string `form:"createByOrder" search:"type:order;column:create_by;table:sms_renewal_log"` + UpdateBy string `form:"updateByOrder" search:"type:order;column:update_by;table:sms_renewal_log"` +} + +func (m *SmsRenewalLogGetPageReq) GetNeedSearch() interface{} { + return *m +} + +type SmsRenewalLogInsertReq struct { + Id int `json:"-" comment:"主键id"` // 主键id + PhoneId int `json:"phoneId" comment:"号码id"` + Type int `json:"type" comment:"类型 0-长效 1-短效"` + UserId int `json:"userId" comment:"用户id"` + Amount decimal.Decimal `json:"amount" comment:"扣费金额"` + BeforeTime time.Time `json:"beforeTime" comment:"续费前过期时间"` + Period int `json:"period" comment:"时间段"` + common.ControlBy +} + +func (s *SmsRenewalLogInsertReq) Generate(model *models.SmsRenewalLog) { + if s.Id == 0 { + model.Model = common.Model{Id: s.Id} + } + model.PhoneId = s.PhoneId + model.Type = s.Type + model.UserId = s.UserId + model.Amount = s.Amount + model.BeforeTime = s.BeforeTime + model.Period = s.Period + model.CreateBy = s.CreateBy // 添加这而,需要记录是被谁创建的 +} + +func (s *SmsRenewalLogInsertReq) GetId() interface{} { + return s.Id +} + +type SmsRenewalLogUpdateReq struct { + Id int `uri:"id" comment:"主键id"` // 主键id + PhoneId int `json:"phoneId" comment:"号码id"` + Type int `json:"type" comment:"类型 0-长效 1-短效"` + UserId int `json:"userId" comment:"用户id"` + Amount decimal.Decimal `json:"amount" comment:"扣费金额"` + BeforeTime time.Time `json:"beforeTime" comment:"续费前过期时间"` + Period int `json:"period" comment:"时间段"` + common.ControlBy +} + +func (s *SmsRenewalLogUpdateReq) Generate(model *models.SmsRenewalLog) { + if s.Id == 0 { + model.Model = common.Model{Id: s.Id} + } + model.PhoneId = s.PhoneId + model.Type = s.Type + model.UserId = s.UserId + model.Amount = s.Amount + model.BeforeTime = s.BeforeTime + model.Period = s.Period + model.UpdateBy = s.UpdateBy // 添加这而,需要记录是被谁更新的 +} + +func (s *SmsRenewalLogUpdateReq) GetId() interface{} { + return s.Id +} + +// SmsRenewalLogGetReq 功能获取请求参数 +type SmsRenewalLogGetReq struct { + Id int `uri:"id"` +} + +func (s *SmsRenewalLogGetReq) GetId() interface{} { + return s.Id +} + +// SmsRenewalLogDeleteReq 功能删除请求参数 +type SmsRenewalLogDeleteReq struct { + Ids []int `json:"ids"` +} + +func (s *SmsRenewalLogDeleteReq) GetId() interface{} { + return s.Ids +} diff --git a/app/admin/service/member_proxy.go b/app/admin/service/member_proxy.go index 6f4f687..0119544 100644 --- a/app/admin/service/member_proxy.go +++ b/app/admin/service/member_proxy.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "math/rand" + "strconv" "time" "github.com/go-admin-team/go-admin-core/sdk/service" @@ -20,6 +21,25 @@ type MemberProxy struct { service.Service } +// 删除个人代理 +func (e MemberProxy) DeleteMyProxy(req *dto.MemberProxyDeleteMyProxyReq, userId int) error { + var data models.MemberProxy + if err := e.Orm.Model(&data).Where("id =? and user_id =?", req.Id, userId).First(&data).Error; err != nil { + e.Log.Errorf("删除代理失败 记录不存在 %v", err) + } + + if data.Expired.After(time.Now()) { + return errors.New("该代理还未到期") + } + + if err := e.Orm.Model(&data).Delete(&data, data.GetId()).Error; err != nil { + e.Log.Errorf("删除代理失败 err:%v", err.Error()) + return errors.New("删除失败") + } + + return nil +} + // 切换自动续状态 func (e MemberProxy) ChangeAutoRenewal(req *dto.MemberProxyChangeAutoRenewalReq, userId int) error { var data models.MemberProxy @@ -64,7 +84,7 @@ func (e MemberProxy) GetAutoRenewalProxys() ([]models.MemberProxy, error) { endDate := time.Now().Add(24 * time.Hour) startDate := time.Now() - if err := e.Orm.Model(&models.MemberProxy{}).Where("status =1 and auto_renewal =1 and expired BETWEEN ? AND ?", startDate, endDate).Select("id,type,user_id,expired").Find(&datas).Error; err != nil { + if err := e.Orm.Model(&models.MemberProxy{}).Where("status =1 and auto_renewal =1 and expired BETWEEN ? AND ?", startDate, endDate).Select("id,type,user_id,ip,expired").Find(&datas).Error; err != nil { return nil, err } return datas, nil @@ -142,12 +162,13 @@ func (e MemberProxy) GetMyProxy(req *dto.MemberProxyGetMyProxyReq, resp *[]dto.M respItem.UserName = item.UserName respItem.Expired = item.Expired respItem.Status = item.Status + respItem.Password = item.Password if item.AutoRenewal == 1 { respItem.AutoRenewal = true } - if cliProxyConfig.ConfigValue != "" { + if cliProxyConfig.ConfigValue != "" && item.Password == "" { respItem.Password = cliProxyConfig.ConfigValue } *resp = append(*resp, respItem) @@ -264,13 +285,24 @@ func (e *MemberProxy) CreateProxy(req *dto.MemberProxyInsertReq, userId int) (de return balance, errors.New("余额不足") } + configService := SysConfig{Service: e.Service} + cliProxyConfig := dto.GetSysConfigByKEYForServiceResp{} + configService.GetWithKey(&dto.SysConfigByKeyReq{ConfigKey: "traffic_proxy_effective_day"}, &cliProxyConfig) + + if cliProxyConfig.ConfigValue == "" { + e.Log.Error("获取动态ip默认时长失败") + return balance, errors.New("server error") + } + + hour, _ := strconv.Atoi(cliProxyConfig.ConfigValue) data.Type = 2 - data.Day = 30 + // data.Day = day data.UserId = userId data.SessionType = "Sticky IP" data.UserName = userName data.Status = 1 - data.Expired = time.Now().AddDate(0, 0, 30) + period := time.Duration(hour) * time.Hour + data.Expired = time.Now().Add(period) err = e.Orm.Transaction(func(tx *gorm.DB) error { if err1 := tx.Create(&data).Error; err1 != nil { diff --git a/app/admin/service/member_renewal_log.go b/app/admin/service/member_renewal_log.go index 6ee8be8..017aaf0 100644 --- a/app/admin/service/member_renewal_log.go +++ b/app/admin/service/member_renewal_log.go @@ -31,7 +31,7 @@ func (e *MemberRenewalLog) AutoRenewal() error { balanceService := MemberBalance{Service: e.Service} configService := SysConfig{Service: e.Service} configResp := dto.GetSysConfigByKEYForServiceResp{} - configService.GetWithKey(&dto.SysConfigByKeyReq{ConfigKey: "deduction_standard"}, &configResp) + configService.GetWithKey(&dto.SysConfigByKeyReq{ConfigKey: "ip_renew_deduction_standard"}, &configResp) if configResp.ConfigValue == "" { e.Log.Error("没有设置扣费标准,不自动续期") @@ -70,7 +70,7 @@ func (e *MemberRenewalLog) AutoRenewal() error { } for _, proxy := range autoProxys { - if proxy.Type == 1 { + if proxy.Type == 0 { continue } @@ -96,17 +96,33 @@ func (e *MemberRenewalLog) DoRenewal(proxy models.MemberProxy, amount decimal.De renewalLog.Amount = amount renewalLog.Day = 30 renewalLog.ProxyId = proxy.Id + cliproxyService := CliProxyService{Service: e.Service} err := e.Orm.Transaction(func(tx *gorm.DB) error { if err := tx.Save(&renewalLog).Error; err != nil { return err } - if err := tx.Exec("UPDATE member_balance SET balance = balance -? WHERE user_id =? AND balance >= ?", amount, proxy.UserId, amount).Error; err != nil { - return err + db := tx.Exec("UPDATE member_balance SET balance = balance -? WHERE user_id =? AND balance >= ?", amount, proxy.UserId, amount) + + if db.RowsAffected != 1 { + e.Log.Errorf("续费扣费失败,ip:%s,err:%s", proxy.Ip, "余额不足") + return errors.New("余额不足") + } + + if db.Error != nil { + e.Log.Errorf("续费扣费失败,ip:%s,err:%s", proxy.Ip, db.Error.Error()) + return db.Error } if err := tx.Model(&proxy).Update("expired", proxy.Expired.AddDate(0, 0, 30)).Error; err != nil { + e.Log.Errorf("续费修改过期时间失败,ip:%s,err:%s", proxy.Ip, err.Error()) + + return err + } + + if err := cliproxyService.Renewal(proxy.Ip, 30); err != nil { + e.Log.Errorf("续费失败,ip:%s,err:%s", proxy.Ip, err.Error()) return err } @@ -119,17 +135,17 @@ func (e *MemberRenewalLog) DoRenewal(proxy models.MemberProxy, amount decimal.De func (e *MemberRenewalLog) UserRenewal(req *dto.MemberProxyUserRenewalReq, userId int) (decimal.Decimal, error) { configService := SysConfig{Service: e.Service} configResp := dto.GetSysConfigByKEYForServiceResp{} - configService.GetWithKey(&dto.SysConfigByKeyReq{ConfigKey: "deduction_standard"}, &configResp) + configService.GetWithKey(&dto.SysConfigByKeyReq{ConfigKey: "ip_renew_deduction_standard"}, &configResp) if configResp.ConfigValue == "" { - e.Log.Error("没有设置扣费标准,不自动续期") + e.Log.Error("没有设置扣费标准,无法续期") return decimal.Zero, nil } amount, err := decimal.NewFromString(configResp.ConfigValue) if err != nil { - e.Log.Error("扣费标准设置错误,不自动续期") + e.Log.Error("扣费标准设置错误,无法续期") return decimal.Zero, errors.New("续费失败,请联系管理员") } @@ -149,8 +165,8 @@ func (e *MemberRenewalLog) UserRenewal(req *dto.MemberProxyUserRenewalReq, userI return balance, errors.New("代理不存在") } - if proxy.Type == 1 { - return balance, errors.New("长效ip不支持续费") + if proxy.Type == 0 { + return balance, errors.New("短效ip不支持续费") } err = e.DoRenewal(proxy, amount) diff --git a/app/admin/service/sms_phone.go b/app/admin/service/sms_phone.go index 124b485..715d777 100644 --- a/app/admin/service/sms_phone.go +++ b/app/admin/service/sms_phone.go @@ -208,7 +208,8 @@ func (e *SmsPhone) GetNumber(req *dto.GetNumberReq, userId int) (decimal.Decimal smsPhone.Price = price if req.Type == 1 { - now = now.AddDate(0, req.Period, 0) + days := req.Period * 30 + now = now.AddDate(0, 0, days) smsPhone.ExpireTime = &now } else { now = now.Add(time.Minute * time.Duration(serviceItem.ExpirationMinutes)) @@ -556,6 +557,135 @@ func (e *SmsPhone) CancelRental(activationId int) int { } } +// 自动续期 +func (e SmsServices) AutoRenewal() error { + var datas []models.SmsPhone + var data models.SmsPhone + startTime := time.Now().Add(-24 * time.Hour) + endTime := time.Now().Add(24 * time.Hour) + + configService := SysConfig{Service: e.Service} + configResp := dto.GetSysConfigByKEYForServiceResp{} + configService.GetWithKey(&dto.SysConfigByKeyReq{ConfigKey: "long_number_renew_deduction_standard"}, &configResp) + + if configResp.ConfigValue == "" { + e.Log.Errorf("获取续费价格失败") + return nil + } + + price, _ := decimal.NewFromString(configResp.ConfigValue) + if price.IsZero() { + e.Log.Errorf("获取续费价格失败") + return nil + } + + if err := e.Orm.Model(&models.SmsPhone{}).Where("auto_renewal =1 and type =1 and actived =2 and expire_time >=? and expire_time = ?", price, item.UserId, price) + + if db.Error != nil { + return db.Error + } + + if db.RowsAffected == 0 { + return errors.New("余额不足") + } + + if err1 := tx.Create(&renewLog).Error; err1 != nil { + + return errors.New("创建续费日志失败") + } + + newExpireTime := item.ExpireTime.AddDate(0, 0, 30) + if err1 := tx.Model(data).Where("id =?", item.Id).Update("expire_time", newExpireTime).Error; err1 != nil { + return err1 + } + return nil + }); err != nil { + e.Log.Errorf("自动续期失败:%s", err.Error()) + } + } + + return nil +} + +// ChangeAutoRenew 修改自动续期 +func (e *SmsPhone) ChangeAutoRenew(req *dto.SmsPhoneChangeAutoRenewReq, userId int) int { + var data models.SmsPhone + + if err := e.Orm.Model(data).Where("id =? and user_id =?", req.Id, userId).First(&data).Error; err != nil { + e.Log.Errorf("修改自动续期 数据不存在 id:%d err:%s", req.Id, err.Error()) + return statuscode.SmsNotExisted + } + + // 短期租赁不支持自动续期 + if data.Type == 0 { + return statuscode.SmsNotAutoRenew + } + + status := false + changeAutoRenewal := 2 + if req.AutoRenew == 1 { + status = true + changeAutoRenewal = 1 + } + + data.AutoRenewal = req.AutoRenew + code := e.ChangeAutoRenewForApi(data.ActivationId, status) + + if code != statuscode.Success { + return statuscode.ServerError + } + + if err := e.Orm.Model(&data).Update("auto_renewal", changeAutoRenewal).Error; err != nil { + e.Log.Errorf("修改自动续期失败 id:%d, status:%t", data.ActivationId, status) + } + + return statuscode.Success +} + +// ChangeAutoRenew 修改自动续期 +// activationId 短信id +// status 状态 +func (e *SmsPhone) ChangeAutoRenewForApi(activationId int, status bool) int { + key, err := GetApiKey(e) + + if err != statuscode.Success { + e.Log.Errorf("查询sms api请求失败 %d", activationId) + return statuscode.ServerError + } + + url := fmt.Sprintf("?api_key=%s&action=setAutoRenew&id=%d&value=%t", key.ConfigValue, activationId, status) + client := httphelper.NewHTTPClient(10*time.Second, config.ExtConfig.DaisysmsUrl, nil) + bytes, err1 := client.GetRaw(url, nil) + + if err1 != nil { + e.Log.Errorf("租赁请求失败 %s", err1.Error()) + return statuscode.ServerError + } + + content := string(bytes) + + if content == "OK" { + return statuscode.Success + } else { + e.Log.Errorf("修改自动续期请求失败 id:%d, status:%t, %s", activationId, status, content) + return statuscode.ServerError + } +} + // GetPage 获取SmsPhone列表 func (e *SmsPhone) GetPage(c *dto.SmsPhoneGetPageReq, p *actions.DataPermission, list *[]models.SmsPhone, count *int64) error { var err error diff --git a/app/admin/service/sms_renewal_log.go b/app/admin/service/sms_renewal_log.go new file mode 100644 index 0000000..dff19e9 --- /dev/null +++ b/app/admin/service/sms_renewal_log.go @@ -0,0 +1,109 @@ +package service + +import ( + "errors" + + "github.com/go-admin-team/go-admin-core/sdk/service" + "gorm.io/gorm" + + "go-admin/app/admin/models" + "go-admin/app/admin/service/dto" + "go-admin/common/actions" + cDto "go-admin/common/dto" +) + +type SmsRenewalLog struct { + service.Service +} + +// GetPage 获取SmsRenewalLog列表 +func (e *SmsRenewalLog) GetPage(c *dto.SmsRenewalLogGetPageReq, p *actions.DataPermission, list *[]models.SmsRenewalLog, count *int64) error { + var err error + var data models.SmsRenewalLog + + err = e.Orm.Model(&data). + Scopes( + cDto.MakeCondition(c.GetNeedSearch()), + cDto.Paginate(c.GetPageSize(), c.GetPageIndex()), + actions.Permission(data.TableName(), p), + ). + Find(list).Limit(-1).Offset(-1). + Count(count).Error + if err != nil { + e.Log.Errorf("SmsRenewalLogService GetPage error:%s \r\n", err) + return err + } + return nil +} + +// Get 获取SmsRenewalLog对象 +func (e *SmsRenewalLog) Get(d *dto.SmsRenewalLogGetReq, p *actions.DataPermission, model *models.SmsRenewalLog) error { + var data models.SmsRenewalLog + + err := e.Orm.Model(&data). + Scopes( + actions.Permission(data.TableName(), p), + ). + First(model, d.GetId()).Error + if err != nil && errors.Is(err, gorm.ErrRecordNotFound) { + err = errors.New("查看对象不存在或无权查看") + e.Log.Errorf("Service GetSmsRenewalLog error:%s \r\n", err) + return err + } + if err != nil { + e.Log.Errorf("db error:%s", err) + return err + } + return nil +} + +// Insert 创建SmsRenewalLog对象 +func (e *SmsRenewalLog) Insert(c *dto.SmsRenewalLogInsertReq) error { + var err error + var data models.SmsRenewalLog + c.Generate(&data) + err = e.Orm.Create(&data).Error + if err != nil { + e.Log.Errorf("SmsRenewalLogService Insert error:%s \r\n", err) + return err + } + return nil +} + +// Update 修改SmsRenewalLog对象 +func (e *SmsRenewalLog) Update(c *dto.SmsRenewalLogUpdateReq, p *actions.DataPermission) error { + var err error + var data = models.SmsRenewalLog{} + e.Orm.Scopes( + actions.Permission(data.TableName(), p), + ).First(&data, c.GetId()) + c.Generate(&data) + + db := e.Orm.Save(&data) + if err = db.Error; err != nil { + e.Log.Errorf("SmsRenewalLogService Save error:%s \r\n", err) + return err + } + if db.RowsAffected == 0 { + return errors.New("无权更新该数据") + } + return nil +} + +// Remove 删除SmsRenewalLog +func (e *SmsRenewalLog) Remove(d *dto.SmsRenewalLogDeleteReq, p *actions.DataPermission) error { + var data models.SmsRenewalLog + + db := e.Orm.Model(&data). + Scopes( + actions.Permission(data.TableName(), p), + ).Delete(&data, d.GetId()) + if err := db.Error; err != nil { + e.Log.Errorf("Service RemoveSmsRenewalLog error:%s \r\n", err) + return err + } + if db.RowsAffected == 0 { + return errors.New("无权删除该数据") + } + return nil +} diff --git a/app/admin/service/sys_config.go b/app/admin/service/sys_config.go index 2323cbb..6f15662 100644 --- a/app/admin/service/sys_config.go +++ b/app/admin/service/sys_config.go @@ -76,13 +76,13 @@ func (e *SysConfig) Update(c *dto.SysConfigControl) error { } - // if c.ConfigKey == "proxy_dash_email" || c.ConfigKey == "proxy_dash_password" { - // e.Log.Info("更新了邮箱或密码,刷新token") - // proxyService := CliProxyService{Service: e.Service} - // if _, err := proxyService.resetToken(); err != nil { - // e.Log.Errorf("修改配置重置token失败:%s", err) - // } - // } + if c.ConfigKey == "proxy_dash_email" || c.ConfigKey == "proxy_dash_password" { + e.Log.Info("更新了邮箱或密码,刷新token") + proxyService := CliProxyService{Service: e.Service} + if _, err := proxyService.resetToken(); err != nil { + e.Log.Errorf("修改配置重置token失败:%s", err) + } + } return nil } diff --git a/app/jobs/examples.go b/app/jobs/examples.go index 324ffce..667dc64 100644 --- a/app/jobs/examples.go +++ b/app/jobs/examples.go @@ -13,10 +13,11 @@ func InitJob() { "ExamplesOne": ExamplesOne{}, "TrxPaymentJob": TrxPaymentJob{}, "CliProxyTrafficsJob": CliProxyJob{}, - "RenewalJob": RenewalJob{}, - "ExpireProxyJob": ExpireProxyJob{}, - "CleanExpiredOrderJob": CleanExpiredOrderJob{}, - "SmsJob": SmsJob{}, + "RenewalJob": RenewalJob{}, //长效ip定时续期 + "ExpireProxyJob": ExpireProxyJob{}, //定时过期代理 + "CleanExpiredOrderJob": CleanExpiredOrderJob{}, //清理过期订单 + "SmsJob": SmsJob{}, //短信定时查询验证码 + "SmsRenewalJob": SmsRenewalJob{}, //短信定时自动续期 // ... } } diff --git a/app/jobs/proxy_job.go b/app/jobs/proxy_job.go index 17f0cda..d2996eb 100644 --- a/app/jobs/proxy_job.go +++ b/app/jobs/proxy_job.go @@ -7,6 +7,7 @@ import ( ) type RenewalJob struct{} +type SmsRenewalJob struct{} type ExpireProxyJob struct{} // 定时续期任务 @@ -18,6 +19,15 @@ func (j RenewalJob) Exec(args interface{}) error { return memberRenewalService.AutoRenewal() } +// 定时短信续期任务 +func (j SmsRenewalJob) Exec(args interface{}) error { + smsService := service.SmsServices{} + smsService.Orm = GetDb() + smsService.Log = logger.NewHelper(logger.DefaultLogger) + + return smsService.AutoRenewal() +} + // 过期任务 func (j ExpireProxyJob) Exec(args interface{}) error { memberRenewalService := service.MemberRenewalLog{} diff --git a/app/jobs/proxy_job_test.go b/app/jobs/proxy_job_test.go new file mode 100644 index 0000000..f6532f7 --- /dev/null +++ b/app/jobs/proxy_job_test.go @@ -0,0 +1,19 @@ +package jobs + +import ( + "go-admin/config" + "testing" +) + +func TestProxyJob(t *testing.T) { + initSetting() + config.ExtConfig.CliproxyUrl = "https://f.cliproxy.com" + config.ExtConfig.CliproxyApiUrl = "https://api.cliproxy.com" + config.ExtConfig.DaisysmsUrl = "https://daisysms.com/stubs/handler_api.php" + + renewJob := RenewalJob{} + + if err := renewJob.Exec(nil); err != nil { + t.Error(err) + } +} diff --git a/app/jobs/sms_job_test.go b/app/jobs/sms_job_test.go index 4fabded..60a75e4 100644 --- a/app/jobs/sms_job_test.go +++ b/app/jobs/sms_job_test.go @@ -14,3 +14,14 @@ func TestSendSMS(t *testing.T) { t.Error(err) } } + +// 短信自动续期 +func TestSmsRenew(t *testing.T) { + initSetting() + config.ExtConfig.DaisysmsUrl = "https://daisysms.com/stubs/handler_api.php" + job := SmsRenewalJob{} + + if err := job.Exec(nil); err != nil { + t.Error(err) + } +} diff --git a/common/global/config_key.go b/common/global/config_key.go new file mode 100644 index 0000000..70ec768 --- /dev/null +++ b/common/global/config_key.go @@ -0,0 +1,8 @@ +package global + +//ConfigKey +const ( + 流量代理有效天数 = "traffic_proxy_effective_day" + 长效号码续费标准 = "long_number_renew_deduction_standard" + 长效IP续费kk扣除标准 = "ip_renew_deduction_standard" +) diff --git a/common/statuscode/status_code.go b/common/statuscode/status_code.go index 9a96195..a9d22ad 100644 --- a/common/statuscode/status_code.go +++ b/common/statuscode/status_code.go @@ -22,6 +22,7 @@ var StatusCodeZh = map[int]string{ SmsLongNumWaitCode: "短信验证码_长效号码已唤醒", SmsNotExisted: "号码不存在", SmsNotExpired: "号码未过期无法删除", + SmsNotAutoRenew: "短效号码无法自动续期", } var StatusCodeEn = map[int]string{ @@ -46,6 +47,7 @@ var StatusCodeEn = map[int]string{ SmsLongNumWaitCode: "sms code long num wake up", SmsNotExisted: "number not exist", SmsNotExpired: "number not expired, can not delete", + SmsNotAutoRenew: "num can not auto renew", } func GetMsg(code int, lang string) string { @@ -103,4 +105,6 @@ const ( SmsNotExisted = 20018 //号码未过期无法删除 SmsNotExpired = 20019 + //短效号码无法自动续期 + SmsNotAutoRenew = 20020 )