作者 yangfu

Merge remote-tracking branch 'origin/test'

... ... @@ -98,6 +98,7 @@ func GetRequestHeader(ctx *context.Context) *protocol.RequestHeader {
h.Sign = ctx.Input.Header("x-mmm-sign")
h.Uuid = ctx.Input.Header("x-mmm-uuid")
h.TimeStamp = ctx.Input.Header("x-mmm-timestamp")
h.Version = ctx.Input.Header("x-mmm-version")
h.Uid, _ = strconv.ParseInt(ctx.Input.Header("uid"), 10, 64) //需要uid写入到header里面
if h.Uid == 0 {
h.Uid, _ = strconv.ParseInt(ctx.Input.Header("x-mmm-uid"), 10, 64)
... ...
package v1
import (
"encoding/json"
"fmt"
"github.com/astaxie/beego"
"gitlab.fjmaimaimai.com/mmm-go/gocomm/pkg/log"
"opp/controllers"
"opp/internal/aliyun"
"opp/internal/utils"
"opp/protocol"
"opp/services/file"
"path/filepath"
"strings"
)
... ... @@ -37,3 +41,24 @@ func (this *FileController) DownLoad() {
}
msg = protocol.NewReturnResponse(rsp, err)
}
//GetPlayInfo 获取播放信息
// @router /getPlayInfo [post]
func (this *FileController) GetPlayInfo() {
var msg *protocol.ResponseMessage
defer func() {
this.Resp(msg)
}()
var request *aliyun.GetPlayInfoRequest
if err := json.Unmarshal(this.ByteBody, &request); err != nil {
log.Error(err)
msg = protocol.BadRequestParam(1)
return
}
if b, m := this.Valid(request); !b {
msg = m
return
}
header := controllers.GetRequestHeader(this.Ctx)
msg = protocol.NewReturnResponse(file.GetPlayInfo(header, request))
}
... ...
... ... @@ -2,8 +2,10 @@ package v1
import (
"bytes"
"encoding/json"
"fmt"
"opp/controllers"
"opp/internal/aliyun"
"opp/protocol"
"opp/services/upload"
... ... @@ -94,3 +96,24 @@ func (this *UploadController) Video() {
}
msg = protocol.NewReturnResponse(rsp, err)
}
//创建视频上传凭证 CreateUploadVideo
// @router /createUploadVideo [post]
func (this *UploadController) CreateUploadVideo() {
var msg *protocol.ResponseMessage
defer func() {
this.Resp(msg)
}()
var request *aliyun.CreateUploadVideoRequest
if err := json.Unmarshal(this.ByteBody, &request); err != nil {
log.Error(err)
msg = protocol.BadRequestParam(1)
return
}
if b, m := this.Valid(request); !b {
msg = m
return
}
header := controllers.GetRequestHeader(this.Ctx)
msg = protocol.NewReturnResponse(upload.CreateUploadVideo(header, request))
}
... ...
... ... @@ -3,6 +3,7 @@ module opp
go 1.12
require (
github.com/aliyun/alibaba-cloud-sdk-go v1.60.348
github.com/astaxie/beego v1.10.0
github.com/disintegration/imaging v1.6.2
github.com/go-sql-driver/mysql v1.4.1
... ...
package aliyun
const (
RegionID = "cn-shanghai"
AccessKeyID = "LTAI4FhiZ3UktC6N1u3H5GFC"
AccessKeySecret = "UyspWwdni55CYQ02hUCint4qY2jNYO"
)
const (
FileImage = "image"
FileVoice = "voice"
FileVideo = "video"
)
... ...
package aliyun
//创建视频上传凭证
/*CreateUploadVideo */
type CreateUploadVideoRequest struct {
}
type CreateUploadVideoResponse struct {
RequestId string `json:"requestId"`
VideoId string `json:"videoId"`
UploadAddress string `json:"uploadAddress"`
UploadAuth string `json:"uploadAuth"`
}
/*GetPlayInfo 获取播放信息*/
type GetPlayInfoRequest struct {
VideoId string `json:"videoId" xml:"VideoId"`
}
// GetPlayInfoResponse is the response struct for api GetPlayInfo
type GetPlayInfoResponse struct {
//*responses.BaseResponse
//RequestId string `json:"RequestId" xml:"RequestId"`
VideoBase VideoBase `json:"VideoBase" xml:"VideoBase"`
PlayInfoList PlayInfoListInGetPlayInfo `json:"PlayInfoList" xml:"PlayInfoList"`
}
// VideoBase is a nested struct in vod response
type VideoBase struct {
OutputType string `json:"OutputType" xml:"OutputType"`
CoverURL string `json:"CoverURL" xml:"CoverURL"`
Duration string `json:"Duration" xml:"Duration"`
Status string `json:"Status" xml:"Status"`
Title string `json:"Title" xml:"Title"`
VideoId string `json:"VideoId" xml:"VideoId"`
MediaType string `json:"MediaType" xml:"MediaType"`
CreationTime string `json:"CreationTime" xml:"CreationTime"`
TranscodeMode string `json:"TranscodeMode" xml:"TranscodeMode"`
//ThumbnailList ThumbnailListInGetPlayInfo `json:"ThumbnailList" xml:"ThumbnailList"`
}
type PlayInfoListInGetPlayInfo struct {
PlayInfo []PlayInfo `json:"PlayInfo" xml:"PlayInfo"`
}
// PlayInfo is a nested struct in vod response
type PlayInfo struct {
JobId string `json:"JobId" xml:"JobId"`
Format string `json:"Format" xml:"Format"`
PreprocessStatus string `json:"PreprocessStatus" xml:"PreprocessStatus"`
EncryptType string `json:"EncryptType" xml:"EncryptType"`
Fps string `json:"Fps" xml:"Fps"`
ModificationTime string `json:"ModificationTime" xml:"ModificationTime"`
NarrowBandType string `json:"NarrowBandType" xml:"NarrowBandType"`
Bitrate string `json:"Bitrate" xml:"Bitrate"`
Encrypt int64 `json:"Encrypt" xml:"Encrypt"`
Rand string `json:"Rand" xml:"Rand"`
CreationTime string `json:"CreationTime" xml:"CreationTime"`
StreamType string `json:"StreamType" xml:"StreamType"`
Height int64 `json:"Height" xml:"Height"`
WatermarkId string `json:"WatermarkId" xml:"WatermarkId"`
Duration string `json:"Duration" xml:"Duration"`
Complexity string `json:"Complexity" xml:"Complexity"`
Width int64 `json:"Width" xml:"Width"`
Size int64 `json:"Size" xml:"Size"`
Status string `json:"Status" xml:"Status"`
Definition string `json:"Definition" xml:"Definition"`
Plaintext string `json:"Plaintext" xml:"Plaintext"`
PlayURL string `json:"PlayURL" xml:"PlayURL"`
Specification string `json:"Specification" xml:"Specification"`
}
... ...
package aliyun
import (
"fmt"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials"
"github.com/aliyun/alibaba-cloud-sdk-go/services/vod"
"github.com/astaxie/beego"
"gitlab.fjmaimaimai.com/mmm-go/gocomm/common"
comm_time "gitlab.fjmaimaimai.com/mmm-go/gocomm/time"
"path"
"time"
)
//客户端
func DefaultVodClient() (client *vod.Client, err error) {
return InitVodClient(AccessKeyID, AccessKeySecret)
}
//初始化客户端
func InitVodClient(accessKeyId string, accessKeySecret string) (client *vod.Client, err error) {
// 点播服务接入区域
regionId := RegionID
// 创建授权对象
credential := &credentials.AccessKeyCredential{
accessKeyId,
accessKeySecret,
}
// 自定义config
config := sdk.NewConfig()
config.AutoRetry = true // 失败是否自动重试
config.MaxRetryTime = 3 // 最大重试次数
config.Timeout = 3000000000 // 连接超时,单位:纳秒;默认为3秒
// 创建vodClient实例
return vod.NewClientWithOptions(regionId, config, credential)
}
//获取视频上传地址和凭证,并创建视频信息
func CreateUploadVideo(client *vod.Client) (response *CreateUploadVideoResponse, err error) {
request := vod.CreateCreateUploadVideoRequest()
request.Title = getFileName(FileVideo, "video_file.mp4")
request.FileName = getFileName(FileVideo, "video_file.mp4")
//request.CoverURL = "http://img.alicdn.com/tps/TB1qnJ1PVXXXXXCXXXXXXXXXXXX-700-700.png"
//request.Tags = "tag1,tag2"
request.AcceptFormat = "JSON"
rsp, err := client.CreateUploadVideo(request)
if err != nil {
return
}
response = &CreateUploadVideoResponse{
RequestId: rsp.RequestId,
VideoId: rsp.VideoId,
UploadAddress: rsp.UploadAddress,
UploadAuth: rsp.UploadAuth,
}
return
}
//获取播放信息
func GetPlayInfo(client *vod.Client, videoId string) (response *vod.GetPlayInfoResponse, err error) {
request := vod.CreateGetPlayInfoRequest()
request.VideoId = videoId
request.AcceptFormat = "JSON"
return client.GetPlayInfo(request)
}
//fileType: video voice image
func getFileName(fileType string, filename string) string {
date := comm_time.GetTimeByYyyymmdd()
subfix := path.Ext(filename)
prefix := fmt.Sprintf("%v_%v", time.Now().Unix(), common.RandomString(32))
filename = fmt.Sprintf("%v%v", prefix, subfix)
sourcePath := fmt.Sprintf("%v/%v/%v/%v/%v", beego.BConfig.AppName, beego.BConfig.RunMode, fileType, date, filename)
return sourcePath
}
... ...
package utils
import (
"bytes"
"encoding/gob"
"encoding/json"
"errors"
"fmt"
"gitlab.fjmaimaimai.com/mmm-go/gocomm/pkg/log"
"reflect"
"strconv"
"strings"
)
... ... @@ -85,3 +88,36 @@ func JsonUnmarshal(jsonData string, v interface{}) {
log.Error("json.unmarshal error data:", jsonData, e)
}
}
//深度拷贝
func DeepCopy(dst, src interface{}) error {
var buf bytes.Buffer
if err := gob.NewEncoder(&buf).Encode(src); err != nil {
return err
}
return gob.NewDecoder(&buf).Decode(dst)
}
//检查版本信息
func ValidVersion(current, compare string) bool {
curVersions := strings.Split(current, ".")
comVersions := strings.Split(compare, ".")
for i := range curVersions {
//v1,v2:=strings.TrimSpace(curVersions[i]),""
v1, _ := strconv.ParseInt(strings.TrimSpace(curVersions[i]), 10, 64)
var v2 int64
if i < len(comVersions) {
v2, _ = strconv.ParseInt(strings.TrimSpace(comVersions[i]), 10, 64)
}
if v1 == 0 && v2 == 0 {
continue
}
if v1 >= v2 {
return true
}
if v1 < v2 {
return false
}
}
return false
}
... ...
package utils
import (
"fmt"
"testing"
)
func Test_DeepCopy(t *testing.T) {
type User1 struct {
Name string
Age int
Address string
}
type User2 struct {
Name string
Age int
Job string
}
var src = User1{Name: "foo", Age: 10, Address: "bar"}
var dst *User2
if err := DeepCopy(&dst, src); err != nil {
t.Fatal(err)
}
if src.Name != dst.Name {
t.Fatal("deep copy fail.")
}
//t.Log(src,"\n",dst)
}
func TestValidVersion(t *testing.T) {
inputs := []struct {
In string
Compare string
Out bool
}{
{In: "0.9.0", Compare: "0.8.0", Out: true},
{In: "0.8.11", Compare: "0.8.0", Out: true},
{In: "0.7.0", Compare: "0.8.0", Out: false},
{In: "0.8.0", Compare: "0.8.0", Out: true},
{In: "0.9", Compare: "0.8.0", Out: true},
{In: "0.10", Compare: "0.8.0", Out: true},
{In: "1.8.0", Compare: "0.8.0", Out: true},
{In: "0.99.0", Compare: "0.8.0", Out: true},
{In: "01.0.0", Compare: "0.8.0", Out: true},
}
for i := range inputs {
input := inputs[i]
if ValidVersion(input.In, input.Compare) != input.Out {
t.Fatal(fmt.Sprintf("valid version fail. input :%v compare:%v want:%v", input.In, input.Compare, input.Out))
}
}
}
... ...
... ... @@ -184,7 +184,7 @@ from audit_flow_process where uid=? and review_status in (%v) and enable_status
func GetChanceCollect(uid int64, lastId int64, pageSize int, v interface{}) (total int, err error) {
sql := fmt.Sprintf(`select a.*,b.images,b.speechs,b.videos from (
select a.*,b.user_id chance_user_id,b.create_at,b.source_content,b.enable_status,b.review_status,b.audit_template_id,b.chance_type_id,comment_total,zan_total,view_total,b.publish_status,b.status from (
select id collect_id,source_id,update_at,collect_time,chance_id from chance_favorite where (0=? or id<?) and user_id =? and enable_status=1
select id collect_id,source_id,update_at,collect_time,chance_id from chance_favorite where (0=? or unix_timestamp(collect_time)<?) and user_id =? and enable_status=1
and source_type=1
and (mark_flag&2)>0
)a left outer join chance b on a.source_id = b.id
... ... @@ -207,7 +207,7 @@ limit ?`)
func GetChanceThumbUp(uid int64, lastId int64, pageSize int, v interface{}) (total int, err error) {
sql := fmt.Sprintf(`select a.*,b.images,b.speechs,b.videos from (
select a.*,b.user_id chance_user_id,b.id chance_id,b.create_at,b.source_content,b.enable_status,b.review_status,b.audit_template_id,b.chance_type_id,comment_total,zan_total,view_total,b.publish_status,b.status from (
select id collect_id,source_id,update_at,zan_time from chance_favorite where (0=? or id<?) and user_id =? and enable_status=1
select id collect_id,source_id,update_at,zan_time from chance_favorite where (0=? or unix_timestamp(zan_time)<?) and user_id =? and enable_status=1
and source_type=1
and (mark_flag&1)>0
)a left outer join chance b on a.source_id = b.id
... ...
... ... @@ -16,6 +16,7 @@ const (
)
const TokenExpire = 3600
const RefreshTokenExipre = 3600 * 24 * 30 * 3 //刷新token 三个月过期
const SmscodeDayLimitTime = 10 //短信验证码每天最多发10次
... ... @@ -23,6 +24,7 @@ var Nums = []byte("0123456789")
type RequestHeader struct {
TimeStamp string
Version string
Uuid string
Sign string
DeviceType int
... ...
package protocol
const RequireVersion = "0.9.0"
/*
全局变量声明
*/
... ...
... ... @@ -77,7 +77,7 @@ const (
var (
MessageApproving = "提交了一条%v机会消息,需要您审核"
MessageApproveSuccess = "审核通过你提交的%v机会"
MessageApproveReject = "退回您了提交的%v机会"
MessageApproveReject = "退回了您提交的%v机会"
MessageZanChance = "点赞了您发布的机会"
MessageZanComment = "点赞了您发布的评论"
... ...
... ... @@ -5,7 +5,7 @@ import "mime/multipart"
const (
FileImage = "image"
FileVoice = "voice"
FileVideo ="video"
FileVideo = "video"
)
/*Image */
... ...
... ... @@ -289,6 +289,14 @@ func init() {
beego.GlobalControllerRouter["opp/controllers/v1:FileController"] = append(beego.GlobalControllerRouter["opp/controllers/v1:FileController"],
beego.ControllerComments{
Method: "GetPlayInfo",
Router: `/getPlayInfo`,
AllowHTTPMethods: []string{"post"},
MethodParams: param.Make(),
Params: nil})
beego.GlobalControllerRouter["opp/controllers/v1:FileController"] = append(beego.GlobalControllerRouter["opp/controllers/v1:FileController"],
beego.ControllerComments{
Method: "DownLoad",
Router: `/opp/file`,
AllowHTTPMethods: []string{"post"},
... ... @@ -393,6 +401,14 @@ func init() {
beego.GlobalControllerRouter["opp/controllers/v1:UploadController"] = append(beego.GlobalControllerRouter["opp/controllers/v1:UploadController"],
beego.ControllerComments{
Method: "CreateUploadVideo",
Router: `/createUploadVideo`,
AllowHTTPMethods: []string{"post"},
MethodParams: param.Make(),
Params: nil})
beego.GlobalControllerRouter["opp/controllers/v1:UploadController"] = append(beego.GlobalControllerRouter["opp/controllers/v1:UploadController"],
beego.ControllerComments{
Method: "Image",
Router: `/image`,
AllowHTTPMethods: []string{"post"},
... ...
... ... @@ -23,6 +23,7 @@ func init() {
beego.NSNamespace("message", beego.NSBefore(controllers.FilterComm), beego.NSInclude(&v1.MessageController{})),
beego.NSNamespace("department", beego.NSBefore(controllers.FilterComm), beego.NSInclude(&v1.DepartmentController{})),
beego.NSNamespace("config", beego.NSBefore(controllers.FilterComm), beego.NSInclude(&v1.ConfigController{})),
beego.NSNamespace("file", beego.NSBefore(controllers.FilterComm), beego.NSInclude(&v1.FileController{})),
)
beego.AddNamespace(nsV1)
... ...
... ... @@ -15,7 +15,7 @@ import (
var (
MessageApproving = "提交了一条%v机会消息,需要您审核"
MessageApproveSuccess = "审核通过你提交的%v机会"
MessageApproveReject = "退回您了提交的%v机会"
MessageApproveReject = "退回了您提交的%v机会"
MessageApproveAutoPass = "自动审核通过你提交的%v机会"
)
... ...
... ... @@ -51,6 +51,11 @@ func Login(header *protocol.RequestHeader, request *protocol.LoginRequest) (rsp
err = protocol.NewErrWithMessage(2002, err) //账号不存在
return
}
if !utils.ValidVersion(header.Version, protocol.RequireVersion) {
log.Warn(fmt.Sprintf("版本不足 当前手机版本:%v 需要版本大于:%v", header.Version, protocol.RequireVersion))
err = protocol.NewCustomMessage(2002, "版本不足,请升级app") //账号不存在
return
}
//获取最后一次公司编号给统一用户中心
if u, e := models.GetUserAuthByUserId(user.Id, protocol.DeviceType); e == nil && user.UserCenterId == id {
if company, e = models.GetCompanyById(u.CurrentCompanyId); e == nil {
... ... @@ -215,7 +220,7 @@ func AccessToken(request *protocol.AccessTokenRequest) (rsp *protocol.AccessToke
userAuth.AccessToken = uid.NewV1().StringNoDash()
userAuth.RefreshToken = uid.NewV1().StringNoDash()
userAuth.AccessTokenExp = time.Now().Add(protocol.TokenExpire * time.Second)
userAuth.RefreshTokenExp = time.Now().Add(protocol.TokenExpire * time.Second * 2)
userAuth.RefreshTokenExp = time.Now().Add(protocol.RefreshTokenExipre * time.Second)
if err = models.UpdateUserAuthById(userAuth); err != nil {
log.Error(err)
return
... ... @@ -248,7 +253,7 @@ func RefreshToken(request *protocol.RefreshTokenRequest) (rsp *protocol.RefreshT
userAuth.AccessToken = uid.NewV1().StringNoDash()
userAuth.RefreshToken = uid.NewV1().StringNoDash()
userAuth.AccessTokenExp = time.Now().Add(protocol.TokenExpire * time.Second)
userAuth.RefreshTokenExp = time.Now().Add(protocol.TokenExpire * time.Second * 2)
userAuth.RefreshTokenExp = time.Now().Add(protocol.RefreshTokenExipre * time.Second)
if err = models.UpdateUserAuthById(userAuth); err != nil {
return
}
... ...
... ... @@ -1541,7 +1541,15 @@ func MyCollectChance(header *protocol.RequestHeader, request *protocol.MyCollect
myChances []protocol.ChanceCollectItemOrm
total int
provider *protocol.BaseUserInfo
favorite *models.ChanceFavorite
)
if request.LastId > 0 {
if favorite, err = models.GetChanceFavoriteById(request.LastId); err != nil {
log.Error("不存在", request.LastId, err)
return
}
request.LastId = favorite.CollectTime.Unix()
}
if total, err = models.GetChanceCollect(header.UserId, request.LastId, request.PageSize, &myChances); err != nil {
if err == orm.ErrNoRows {
err = nil
... ... @@ -1624,7 +1632,15 @@ func MyThumbUpChance(header *protocol.RequestHeader, request *protocol.MyThumbUp
myChances []protocol.ChanceThumbUpItemOrm
total int
provider *protocol.BaseUserInfo
favorite *models.ChanceFavorite
)
if request.LastId > 0 {
if favorite, err = models.GetChanceFavoriteById(request.LastId); err != nil {
log.Error("不存在", request.LastId, err)
return
}
request.LastId = favorite.ZanTime.Unix()
}
if total, err = models.GetChanceThumbUp(header.UserId, request.LastId, request.PageSize, &myChances); err != nil {
if err == orm.ErrNoRows {
err = nil
... ...
package file
import (
"github.com/prometheus/common/log"
"opp/internal/aliyun"
"opp/internal/utils"
"opp/protocol"
)
//GetPlayInfo 获取播放信息
func GetPlayInfo(header *protocol.RequestHeader, request *aliyun.GetPlayInfoRequest) (rsp *aliyun.GetPlayInfoResponse, err error) {
var ()
client, e := aliyun.DefaultVodClient()
if e != nil {
log.Error(e)
err = e
return
}
response, e := aliyun.GetPlayInfo(client, request.VideoId)
if e != nil {
log.Error(e)
err = e
return
}
rsp = &aliyun.GetPlayInfoResponse{}
if err = utils.DeepCopy(&rsp, response); err != nil {
log.Error(err)
return
}
return
}
... ...
... ... @@ -5,6 +5,7 @@ import (
"github.com/disintegration/imaging"
"io"
"mime/multipart"
"opp/internal/aliyun"
"os"
"path"
"path/filepath"
... ... @@ -133,3 +134,16 @@ func GetSortFileKeys(files map[string][]*multipart.FileHeader) (keys []string) {
sort.Strings(keys)
return
}
//创建视频上传凭证
func CreateUploadVideo(header *protocol.RequestHeader, request *aliyun.CreateUploadVideoRequest) (rsp *aliyun.CreateUploadVideoResponse, err error) {
var ()
client, e := aliyun.DefaultVodClient()
if e != nil {
log.Error(e)
err = e
return
}
rsp, err = aliyun.CreateUploadVideo(client)
return
}
... ...