init
This commit is contained in:
235
service/vas/purchase.go
Normal file
235
service/vas/purchase.go
Normal file
@ -0,0 +1,235 @@
|
||||
package vas
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
model "github.com/cloudreve/Cloudreve/v3/models"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/payment"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/serializer"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// CreateOrderService 创建订单服务
|
||||
type CreateOrderService struct {
|
||||
Action string `json:"action" binding:"required,eq=group|eq=pack|eq=score"`
|
||||
Method string `json:"method" binding:"required,eq=alipay|eq=score|eq=payjs|eq=wechat|eq=custom"`
|
||||
ID int64 `json:"id" binding:"required"`
|
||||
Num int `json:"num" binding:"required,min=1"`
|
||||
}
|
||||
|
||||
// RedeemService 兑换服务
|
||||
type RedeemService struct {
|
||||
Code string `uri:"code" binding:"required,max=64"`
|
||||
}
|
||||
|
||||
// OrderService 订单查询
|
||||
type OrderService struct {
|
||||
ID string `uri:"id" binding:"required"`
|
||||
}
|
||||
|
||||
// Status 查询订单状态
|
||||
func (service *OrderService) Status(c *gin.Context, user *model.User) serializer.Response {
|
||||
order, _ := model.GetOrderByNo(service.ID)
|
||||
if order == nil || order.UserID != user.ID {
|
||||
return serializer.Err(serializer.CodeNotFound, "", nil)
|
||||
}
|
||||
|
||||
return serializer.Response{Data: order.Status}
|
||||
}
|
||||
|
||||
// Redeem 开始兑换
|
||||
func (service *RedeemService) Redeem(c *gin.Context, user *model.User) serializer.Response {
|
||||
redeem, err := model.GetAvailableRedeem(service.Code)
|
||||
if err != nil {
|
||||
return serializer.Err(serializer.CodeInvalidGiftCode, "", err)
|
||||
}
|
||||
|
||||
// 取得当前商品信息
|
||||
packs, groups, err := decodeProductInfo()
|
||||
if err != nil {
|
||||
return serializer.Err(serializer.CodeInternalSetting, "Failed to parse product settings", err)
|
||||
}
|
||||
|
||||
// 查找要购买的商品
|
||||
var (
|
||||
pack *serializer.PackProduct
|
||||
group *serializer.GroupProducts
|
||||
)
|
||||
if redeem.Type == model.GroupOrderType {
|
||||
for _, v := range groups {
|
||||
if v.ID == redeem.ProductID {
|
||||
group = &v
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if group == nil {
|
||||
return serializer.Err(serializer.CodeNotFound, "", err)
|
||||
}
|
||||
|
||||
} else if redeem.Type == model.PackOrderType {
|
||||
for _, v := range packs {
|
||||
if v.ID == redeem.ProductID {
|
||||
pack = &v
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if pack == nil {
|
||||
return serializer.Err(serializer.CodeNotFound, "", err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
err = payment.GiveProduct(user, pack, group, redeem.Num)
|
||||
if err != nil {
|
||||
return serializer.Err(serializer.CodeNotSet, "Redeem failed", err)
|
||||
}
|
||||
|
||||
redeem.Use()
|
||||
|
||||
return serializer.Response{}
|
||||
|
||||
}
|
||||
|
||||
// Query 检查兑换码信息
|
||||
func (service *RedeemService) Query(c *gin.Context) serializer.Response {
|
||||
redeem, err := model.GetAvailableRedeem(service.Code)
|
||||
if err != nil {
|
||||
return serializer.Err(serializer.CodeInvalidGiftCode, "", err)
|
||||
}
|
||||
|
||||
var (
|
||||
name = "积分"
|
||||
productTime int64
|
||||
)
|
||||
if redeem.Type != model.ScoreOrderType {
|
||||
packs, groups, err := decodeProductInfo()
|
||||
if err != nil {
|
||||
return serializer.Err(serializer.CodeInternalSetting, "Failed to parse product settings", err)
|
||||
}
|
||||
if redeem.Type == model.GroupOrderType {
|
||||
for _, v := range groups {
|
||||
if v.ID == redeem.ProductID {
|
||||
name = v.Name
|
||||
productTime = v.Time
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for _, v := range packs {
|
||||
if v.ID == redeem.ProductID {
|
||||
name = v.Name
|
||||
productTime = v.Time
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if name == "积分" {
|
||||
return serializer.Err(serializer.CodeNotFound, "", err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return serializer.Response{
|
||||
Data: struct {
|
||||
Name string `json:"name"`
|
||||
Type int `json:"type"`
|
||||
Num int `json:"num"`
|
||||
Time int64 `json:"time"`
|
||||
}{
|
||||
name, redeem.Type, redeem.Num, productTime,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Create 创建新订单
|
||||
func (service *CreateOrderService) Create(c *gin.Context, user *model.User) serializer.Response {
|
||||
// 取得当前商品信息
|
||||
packs, groups, err := decodeProductInfo()
|
||||
if err != nil {
|
||||
return serializer.Err(serializer.CodeInternalSetting, "Failed to parse product list", err)
|
||||
}
|
||||
|
||||
// 查找要购买的商品
|
||||
var (
|
||||
pack *serializer.PackProduct
|
||||
group *serializer.GroupProducts
|
||||
)
|
||||
if service.Action == "group" {
|
||||
for _, v := range groups {
|
||||
if v.ID == service.ID {
|
||||
group = &v
|
||||
break
|
||||
}
|
||||
}
|
||||
} else if service.Action == "pack" {
|
||||
for _, v := range packs {
|
||||
if v.ID == service.ID {
|
||||
pack = &v
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 购买积分
|
||||
if pack == nil && group == nil {
|
||||
if service.Method == "score" {
|
||||
return serializer.ParamErr("Payment method not supported", nil)
|
||||
}
|
||||
}
|
||||
|
||||
// 创建订单
|
||||
res, err := payment.NewOrder(pack, group, service.Num, service.Method, user)
|
||||
if err != nil {
|
||||
return serializer.Err(serializer.CodeNotSet, err.Error(), err)
|
||||
}
|
||||
|
||||
return serializer.Response{Data: res}
|
||||
|
||||
}
|
||||
|
||||
// Products 获取商品信息
|
||||
func (service *GeneralVASService) Products(c *gin.Context, user *model.User) serializer.Response {
|
||||
options := model.GetSettingByNames(
|
||||
"wechat_enabled",
|
||||
"alipay_enabled",
|
||||
"payjs_enabled",
|
||||
"payjs_enabled",
|
||||
"custom_payment_enabled",
|
||||
"custom_payment_name",
|
||||
)
|
||||
scorePrice := model.GetIntSetting("score_price", 0)
|
||||
packs, groups, err := decodeProductInfo()
|
||||
if err != nil {
|
||||
return serializer.Err(serializer.CodeInternalSetting, "Failed to parse product list", err)
|
||||
}
|
||||
|
||||
return serializer.BuildProductResponse(
|
||||
groups,
|
||||
packs,
|
||||
model.IsTrueVal(options["wechat_enabled"]),
|
||||
model.IsTrueVal(options["alipay_enabled"]),
|
||||
model.IsTrueVal(options["payjs_enabled"]),
|
||||
model.IsTrueVal(options["custom_payment_enabled"]),
|
||||
options["custom_payment_name"],
|
||||
scorePrice,
|
||||
)
|
||||
}
|
||||
|
||||
func decodeProductInfo() ([]serializer.PackProduct, []serializer.GroupProducts, error) {
|
||||
options := model.GetSettingByNames("pack_data", "group_sell_data", "alipay_enabled", "payjs_enabled")
|
||||
|
||||
var (
|
||||
packs []serializer.PackProduct
|
||||
groups []serializer.GroupProducts
|
||||
)
|
||||
if err := json.Unmarshal([]byte(options["pack_data"]), &packs); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if err := json.Unmarshal([]byte(options["group_sell_data"]), &groups); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return packs, groups, nil
|
||||
}
|
113
service/vas/qq.go
Normal file
113
service/vas/qq.go
Normal file
@ -0,0 +1,113 @@
|
||||
package vas
|
||||
|
||||
import (
|
||||
model "github.com/cloudreve/Cloudreve/v3/models"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/qq"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/request"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/serializer"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/thumb"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/util"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// QQCallbackService QQ互联回调处理服务
|
||||
type QQCallbackService struct {
|
||||
Code string `json:"code" binding:"required"`
|
||||
State string `json:"state" binding:"required"`
|
||||
}
|
||||
|
||||
// Callback 处理QQ互联回调
|
||||
func (service *QQCallbackService) Callback(c *gin.Context, user *model.User) serializer.Response {
|
||||
|
||||
state := util.GetSession(c, "qq_login_secret")
|
||||
if stateStr, ok := state.(string); !ok || stateStr != service.State {
|
||||
return serializer.Err(serializer.CodeSignExpired, "", nil)
|
||||
}
|
||||
util.DeleteSession(c, "qq_login_secret")
|
||||
|
||||
// 获取OpenID
|
||||
credential, err := qq.Callback(service.Code)
|
||||
if err != nil {
|
||||
return serializer.Err(serializer.CodeInternalSetting, "Failed to get session status", err)
|
||||
}
|
||||
|
||||
// 如果已登录,则绑定已有用户
|
||||
if user != nil {
|
||||
|
||||
if user.OpenID != "" {
|
||||
return serializer.Err(serializer.CodeQQBindConflict, "", nil)
|
||||
}
|
||||
|
||||
// OpenID 是否重复
|
||||
if _, err := model.GetActiveUserByOpenID(credential.OpenID); err == nil {
|
||||
return serializer.Err(serializer.CodeQQBindOtherAccount, "", nil)
|
||||
}
|
||||
|
||||
if err := user.Update(map[string]interface{}{"open_id": credential.OpenID}); err != nil {
|
||||
return serializer.DBErr("Failed to update user open id", err)
|
||||
}
|
||||
return serializer.Response{
|
||||
Data: "/setting",
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 未登录,尝试查找用户
|
||||
if expectedUser, err := model.GetActiveUserByOpenID(credential.OpenID); err == nil {
|
||||
// 用户绑定了此QQ,设定为登录状态
|
||||
util.SetSession(c, map[string]interface{}{
|
||||
"user_id": expectedUser.ID,
|
||||
})
|
||||
res := serializer.BuildUserResponse(expectedUser)
|
||||
res.Code = 203
|
||||
return res
|
||||
|
||||
}
|
||||
|
||||
// 无匹配用户,创建新用户
|
||||
if !model.IsTrueVal(model.GetSettingByName("qq_direct_login")) {
|
||||
return serializer.Err(serializer.CodeQQNotLinked, "", nil)
|
||||
}
|
||||
|
||||
// 获取用户信息
|
||||
userInfo, err := qq.GetUserInfo(credential)
|
||||
if err != nil {
|
||||
return serializer.Err(serializer.CodeInternalSetting, "Failed to fetch user info", err)
|
||||
}
|
||||
|
||||
// 生成邮箱地址
|
||||
fakeEmail := util.RandStringRunes(16) + "@login.qq.com"
|
||||
|
||||
// 创建用户
|
||||
defaultGroup := model.GetIntSetting("default_group", 2)
|
||||
|
||||
newUser := model.NewUser()
|
||||
newUser.Email = fakeEmail
|
||||
newUser.Nick = userInfo.Nick
|
||||
newUser.SetPassword("")
|
||||
newUser.Status = model.Active
|
||||
newUser.GroupID = uint(defaultGroup)
|
||||
newUser.OpenID = credential.OpenID
|
||||
newUser.Avatar = "file"
|
||||
|
||||
// 创建用户
|
||||
if err := model.DB.Create(&newUser).Error; err != nil {
|
||||
return serializer.Err(serializer.CodeEmailExisted, "", err)
|
||||
}
|
||||
|
||||
// 下载头像
|
||||
r := request.NewClient()
|
||||
rawAvatar := r.Request("GET", userInfo.Avatar, nil)
|
||||
if avatar, err := thumb.NewThumbFromFile(rawAvatar.Response.Body, "avatar.jpg"); err == nil {
|
||||
avatar.CreateAvatar(newUser.ID)
|
||||
}
|
||||
|
||||
// 登录
|
||||
util.SetSession(c, map[string]interface{}{"user_id": newUser.ID})
|
||||
|
||||
newUser, _ = model.GetActiveUserByID(newUser.ID)
|
||||
|
||||
res := serializer.BuildUserResponse(newUser)
|
||||
res.Code = 203
|
||||
return res
|
||||
}
|
17
service/vas/quota.go
Normal file
17
service/vas/quota.go
Normal file
@ -0,0 +1,17 @@
|
||||
package vas
|
||||
|
||||
import (
|
||||
model "github.com/cloudreve/Cloudreve/v3/models"
|
||||
"github.com/cloudreve/Cloudreve/v3/pkg/serializer"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// GeneralVASService 通用增值服务
|
||||
type GeneralVASService struct {
|
||||
}
|
||||
|
||||
// Quota 获取容量配额信息
|
||||
func (service *GeneralVASService) Quota(c *gin.Context, user *model.User) serializer.Response {
|
||||
packs := user.GetAvailableStoragePacks()
|
||||
return serializer.BuildUserQuotaResponse(user, packs)
|
||||
}
|
Reference in New Issue
Block a user