Create & Init Project...

This commit is contained in:
2019-04-22 18:49:16 +08:00
commit fc4fa37393
25440 changed files with 4054998 additions and 0 deletions

View File

@@ -0,0 +1,36 @@
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//app/interface/main/videoup/cmd:all-srcs",
"//app/interface/main/videoup/conf:all-srcs",
"//app/interface/main/videoup/dao/account:all-srcs",
"//app/interface/main/videoup/dao/archive:all-srcs",
"//app/interface/main/videoup/dao/bfs:all-srcs",
"//app/interface/main/videoup/dao/creative:all-srcs",
"//app/interface/main/videoup/dao/dynamic:all-srcs",
"//app/interface/main/videoup/dao/elec:all-srcs",
"//app/interface/main/videoup/dao/filter:all-srcs",
"//app/interface/main/videoup/dao/geetest:all-srcs",
"//app/interface/main/videoup/dao/mission:all-srcs",
"//app/interface/main/videoup/dao/order:all-srcs",
"//app/interface/main/videoup/dao/pay:all-srcs",
"//app/interface/main/videoup/dao/subtitle:all-srcs",
"//app/interface/main/videoup/dao/tag:all-srcs",
"//app/interface/main/videoup/http:all-srcs",
"//app/interface/main/videoup/model/archive:all-srcs",
"//app/interface/main/videoup/model/geetest:all-srcs",
"//app/interface/main/videoup/model/mission:all-srcs",
"//app/interface/main/videoup/model/porder:all-srcs",
"//app/interface/main/videoup/service:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,606 @@
#### 投稿API
##### Version 2.4.1
>1.重构特殊用户组查询接口,使用grpc并且进行批量查询
##### Version 2.4.0
>1.重构商单
##### Version 2.3.13
>1.修复联合投稿中有封禁用户的提示语错误的bug
##### Version 2.3.12
>1.标题增加newline过滤
##### Version 2.3.11
>1.添加联合投稿功能在稿件web编辑和web新增接口中加了联合投稿验证
##### Version 2.3.10
>1.升级账号API为grpc服务,简化配置
##### Version 2.3.9
>1.Web端:支持高频投稿的用户组
##### Version 2.3.8
>1.兼容支持投稿客户端ipad, app.upfrom添加UpFromIpad(11),仅限ios
>2.完善,MaxAllVsCnt的日志格式,方便查询问题
##### Version 2.3.7
>1.fix init service
##### Version 2.3.6
>1.fix infoc的service new和close
>2.支持app的投票动态带入object replacement character
##### Version 2.3.5
>1.添加支持投票app支持传递vote_id和vote_title
>2.支持pic_count和video_count上报到infocproc
##### Version 2.3.4
>1.升级并精简化自定义错误码
##### Version 2.3.3
>1.修复和基础库错误码不兼容的问题
##### Version 2.3.2
>1.为防止客户端(pc windows端除外)添加和编辑的时候触发敏感词而且用户侧已经无法修改老稿件的分P简介决定禁止添加和修改分P的简介
##### Version 2.3.1 for APP535
>1.素材上报支持 拍摄稿件合拍+编辑器主题使用
>2.APP端投稿的时候允许上报POI地理位置信息
>3.删除数据上报的部分
>4.精简日志打印
- 编辑器切割字段split
- 编辑器裁剪字段cut
- 编辑器旋转字段rotate
- 拍摄闪光灯字段flashlight
- 拍摄倒计时字段countdown
- 拍摄美颜字段beauty
##### Version 2.3.0
>1.UGC投稿内容付费
1. 统一校验-是否同意协议
2. 统一校验-创作类型+定价区间+用户灰度资格
3. 统一校验-私单+商单+UGC付费是否冲突
4. 添加稿件step1注册内容付费接口调用
5. 添加稿件step2同意当前协议ES日志添加
6. 编辑时候:如果已经付费的稿件,未开放之前都是可以编辑的
7. 编辑时候如果已经付费的稿件开放之后要删除必须在60天之后
8. 编辑时候为了兼容其他端付费稿件如果未提交付费信息就按照原信息覆盖ap.UgcPay
9. 编辑时候:如果开启调价就无脑调用
### Version 2.2.21
>1.和服务端下发相关的素材类型兼容app上报数据集合或者单个数据, string/int
##### Version 2.2.20
>1.兼容editor.bgms为interface允许上报int和string
##### Version 2.2.19
>1.由于客户端5.34上报格式问题, 暂时取消bgms上报
##### Version 2.2.18
>1.封面支持第一个第三方cdn存储:acgvideo.com
##### Version 2.2.17
>1.封面支持第一个第三方cdn存储:clouddn.com
##### Version 2.2.16
>1.update ut for dao
##### Version 2.2.15
>1.fixbug 解决bm bindWith 两次读取body为EOF bug
##### Version 2.2.14
>1.fixbug 解决投稿行为日志缺少关键数据bug
##### Version 2.2.13
>1.投稿行为日志记录原始提交数据
##### Version 2.2.12
>1.APP支持投稿完成之后推荐关注创作中心官方号的MID
##### Version 2.2.11
>1.稿件字幕提交全量开放
##### Version 2.2.10
>1.es最多存32k,投稿日志就最多记100p吧
##### Version 2.2.9
>1.支持拍摄开关的数据上报
##### Version 2.2.8
>1.增加编辑操作时候的总分P数目的限制落在配置文件中自定义返回提示信息
##### Version 2.2.7
>1.去掉不必须要的access_key和cookie的传递
##### Version 2.2.6
>1.修复添加稿件商单检验问题
##### Version 2.2.5
>1.添加字幕提交的业务
##### Version 2.2.4
>1.编辑器使用信息上报支持2d的投稿贴纸信息, videoup_stickers
>2.打Warn日志报告有人在稿件标题中进行了xss攻击
##### Version 2.2.3
>1.标题增加xss过滤
##### Version 2.2.2
>1.app端添加稿件的时候支持绑定抽奖活动
>2.service的context使用TODO防止cancel
##### Version 2.2.1
>1.暂时去掉简介格式化的校验信息,remove checkDescForMap
##### Version 2.2.0 (for app 5.31)
>1.稿件提交增加新视频的素材绑定
>2.添加新增稿件的业务来源说明
##### Version 2.1.37
>1.添加不可见字符的unicode正则集合U+202E(right-to-left override)
##### Version 2.1.36
>1.按照分区校验活动可用性只做videoall的校验
##### Version 2.1.35
>1.投稿日志记录build和buvid
##### Version 2.1.34
>1.添加和提交的时候所有的分P必须去重直接提示错误信息
##### Version 2.1.33
>1.升级ip获取的方式使用metadata.RemoteIP
##### Version 2.1.32
>1.feature: update acts for videoall
##### Version 2.1.31
>1.feature: 升级bm组件初始化升级authService和verifyService
##### Version 2.1.30
>1.feature: 添加和编辑稿件的时候全平台的如果mission_id大于零且有效则交叉对比创作类型转载的稿件禁止参加活动
##### Version 2.1.29
>1.fixVideoErrorsFrom
##### Version 2.1.28
>1.添加投稿日志
##### Version 2.1.27
>1.去掉48小时filename的校验
##### Version 2.1.26
>1.fix bug:tag service:5xx超时错误未捕获并且做了数据判断
##### Version 2.1.25
>1.tag同步绑定一级、二级分区名
##### Version 2.1.24
>1.投稿时候的充电开关展示的逻辑交各客户端自己把握,APP端暂时默认开启等后续APP升级再做自主选择
>2.Windows客户端的tag添加校验逻辑直接报错提示予以修改
##### Version 2.1.23
>1.fix bug:自定义错误兼容ecode的interface Detail
##### Version 2.1.22
>1.添加web端30秒投稿过快的警告提示
>2.允许sid在投稿的时候提交上来
##### Version 2.1.21
>1.Edit:完结动画32连载动画33不允许编辑自制原创类型的稿件
##### Version 2.1.20
>1.Add:完结动画32连载动画33不允许添加自制原创类型的稿件
##### Version 2.1.19
>1.去掉新投稿和编辑稿件的tag同步逻辑
##### Version 2.1.18
>1.去掉APP封面的限制
##### Version 2.1.17
>1.为APP投稿缺少封面信息增加日志提示方便定位具体问题
##### Version 2.1.16
>1.APP添加稿件的第一个tag当做校验的tag并获取对应的活动id当做参加的活动ID
##### Version 2.1.15
>1.UGC投稿入口禁止出现ASMR分区,提示:该分区不存在
##### Version 2.1.14
>1.兼容app不允许活动数据负数存入db
>2.商业产品的投稿接口重构,异步化第三方业务
##### Version 2.1.13
>1.提供UGC商单新增稿件的接口新增加upfrom:UpFromCM(10),另外强制校验分区必须为广告分区(166)
>2.顺便去掉支持代码模式的代码
##### Version 2.1.12
>1.为清理配置做准备
##### Version 2.1.11
>1.缓存用户投稿偏好数据之分区信息集合
##### Version 2.1.10
>1.全端兼容允许稿件描述为空
##### Version 2.1.9
>1.patch:前端native对mission_id没做有效性验证会提交-1暂时服务端兼容小于等于0的都当做活动不参与
##### Version 2.1.8
>1.fix: 检测并过滤掉前端提交的分P信息为null保护后端业务的正确性
##### Version 2.1.7
>1.兼容修改稿件的时候只选择了tag活动去除后面的逗号
##### Version 2.1.6
>1.兼容活动服务不可用的情况
##### Version 2.1.5
>1.patch:对活动mission_id和分区做强校验不允许活动跨分区投稿和编辑
##### Version 2.1.4
>1.fix: 只选择活动tag也参加了活动当活动tag被过滤完之后应该做是否参加活动的判断也就是说允许只选择活动tag后面会对活动tag和活动id不匹配做校验
##### Version 2.1.3
>1.缓存中的活动tag过滤数据使用split之后的单个tag或者活动的名字作为key
>2.单个tag的长度限制和tag服务的一致30个字符
##### Version 2.1.2
>1.patch:缓存中的活动tag过滤数据都用split之后的单个tag作为key
##### Version 2.1.1
>1.非投稿第三方服务请求异步调用
>2.去掉代码模式的判断web前端已经没有代码模式投稿的入口
##### Version 2.1.0
>1.添加和编辑稿件的时候支持dynamic字段的添加和修改并且要去除app对这两个字段protect的保护操作
>2.添加稿件和编辑稿件支持参加或者修改活动
>3.支持watermark水印数据的添加和展现,APP端添加的时候可以修改
##### Version 2.0.6
>1.fix Bug:未参加活动的情况下不允许添加活动的tag自定义标签包含不可选的活动tag请修改后重新提交
##### Version 2.0.5
>1.Dynamic完善日志输出
>2.注释去掉WebFilterServer
##### Version 2.0.4
>1.过滤服务添加操作记录日志,自定义错误之后moni是捕获不到日志的,需要自己手动加日志记录
##### Version 2.0.3
>1.web投稿对接敏感词过滤服务新增独立字符串验证的过滤并且在创建或者编辑稿件的时候对[转载来源、标题、简介、稿件推荐语]四个字段进行批量校验
##### Version 2.0.2
>1.为避免审核后台改动稿件分区导致格式化简介错乱在稿件编辑的时候直接去掉校验数据的存在与否checkDescForMap
##### Version 2.0.1
>1.APP修改暂时不允许修改四个字段:dynamic,porder,order,mission,desc_format_id等待接入
##### Version 2.0.0
>1.UpSpecial请求迁移到up-service
>2.迁移到master目录
##### Version 1.9.9
>1.分P细节校验和提交失败的日志内容再次添加上
##### Version 1.9.8
>1.使用account-service v7
##### Version 1.9.7
>1.禁止转载只有在0,8,9三种upfrom值情况下才允许修改
##### Version 1.9.6
>1.分P错误码的接口有人在master加了补锅equal interface补锅
##### Version 1.9.5
>1.修改文案, "暂无"=>"-"
##### Version 1.9.4
>1.原始的描述信息在APP端在开启格式化简介的情况下是允许为空的在checkDescFormat的时候取消不应该的下限校验
##### Version 1.9.3
>1.fix bug, errcode(21052):转载类型的投稿,转载来源添加到描述信息之后再校验会不定概率的出现超出规定限制的长度
##### Version 1.9.2
>1.fix bug主app允许在编辑的时候描述信息为空提交
##### Version 1.9.1
>1.fix bug转载的稿件在投稿的时候描述不可能是空的自制的会参与判断
##### Version 1.9.0
>1.支持主APP投稿
##### Version 1.8.8
>1.去掉对statsd的依赖
##### Version 1.8.7
>1.移除对数据库的依赖upSpecial信息从videoup-service获取
##### Version 1.8.6
>1.修复tagBind的不完整绑定需要事先判断是否有修改才决定请求tagAPI防止多次编辑产生的无效请求
##### Version 1.8.5
>1.update baldemaster for identify sec hotfix
##### Version 1.8.4
>1.HttpServer组件升级到BladeMaster
##### Version 1.8.3
>1.去掉语言强制匹配
##### Version 1.8.2
>1.支持日文投稿
##### Version 1.8.1
>1.支持忽略等级和答题的白名单
>2.更新单元测试以符合saga的要求
##### Version 1.8.0
>1.对接私单项目之游戏广告交易平台
##### Version 1.7.2
>1.取消代码模式对分P的单次提交数量限制
##### Version 1.7.1
>1.添加稿件的时候一次性最多100P
>2.编辑稿件的时候一次性最多100P, 创作姬除外(暂时不支持编辑时候添加分P)
>3.Tag添加去重步骤
##### Version 1.7.0
>1.创作姬投稿添加稿件接口上线
##### Version 1.6.4
>1.支持前端投稿使用新转码方案, 参数为upos
##### Version 1.6.3
>1.videoup全Post接口全去掉ecode.NoLogin
##### Version 1.6.2
>1.在查询redis中filename是否过期之前,提前检测filename是否为空
##### Version 1.6.1
>1.创作姬编辑稿件,如果稿件在-30,-40,-1,1,0环境下只修改tag那么直接调用tagUpbind和update稿件库的tag字段
>2.创作姬编辑稿件添加tag过滤
##### Version 1.6.0
>1.提供给创作姬稿件编辑的接口暂时支持title,tag,desc,open_elec
##### Version 1.5.23
>1.替换稿件被锁定的错误提示,当前稿件已锁定,可能处于以下状态之一(审核锁定,网警锁定,用户删除)
##### Version 1.5.22
>1.禁止在剧集二级分区下进行添加稿件,提示"改分区不存在"
##### Version 1.5.21
>1.账号实名制使用protobuffer的RPC3来查询用户信息
##### Version 1.5.20
>1.FixBug: Add的时候不能用AP.Aid,默认为0应该使用返回的aid
##### Version 1.5.19
>1.Web和Client添加稿件的时候重新绑定tag的信息调用tag-service的upbind
##### Version 1.5.18
>1.Fix:代码模式下经过转换的Videos里没有Filename但是有Cid所以不需要检测上传的Filename是否超过了48小时的上传期限限制
##### Version 1.5.17
>1.完善Redis filename校验的日志有待观察和校验
##### Version 1.5.16
>1.fix: 在创建添加稿件的时候不需要更新Tag,因为这个时候TagService还没有aid关联到
##### Version 1.5.15
>1.添加支持稿件的动态字段Dynamic输入
##### Version 1.5.14
>1.Fix: 除了PC端暂时不允许其他端修改稿件的版权信息标记位沿用已有的值
##### Version 1.5.13
>1.feature: 实名认证APP修改稿件信息
>2.优化商单Http请求的4个API
##### Version 1.5.12
> 1.add feature: 添加稿件和修改稿件的时候tag统一不允许为空字符串
##### Version 1.5.11
> 1.hot fix: 手机端无法修改分P信息所以手机端去除对分P信息的长度校验逻辑
##### Version 1.5.10
> 1.feature: 在添加或者编辑稿件的时候提交空分P稿件服务端强行提示对应的文案
##### Version 1.5.9
> 1.优化: 简介格式化的数据从videoup-service的接口获取不连数据库查询
##### Version 1.5.8
> 1.Profile RPC接口使用创作中心自定义的账号错误码方便后续账号查找问题
##### Version 1.5.7
> 1.已经被打回的稿件在编辑的时候,如果参加了活动,就强制校验活动时间的有效性
##### Version 1.5.6
> 1.投稿的时候添加特殊限制条件,[电影]分区的特殊二级分区[欧美电影,日本电影,国产电影,其他国家]不允许提交多P稿件, 错误码为:VideoupForbidMultiVideoForTypes
##### Version 1.5.5
> 1.重构分P上传超出48小时期限的错误提示, VideoupFilenameExpired
##### Version 1.5.4
> 1.合并大仓库
##### Version 1.5.3
> 1.投稿编辑时候的投稿充电更新接口重构
##### Version 1.5.2
> 1.windows client 统一接入实名制
##### Version 1.5.1
> 1.充电的ArcShow接口重构,开启充电内部接口HOST:http://elec.bilibili.co
#### Version 1.5.0
> 1.格式化描述字段提交
> 2.冗余desc_format字段用来存储格式化之后的描述信息
> 3.校验对应的desc_format_id的逻辑
a: desc_format_id的有效性校验
b: 分区类型和格式化模板的有效性校验
c: 创作类型和格式化模板的有效性校验
##### Version 1.4.2
> 1.完善protectFieldForEdit特定情况下才允许修改typeID,Copyright,tag,missionID
> 2.Fix add dealTag for edit app and client
> 3.Fix add dealTag and dealElec for add client
##### Version 1.4.1
> 1.账号的_identifyInfo接口私有化
##### Version 1.4.0
> 1.私单功能上线
#### Version 1.3.3
> 1.特殊emoji字符的过滤允许输入基本的emoji字符集合但是高级的由于暂时表级别还不支持所以必须手动过滤
#### Version 1.3.2
> 1.fix bug: 只有-2:打回的稿件才能允许修改分区TypeID
> 2.add protect: 只有-2:打回的稿件才能允许修改创作类型copyright
#### Version 1.3.1
> 1.实名认证手机或者身份证有一个有效就可以
> 2.pre接口身份认证自定义: 2,"请先绑定手机"; 4,"请先完成实名认证"
##### Version 1.3.0
> 1. 实名认证, 只针对web端
##### Version 1.2.29
> 1. govendor升级一波 go-business v2.34.0 go-common v6.24.4
> 2. 对接新的bfs上传的错误代码
##### Version 1.2.28
> 1. 添加稿件的时候Must和编辑的时候一样必须放在第一位否则会被正则校验三国文字所影响
##### Version 1.2.26
> 1. BFS的配置全部落到配置文件包括传输超时和传输文件的最大值
> 2. 加上HTTP限速的代码和配置文件里面的两个配置项
##### Version 1.2.25
> 1. HotFix BFS timeout 2 seconds
##### Version 1.2.24
> 1. 添加Prom的LibClient监控
##### Version 1.2.23
> 1. fix bug: 编辑稿件的时候防止活动id为负数参数传递
##### Version 1.2.22
> 1. 升级go-common v6.17.0 和 go-business v2.24.1
##### Version 1.2.21
> 1.修复活动tag剔除
##### Version 1.2.20
> 1.bfs参数微调大小5mb以内
##### Version 1.2.19
> 1.up投稿时处理绑定tag
##### Version 1.2.18
> 1.更新govendor
> 2.添加prom monitor代码
> 3.修改redis的配置格式
##### Version 1.2.17
> 1.删除无用代码
> 2.修复错误码透传
##### Version 1.2.16
> 1.代码模式修改为传cid
##### Version 1.2.15
> 1.更新客户端请求方式VerifyPost=>UserPost, 统一使用c.Get("mid")获取用户mid
##### Version 1.2.14
> 1.分区信息脱离dede老库,使用videoup-service的typesAPI获取分区数据
##### Version 1.2.12
> 1.app编辑接口兼容ios
##### Version 1.2.11
> 1.Update GoBusiness to v2.13.2
##### Version 1.2.10
> 1.修复活动取消的逻辑
##### Version 1.2.9
> 1.重构活动在创建和编辑稿件的时候触发的逻辑
##### Version 1.2.8
> 1.添加allowSubmit限制filename的48h提交
##### Version 1.2.7
> 1.过滤不可见零宽字符
> 2.去掉删除48hfilename逻辑放job中实现
##### Version 1.2.6
> 1.修正简介回车换行被过滤的bug
##### Version 1.2.5
> 1.取消allowSubmit的限制
##### Version 1.2.4
> 1.更新分P的日志格式, 修正回车换行被过滤的bug
##### Version 1.2.3
> 1.添加allowSubmit限制filename的超时
##### Version 1.2.2
> 1.Update MonitorPing Left redisPing
##### Version 1.2.1
> 1.添加MonitorPing
##### Version 1.2.0
> 1.接入新配置中心
> 2.过滤ascii码中的不可见字符
> 3.添加编辑和新增稿件时的info日志
##### Version 1.1.1
> 1.支持windows client对接商单ID
##### Version 1.1.0
> 1.videoup对接商单ID的实现
##### Version 1.0.8
> 1.提交的时候判断活动的etime是否有效
##### Version 1.0.7
> 1.上次封面限制改为2mb
##### Version 1.0.6
> 1.修改判断dtime的逻辑
##### Version 1.0.5
> 1.转载来源描述信息拼接在一起
##### Version 1.0.4
> 1.取消对稿件状态为-40的稿件定时发布是否有效的判断
##### Version 1.0.3
> 1.投稿tag数允许12个
##### Version 1.0.2
> 1.用户编辑稿件的时候去掉对(-7)暂缓的不允许上传的限制
> 2.手机端加上在编辑的时候加上充电选项
> 3.删除form里的cover防止打印到日志
##### Version 1.0.1
> 1.先注释48h判断等全量15天之后再打开
##### Version 1.0.0
> 1.投稿API初版

View File

@@ -0,0 +1,15 @@
# Owner
shencen
wangzhe01
# Author
haoguanwei
shencen
shaojiatong
fengpengfei
# Reviewer
haoguanwei
shencen
shaojiatong
fengpengfei

View File

@@ -0,0 +1,19 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- fengpengfei
- haoguanwei
- shaojiatong
- shencen
- wangzhe01
labels:
- interface
- interface/main/videoup
- main
options:
no_parent_owners: true
reviewers:
- fengpengfei
- haoguanwei
- shaojiatong
- shencen

View File

@@ -0,0 +1,13 @@
#### videoup-interface
##### 项目简介
> 1.投稿API接口 只负责三类接口UGC三端的创建和编辑稿件接口以及封面上传
##### 编译环境
> 请只用golang v1.8.x以上版本编译执行。
##### 依赖包
> 1.公共包go-common
##### 特别说明
> 1.model目录可能会被其他项目引用请谨慎请改并通知各方。

View File

@@ -0,0 +1,45 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_binary",
"go_library",
)
go_binary(
name = "cmd",
embed = [":go_default_library"],
tags = ["automanaged"],
)
go_library(
name = "go_default_library",
srcs = ["main.go"],
data = ["videoup.toml"],
importpath = "go-common/app/interface/main/videoup/cmd",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/videoup/conf:go_default_library",
"//app/interface/main/videoup/http:go_default_library",
"//app/interface/main/videoup/service:go_default_library",
"//library/ecode/tip:go_default_library",
"//library/log:go_default_library",
"//library/net/trace:go_default_library",
"//library/queue/databus/report:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,53 @@
package main
import (
"flag"
"os"
"os/signal"
"syscall"
"time"
"go-common/app/interface/main/videoup/conf"
"go-common/app/interface/main/videoup/http"
"go-common/app/interface/main/videoup/service"
ecode "go-common/library/ecode/tip"
"go-common/library/log"
"go-common/library/net/trace"
"go-common/library/queue/databus/report"
)
func main() {
flag.Parse()
if err := conf.Init(); err != nil {
log.Error("conf.Init() error(%v)", err)
panic(err)
}
log.Init(conf.Conf.Xlog)
defer log.Close()
trace.Init(conf.Conf.Tracer)
defer trace.Close()
ecode.Init(conf.Conf.Ecode)
log.Info("videoup start")
// service init
report.InitUser(nil)
svr := service.New(conf.Conf)
http.Init(conf.Conf, svr)
// init signal
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
for {
s := <-c
log.Info("videoup get a signal %s", s.String())
switch s {
case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:
log.Info("videoup exit")
svr.Close()
time.Sleep(time.Second)
return
case syscall.SIGHUP:
// TODO reload
default:
return
}
}
}

View File

@@ -0,0 +1,11 @@
#!/bin/bash
command -v goconvey >/dev/null 2>&1 || {
echo >&2 "required goconvey but it's not installed.";
echo "Aborting.";
echo "Please run commond: go get github.com/smartystreets/goconvey";
exit 1;
}
cd ../videoup
goconvey -excludedDirs "vendor,node_modules,rpc" -packages 1

View File

@@ -0,0 +1,171 @@
# This is a TOML document. Boom.
tick = "5m"
MaxAllVsCnt = 4000
MaxAddVsCnt = 100
UgcPayAllowEditDays = 60
[AppEditorInfoc]
taskid = "001729"
proto = "tcp"
addr = "172.18.21.101:5403"
chanSize = 10240
[host]
archive = "http://archive.api.bilibili.co"
www = "http://www.bilibili.com"
member = "http://member.bilibili.com"
apico = "http://api.bilibili.co"
upMng = "http://cm.bilibili.co"
tag = "http://api.bilibili.co"
account = "http://account.bilibili.co"
vdsvc = "http://archive.api.bilibili.co"
elec = "http://elec.bilibili.com"
dynamic = "http://api.vc.bilibili.co"
mainsearch = "http://uat-manager.bilibili.co"
chaodian = "http://chaodian.bilibili.co"
[game]
OpenHost = "http://line1-game-open-api.biligame.net"
[game.app]
key = "EeOpM531WqQnBvu4"
secret = "gHtKtXTHZJDqGP1tg9ORFs0YWV3kW12V"
[app]
key = "c05dd4e1638a8af0"
secret = "7daa7f8c06cd33c5c3067063c746fdcb"
[httpClient]
[httpClient.UpMng]
key = "test"
secret = "e6c4c252dc7e3d8a90805eecd7c73396"
dial = "1s"
timeout = "3s"
keepAlive = "60s"
timer = 1000
[httpClient.UpMng.breaker]
window = "10s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[httpClient.read]
key = "c05dd4e1638a8af0"
secret = "7daa7f8c06cd33c5c3067063c746fdcb"
dial = "1s"
timeout = "1s"
keepAlive = "60s"
timer = 1000
[httpClient.read.breaker]
window = "10s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[httpClient.write]
key = "c05dd4e1638a8af0"
secret = "7daa7f8c06cd33c5c3067063c746fdcb"
dial = "1s"
timeout = "3s"
keepAlive = "60s"
timer = 1000
[httpClient.write.breaker]
window = "10s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[httpClient.fastread]
key = "c05dd4e1638a8af0"
secret = "7daa7f8c06cd33c5c3067063c746fdcb"
dial = "50ms"
timeout = "100ms"
keepAlive = "60s"
timer = 1000
[httpClient.fastread.breaker]
window = "10s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[httpClient.chaodian]
key = "chaodian_20190117tangseng"
secret = "chaodian_20190117tangseng"
dial = "1s"
timeout = "3s"
keepAlive = "60s"
timer = 1000
[httpClient.chaodian.breaker]
window = "10s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[memcache]
archiveExpire = "10s"
[memcache.archive]
name = "videoup/archive"
proto = "tcp"
addr = "172.16.33.54:11213"
idle = 5
active = 10
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "80s"
[memcache.account]
name = "videoup/account"
proto = "tcp"
addr = "172.16.33.54:11213"
idle = 5
active = 10
dialTimeout = "80ms"
readTimeout = "200ms"
writeTimeout = "200ms"
idleTimeout = "80s"
submitExpire = "10m"
[redis]
[redis.videoup]
name = "videoup"
proto = "tcp"
addr = "172.16.33.54:6381"
idle = 100
active = 100
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "10s"
expire = "10s"
[UpCoverAnti]
on=true
second=60
n=15
hour=12
m=1000
[UpCoverAnti.redis]
name = "videoup/videoup"
proto = "tcp"
addr = "172.16.33.54:6379"
idle = 100
active = 100
dialTimeout = "500ms"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "80s"
expire = "10m"
[bfs]
Timeout = "2s"
MaxFileSize = 5242880
[bm]
addr = "0.0.0.0:6321"
maxListen = 1000
timeout = "2s"
[limit]
"AddBasicExp" = "30s"

View File

@@ -0,0 +1,44 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["conf.go"],
importpath = "go-common/app/interface/main/videoup/conf",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/cache/memcache:go_default_library",
"//library/cache/redis:go_default_library",
"//library/conf:go_default_library",
"//library/database/sql:go_default_library",
"//library/ecode/tip:go_default_library",
"//library/log:go_default_library",
"//library/log/infoc:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/http/blademaster/middleware/antispam:go_default_library",
"//library/net/rpc:go_default_library",
"//library/net/rpc/warden:go_default_library",
"//library/net/trace:go_default_library",
"//library/time:go_default_library",
"//vendor/github.com/BurntSushi/toml:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,193 @@
package conf
import (
"errors"
"flag"
"go-common/library/cache/memcache"
"go-common/library/cache/redis"
"go-common/library/conf"
"go-common/library/database/sql"
ecode "go-common/library/ecode/tip"
xlog "go-common/library/log"
"go-common/library/log/infoc"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/middleware/antispam"
"go-common/library/net/rpc"
"go-common/library/net/rpc/warden"
"go-common/library/net/trace"
"go-common/library/time"
"github.com/BurntSushi/toml"
)
var (
// ConfPath str
ConfPath string
// Conf cfg
Conf = &Config{}
client *conf.Client
)
// Config struct
type Config struct {
AppEditorInfoc *infoc.Config
// base
Bfs *Bfs
Limit *Limit
// db
DB *DB
// tick
Tick time.Duration
// app
App *bm.App
// host
Host *Host
// http
HTTPClient *HTTPClient
// xlog
Xlog *xlog.Config
// tracer
Tracer *trace.Config
// ecode
Ecode *ecode.Config
// rpc client
RelationRPC *rpc.ClientConfig
SubRPC *rpc.ClientConfig
// mc
Memcache *Memcache
// redis
Redis *Redis
UpCoverAnti *antispam.Config
Game *Game
BM *bm.ServerConfig
// geetest
Geetest *Geetest
MaxAllVsCnt int
MaxAddVsCnt int
UgcPayAllowEditDays int
AccClient *warden.ClientConfig
UpClient *warden.ClientConfig
}
// Geetest geetest id & key
type Geetest struct {
CaptchaID string
MCaptchaID string
PrivateKEY string
MPrivateKEY string
}
// Game str Conf
type Game struct {
OpenHost string
App *bm.App
}
// DB conf.
type DB struct {
// archive db
Manager *sql.Config
}
// Limit config
type Limit struct {
AddBasicExp time.Duration
}
// Bfs bfs config
type Bfs struct {
Timeout time.Duration
MaxFileSize int
}
// Host conf
type Host struct {
Account string
Archive string
APICo string
WWW string
Member string
UpMng string
Tag string
Elec string
Geetest string
Dynamic string
MainSearch string
Chaodian string //超电
}
// HTTPClient str
type HTTPClient struct {
Read *bm.ClientConfig
Write *bm.ClientConfig
UpMng *bm.ClientConfig
FastRead *bm.ClientConfig
Chaodian *bm.ClientConfig
}
// Memcache str
type Memcache struct {
Account *struct {
*memcache.Config
SubmitExpire time.Duration
}
}
// Redis str
type Redis struct {
Videoup *struct {
*redis.Config
Expire time.Duration
}
}
func init() {
flag.StringVar(&ConfPath, "conf", "", "default config path")
}
// Init init
func Init() (err error) {
if ConfPath != "" {
return local()
}
return remote()
}
func local() (err error) {
_, err = toml.DecodeFile(ConfPath, &Conf)
return
}
func remote() (err error) {
if client, err = conf.New(); err != nil {
return
}
if err = load(); err != nil {
return
}
go func() {
for range client.Event() {
xlog.Info("config reload")
if load() != nil {
xlog.Error("config reload error (%v)", err)
}
}
}()
return
}
func load() (err error) {
var (
s string
ok bool
tmpConf *Config
)
if s, ok = client.Toml2(); !ok {
return errors.New("load config center error")
}
if _, err = toml.Decode(s, &tmpConf); err != nil {
return errors.New("could not decode config")
}
*Conf = *tmpConf
return
}

View File

@@ -0,0 +1,67 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"dao_test.go",
"mc_limit_test.go",
"rpc_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/videoup/conf:go_default_library",
"//app/service/main/account/api:go_default_library",
"//app/service/main/relation/model:go_default_library",
"//app/service/main/relation/rpc/client:go_default_library",
"//library/cache/memcache:go_default_library",
"//library/ecode:go_default_library",
"//vendor/github.com/bouk/monkey:go_default_library",
"//vendor/github.com/golang/mock/gomock:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
"//vendor/gopkg.in/h2non/gock.v1:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"dao.go",
"mc_limit.go",
"rpc.go",
],
importpath = "go-common/app/interface/main/videoup/dao/account",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/videoup/conf:go_default_library",
"//app/service/main/account/api:go_default_library",
"//app/service/main/relation/model:go_default_library",
"//app/service/main/relation/rpc/client:go_default_library",
"//library/cache/memcache:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,122 @@
package account
import (
"context"
"net/url"
"strconv"
"time"
"go-common/app/interface/main/videoup/conf"
accapi "go-common/app/service/main/account/api"
relation "go-common/app/service/main/relation/rpc/client"
"go-common/library/cache/memcache"
"go-common/library/ecode"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
)
const (
_addFollowingURI = "/x/internal/relation/following/add"
)
// Dao dao is account dao.
type Dao struct {
// config
c *conf.Config
// rpc
rela *relation.Service
acc accapi.AccountClient
// memcache
mc *memcache.Pool
mcSubExp, mcLimitAddBasicExp int32
client *bm.Client
addFollowingURL string
}
// New new a account dao.
func New(c *conf.Config) (d *Dao) {
d = &Dao{
c: c,
// rpc
rela: relation.New(c.RelationRPC),
// access memcache
mc: memcache.NewPool(c.Memcache.Account.Config),
mcSubExp: int32(time.Duration(c.Memcache.Account.SubmitExpire) / time.Second),
mcLimitAddBasicExp: int32(time.Duration(c.Limit.AddBasicExp) / time.Second),
client: bm.NewClient(c.HTTPClient.Write),
addFollowingURL: c.Host.APICo + _addFollowingURI,
}
var err error
if d.acc, err = accapi.NewClient(c.AccClient); err != nil {
panic(err)
}
return
}
// Close close resource.
func (d *Dao) Close() {
if d.mc != nil {
d.mc.Close()
}
}
// Ping ping success.
func (d *Dao) Ping(c context.Context) (err error) {
if err = d.pingMemcache(c); err != nil {
return
}
return
}
// IdentifyInfo 获取用户实名认证状态
func (d *Dao) IdentifyInfo(c context.Context, ip string, mid int64) (err error) {
var mf *accapi.Profile
if mf, err = d.Profile(c, mid, ip); err != nil {
log.Error("d.Profile mid(%d),ip(%s),error(%v)", mid, ip, err)
err = ecode.CreativeAccServiceErr
return
}
if mf.Identification == 1 {
return
}
//switch for FrontEnd return json format, return OldPhone, and newError
if err = d.switchIDInfoRet(mf.TelStatus); err != nil {
log.Error("switchIDInfoRet res(%v)", mf.TelStatus)
return
}
return
}
func (d *Dao) switchIDInfoRet(phoneRet int32) (err error) {
switch phoneRet {
case 0:
err = ecode.UserCheckNoPhone
case 1:
err = nil
case 2:
err = ecode.UserCheckInvalidPhone
}
return
}
// AddFollowing 添加关注
func (d *Dao) AddFollowing(c context.Context, mid, fid int64, src int, ip string) (err error) {
params := url.Values{}
params.Set("mid", strconv.FormatInt(mid, 10))
params.Set("fid", strconv.FormatInt(fid, 10))
params.Set("src", strconv.Itoa(src))
var res struct {
Code int `json:"code"`
}
if err = d.client.Post(c, d.addFollowingURL, ip, params, &res); err != nil {
log.Error("d.client.Do uri(%s) mid(%d) fid(%d) res(%+v) error(%v)", d.addFollowingURL+"?"+params.Encode(), mid, fid, res, err)
return
}
log.Info("acc AddFollowing url(%s)", d.addFollowingURL+"?"+params.Encode())
if res.Code != 0 {
log.Error("acc AddFollowing (%+s)|(%+d)|(%+d)|(%+d)|(%s) (%+v)", d.addFollowingURL, mid, fid, src, ip, res)
err = ecode.CreativeAccServiceErr
return
}
return
}

View File

@@ -0,0 +1,66 @@
package account
import (
"context"
"flag"
"go-common/app/interface/main/videoup/conf"
"os"
"strings"
"testing"
"github.com/smartystreets/goconvey/convey"
gock "gopkg.in/h2non/gock.v1"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.archive.videoup")
flag.Set("conf_token", "9772c9629b00ac09af29a23004795051")
flag.Set("tree_id", "2306")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
} else {
flag.Set("conf", "../../cmd/videoup.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
m.Run()
os.Exit(0)
}
func httpMock(method, url string) *gock.Request {
r := gock.New(url)
r.Method = strings.ToUpper(method)
d.client.SetTransport(gock.DefaultTransport)
return r
}
func TestAddFollowing(t *testing.T) {
convey.Convey("AddFollowing", t, func(ctx convey.C) {
var (
c = context.Background()
mid = int64(2089809)
fid = int64(2089810)
src = 173
ip = "127.0.0.1"
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
defer gock.OffAll()
httpMock("Post", d.addFollowingURL).Reply(200).JSON(`{"code":0,"data":""}`)
err := d.AddFollowing(c, mid, fid, src, ip)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}

View File

@@ -0,0 +1,132 @@
package account
import (
"context"
"crypto/md5"
"encoding/binary"
"encoding/hex"
"strconv"
"time"
"go-common/library/cache/memcache"
"go-common/library/log"
)
const (
_addMidAndTitlePrefix = "add_midtitle_"
_addMidHalfMinPrefix = "add_midhafmin_"
)
func limitMidHafMin(mid int64) string {
return _addMidHalfMinPrefix + strconv.FormatInt(mid, 10)
}
func limitMidSameTitle(mid int64, title string) string {
ms := md5.Sum([]byte(title))
return _addMidAndTitlePrefix + strconv.FormatInt(mid, 10) + "_" + hex.EncodeToString(ms[:])
}
// HalfMin fn
func (d *Dao) HalfMin(c context.Context, mid int64) (exist bool, ts uint64, err error) {
var (
conn = d.mc.Get(c)
rp *memcache.Item
)
defer conn.Close()
key := limitMidHafMin(mid)
rp, err = conn.Get(key)
if err != nil {
if err == memcache.ErrNotFound {
err = nil
} else {
log.Error("conn.Get error(%v) | key(%s) mid(%d)", err, key, mid)
}
return
}
if err = conn.Scan(rp, &ts); err != nil {
log.Error("conn.Scan(%s) error(%v)", rp.Value, err)
return
}
log.Info("HalfMin key(%s) ts(%d)", key, ts)
if ts != 0 {
exist = true
}
return
}
// AddHalfMin fn
func (d *Dao) AddHalfMin(c context.Context, mid int64) (err error) {
conn := d.mc.Get(c)
defer conn.Close()
key := limitMidHafMin(mid)
ts := time.Now().Unix()
if err = conn.Set(&memcache.Item{Key: key, Object: ts, Flags: memcache.FlagJSON, Expiration: d.mcLimitAddBasicExp}); err != nil {
log.Error("memcache.set error(%v) | key(%s) mid(%d)", err, key, mid)
}
return
}
// DelHalfMin func
func (d *Dao) DelHalfMin(c context.Context, mid int64) (err error) {
conn := d.mc.Get(c)
defer conn.Close()
if err = conn.Delete(limitMidHafMin(mid)); err == memcache.ErrNotFound {
err = nil
}
return
}
// SubmitCache get user submit cache.
func (d *Dao) SubmitCache(c context.Context, mid int64, title string) (exist int8, err error) {
var (
conn = d.mc.Get(c)
rp *memcache.Item
)
defer conn.Close()
key := limitMidSameTitle(mid, title)
rp, err = conn.Get(key)
if err != nil {
if err == memcache.ErrNotFound {
err = nil
} else {
log.Error("conn.Get error(%v) | key(%s) mid(%d) title(%s)", err, key, mid, title)
}
}
if rp != nil {
exist = int8(binary.BigEndian.Uint64(rp.Value))
}
return
}
// AddSubmitCache add submit cache into mc.
func (d *Dao) AddSubmitCache(c context.Context, mid int64, title string) (err error) {
conn := d.mc.Get(c)
defer conn.Close()
key := limitMidSameTitle(mid, title)
bs := make([]byte, 8)
binary.BigEndian.PutUint64(bs, 1)
if err = conn.Set(&memcache.Item{Key: key, Object: bs, Flags: memcache.FlagJSON, Expiration: d.mcSubExp}); err != nil {
log.Error("memcache.set error(%v) | key(%s) mid(%d) title(%s)", err, key, mid, title)
}
return
}
// DelSubmitCache func
func (d *Dao) DelSubmitCache(c context.Context, mid int64, title string) (err error) {
conn := d.mc.Get(c)
defer conn.Close()
if err = conn.Delete(limitMidSameTitle(mid, title)); err == memcache.ErrNotFound {
err = nil
}
return
}
func (d *Dao) pingMemcache(c context.Context) (err error) {
conn := d.mc.Get(c)
defer conn.Close()
if err = conn.Set(&memcache.Item{Key: "ping", Value: []byte("pong"), Expiration: 0}); err != nil {
log.Error("mc.ping.Store error(%v)", err)
return
}
return
}

View File

@@ -0,0 +1,179 @@
package account
import (
"context"
"go-common/library/cache/memcache"
"reflect"
"testing"
"github.com/bouk/monkey"
"github.com/smartystreets/goconvey/convey"
)
func TestAccountlimitMidHafMin(t *testing.T) {
convey.Convey("limitMidHafMin", t, func(ctx convey.C) {
var (
mid = int64(2089809)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := limitMidHafMin(mid)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestAccountlimitMidSameTitle(t *testing.T) {
convey.Convey("limitMidSameTitle", t, func(ctx convey.C) {
var (
mid = int64(2089809)
title = "iamtitle"
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := limitMidSameTitle(mid, title)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestAccountHalfMin(t *testing.T) {
convey.Convey("HalfMin", t, func(ctx convey.C) {
var (
c = context.Background()
mid = int64(2089809)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
connGuard := monkey.PatchInstanceMethod(reflect.TypeOf(d.mc), "Get", func(_ *memcache.Pool, _ context.Context) memcache.Conn {
return memcache.MockWith(memcache.ErrNotFound)
})
defer connGuard.Unpatch()
exist, ts, err := d.HalfMin(c, mid)
ctx.Convey("Then err should be nil.exist,ts should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(ts, convey.ShouldNotBeNil)
ctx.So(exist, convey.ShouldNotBeNil)
})
})
})
}
func TestAccountAddHalfMin(t *testing.T) {
convey.Convey("AddHalfMin", t, func(ctx convey.C) {
var (
c = context.Background()
mid = int64(2089809)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
connGuard := monkey.PatchInstanceMethod(reflect.TypeOf(d.mc), "Get", func(_ *memcache.Pool, _ context.Context) memcache.Conn {
return memcache.MockWith(memcache.ErrNotFound)
})
defer connGuard.Unpatch()
err := d.AddHalfMin(c, mid)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
})
})
})
}
func TestAccountDelHalfMin(t *testing.T) {
convey.Convey("DelHalfMin", t, func(ctx convey.C) {
var (
c = context.Background()
mid = int64(2089809)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
connGuard := monkey.PatchInstanceMethod(reflect.TypeOf(d.mc), "Get", func(_ *memcache.Pool, _ context.Context) memcache.Conn {
return memcache.MockWith(memcache.ErrNotFound)
})
defer connGuard.Unpatch()
err := d.DelHalfMin(c, mid)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestAccountSubmitCache(t *testing.T) {
convey.Convey("SubmitCache", t, func(ctx convey.C) {
var (
c = context.Background()
mid = int64(2089809)
title = "iamtitle"
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
connGuard := monkey.PatchInstanceMethod(reflect.TypeOf(d.mc), "Get", func(_ *memcache.Pool, _ context.Context) memcache.Conn {
return memcache.MockWith(memcache.ErrNotFound)
})
defer connGuard.Unpatch()
exist, err := d.SubmitCache(c, mid, title)
ctx.Convey("Then err should be nil.exist should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(exist, convey.ShouldNotBeNil)
})
})
})
}
func TestAccountAddSubmitCache(t *testing.T) {
convey.Convey("AddSubmitCache", t, func(ctx convey.C) {
var (
c = context.Background()
mid = int64(2089809)
title = "iamtitle"
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
connGuard := monkey.PatchInstanceMethod(reflect.TypeOf(d.mc), "Get", func(_ *memcache.Pool, _ context.Context) memcache.Conn {
return memcache.MockWith(memcache.ErrNotFound)
})
defer connGuard.Unpatch()
err := d.AddSubmitCache(c, mid, title)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
})
})
})
}
func TestAccountDelSubmitCache(t *testing.T) {
convey.Convey("DelSubmitCache", t, func(ctx convey.C) {
var (
c = context.Background()
mid = int64(2089809)
title = "iamtitle"
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
connGuard := monkey.PatchInstanceMethod(reflect.TypeOf(d.mc), "Get", func(_ *memcache.Pool, _ context.Context) memcache.Conn {
return memcache.MockWith(memcache.ErrNotFound)
})
defer connGuard.Unpatch()
err := d.DelSubmitCache(c, mid, title)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestAccountpingMemcache(t *testing.T) {
convey.Convey("pingMemcache", t, func(ctx convey.C) {
var (
c = context.Background()
err error
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
connGuard := monkey.PatchInstanceMethod(reflect.TypeOf(d.mc), "Get", func(_ *memcache.Pool, _ context.Context) memcache.Conn {
return memcache.MockWith(memcache.ErrNotFound)
})
defer connGuard.Unpatch()
err = d.pingMemcache(c)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
})
})
})
}

View File

@@ -0,0 +1,82 @@
package account
import (
"context"
accapi "go-common/app/service/main/account/api"
relaMdl "go-common/app/service/main/relation/model"
"go-common/library/ecode"
"go-common/library/log"
)
// Profile get profile from rpc
func (d *Dao) Profile(c context.Context, mid int64, ip string) (p *accapi.Profile, err error) {
arg := &accapi.MidReq{
Mid: mid,
}
var rpcRes *accapi.ProfileReply
if rpcRes, err = d.acc.Profile3(c, arg); err != nil {
log.Error("d.acc.Profile3 error(%v) | mid(%d) ip(%s) arg(%v)", err, mid, ip, arg)
err = ecode.CreativeAccServiceErr
}
if rpcRes != nil {
p = rpcRes.Profile
}
return
}
// Cards get cards from rpc
func (d *Dao) Cards(c context.Context, mids []int64, ip string) (cards map[int64]*accapi.Card, err error) {
var res *accapi.CardsReply
if len(mids) == 0 {
return
}
arg := &accapi.MidsReq{
Mids: mids,
}
if res, err = d.acc.Cards3(c, arg); err != nil {
log.Error("d.acc.Cards3 error(%v) | mids(%v) ip(%s) arg(%v)", err, mids, ip, arg)
err = ecode.CreativeAccServiceErr
}
if res != nil {
cards = res.Cards
}
return
}
// Infos get infos from rpc
func (d *Dao) Infos(c context.Context, mids []int64, ip string) (infos map[int64]*accapi.Info, err error) {
var res *accapi.InfosReply
arg := &accapi.MidsReq{
Mids: mids,
}
infos = make(map[int64]*accapi.Info)
if res, err = d.acc.Infos3(c, arg); err != nil {
log.Error("d.acc.Infos3 error(%v) | mids(%v) ip(%s) arg(%v)", err, mids, ip, arg)
err = ecode.CreativeAccServiceErr
}
if res != nil {
infos = res.Infos
}
return
}
// Relations get all relation state.
func (d *Dao) Relations(c context.Context, mid int64, fids []int64, ip string) (res map[int64]int, err error) {
var rls map[int64]*relaMdl.Following
if rls, err = d.rela.Relations(c, &relaMdl.ArgRelations{Mid: mid, Fids: fids, RealIP: ip}); err != nil {
log.Error("d.rela.Relations mid(%d)|ip(%s)|error(%v)", mid, ip, err)
err = ecode.CreativeAccServiceErr
return
}
if len(rls) == 0 {
log.Info("d.rela.Relations mid(%d)|ip(%s)", mid, ip)
return
}
res = make(map[int64]int, len(rls))
for _, v := range rls {
res[v.Mid] = int(v.Attribute)
}
log.Info("d.rela.Relations mid(%d)|res(%+v)|rls(%+v)|ip(%s)", mid, res, rls, ip)
return
}

View File

@@ -0,0 +1,107 @@
package account
import (
"context"
"reflect"
"testing"
relaMdl "go-common/app/service/main/relation/model"
"go-common/app/service/main/relation/rpc/client"
"github.com/bouk/monkey"
. "github.com/smartystreets/goconvey/convey"
accapi "go-common/app/service/main/account/api"
"go-common/library/ecode"
"github.com/golang/mock/gomock"
)
func WithMock(t *testing.T, f func(mock *gomock.Controller)) func() {
return func() {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
f(mockCtrl)
}
}
func TestAccountProfile(t *testing.T) {
Convey("1", t, WithMock(t, func(mockCtrl *gomock.Controller) {
var (
c = context.Background()
mid = int64(2089809)
ip = "127.0.0.1"
err error
p *accapi.Profile
)
mock := accapi.NewMockAccountClient(mockCtrl)
d.acc = mock
mockReq := &accapi.MidReq{
Mid: mid,
}
mock.EXPECT().Profile3(gomock.Any(), mockReq).Return(nil, ecode.CreativeAccServiceErr)
p, err = d.Profile(c, mid, ip)
So(err, ShouldNotBeNil)
So(p, ShouldBeNil)
}))
}
func TestDao_Cards(t *testing.T) {
var (
c = context.Background()
mid = int64(2089809)
ip = "127.0.0.1"
err error
)
Convey("Cards", t, WithMock(t, func(mockCtrl *gomock.Controller) {
mock := accapi.NewMockAccountClient(mockCtrl)
d.acc = mock
mockReq := &accapi.MidsReq{
Mids: []int64{mid},
}
res := &accapi.CardsReply{}
mock.EXPECT().Cards3(gomock.Any(), mockReq).Return(res, nil)
_, err = d.Cards(c, []int64{mid}, ip)
So(err, ShouldBeNil)
}))
}
func TestDao_Infos(t *testing.T) {
var (
c = context.Background()
mid = int64(2089809)
ip = "127.0.0.1"
err error
)
Convey("Infos", t, WithMock(t, func(mockCtrl *gomock.Controller) {
mock := accapi.NewMockAccountClient(mockCtrl)
d.acc = mock
mockReq := &accapi.MidsReq{
Mids: []int64{mid},
}
res := &accapi.InfosReply{}
mock.EXPECT().Infos3(gomock.Any(), mockReq).Return(res, nil)
_, err = d.Infos(c, []int64{mid}, ip)
So(err, ShouldBeNil)
}))
}
func TestDao_Relations(t *testing.T) {
var (
c = context.Background()
mid = int64(2089809)
ip = "127.0.0.1"
err error
)
Convey("Relations", t, func(ctx C) {
mock := monkey.PatchInstanceMethod(reflect.TypeOf(d.rela), "Relations",
func(_ *relation.Service, _ context.Context, _ *relaMdl.ArgRelations) (res map[int64]*relaMdl.Following, err error) {
res = make(map[int64]*relaMdl.Following)
res[2089809] = &relaMdl.Following{}
return res, nil
})
defer mock.Unpatch()
_, err = d.Relations(c, mid, []int64{mid}, ip)
So(err, ShouldBeNil)
})
}

View File

@@ -0,0 +1,68 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"api_test.go",
"dao_test.go",
"redis_test.go",
"type_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/videoup/conf:go_default_library",
"//app/interface/main/videoup/model/archive:go_default_library",
"//app/service/main/up/api/v1:go_default_library",
"//library/ecode:go_default_library",
"//vendor/github.com/golang/mock/gomock:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
"//vendor/gopkg.in/h2non/gock.v1:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"api.go",
"dao.go",
"redis.go",
"type.go",
],
importpath = "go-common/app/interface/main/videoup/dao/archive",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/creative/dao/tool:go_default_library",
"//app/interface/main/videoup/conf:go_default_library",
"//app/interface/main/videoup/model/archive:go_default_library",
"//app/interface/main/videoup/model/porder:go_default_library",
"//app/service/main/up/api/v1:go_default_library",
"//library/cache/redis:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/sync/errgroup:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,365 @@
package archive
import (
"bytes"
"context"
"crypto/md5"
"encoding/hex"
"encoding/json"
"go-common/app/interface/main/creative/dao/tool"
"go-common/app/interface/main/videoup/conf"
"go-common/app/interface/main/videoup/model/archive"
pordermdl "go-common/app/interface/main/videoup/model/porder"
upapi "go-common/app/service/main/up/api/v1"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/sync/errgroup"
"net/http"
"net/url"
"strconv"
"sync"
"time"
)
const (
_viewURL = "/videoup/view"
_addURL = "/videoup/add"
_editURL = "/videoup/edit"
_tagUpURL = "/videoup/tag/up"
_applyStaffs = "/videoup/staff/archive/applys"
// StaffWhiteGroupID const
StaffWhiteGroupID = int64(24)
)
// View get archive and videos.
func (d *Dao) View(c context.Context, aid int64, ip string) (a *archive.Archive, vs []*archive.Video, err error) {
params := url.Values{}
params.Set("aid", strconv.FormatInt(aid, 10))
var res struct {
Code int `json:"code"`
Message string `json:"message"`
Data struct {
Archive *archive.Archive `json:"archive"`
Videos []*archive.Video `json:"videos"`
} `json:"data"`
}
if err = d.httpR.Get(c, d.viewURI, ip, params, &res); err != nil {
log.Error("videoup view archive error(%v) | viewUri(%s) aid(%d) ip(%s) params(%v)", err, d.viewURI+"?"+params.Encode(), aid, ip, params)
err = ecode.CreativeArchiveAPIErr
return
}
if res.Code != 0 {
err = ecode.Error(ecode.Int(res.Code), res.Message)
log.Error("videoup view archive res code nq zero, res.Code(%d) | viewUri(%s) aid(%d) ip(%s) params(%v) res(%v)", res.Code, d.viewURI+"?"+params.Encode(), aid, ip, params, res)
return
}
a = res.Data.Archive
vs = res.Data.Videos
return
}
// ApplyStaffs fn
func (d *Dao) ApplyStaffs(c context.Context, aid int64, ip string) (staffs []*archive.Staff, err error) {
params := url.Values{}
params.Set("aid", strconv.FormatInt(aid, 10))
var res struct {
Code int `json:"code"`
Message string `json:"message"`
Data []*archive.StaffView `json:"data"`
}
if err = d.httpR.Get(c, d.applyStaffs, ip, params, &res); err != nil {
log.Error("videoup view archive error(%v) | viewUri(%s) aid(%d) ip(%s) params(%v)", err, d.viewURI+"?"+params.Encode(), aid, ip, params)
err = ecode.CreativeArchiveAPIErr
return
}
if res.Code != 0 {
log.Error("videoup view archive res code nq zero, res.Code(%d) | viewUri(%s) aid(%d) ip(%s) params(%v) res(%v)", res.Code, d.viewURI+"?"+params.Encode(), aid, ip, params, res)
err = ecode.CreativeArchiveAPIErr
return
}
for _, v := range res.Data {
staff := &archive.Staff{
Mid: v.ApMID,
Title: v.ApTitle,
}
staffs = append(staffs, staff)
}
return
}
// Add add archive and videos.
func (d *Dao) Add(c context.Context, ap *archive.ArcParam, ip string) (aid int64, err error) {
params := url.Values{}
params.Set("appkey", d.c.App.Key)
params.Set("ts", strconv.FormatInt(time.Now().Unix(), 10))
mh := md5.Sum([]byte(params.Encode() + d.c.App.Secret))
params.Set("sign", hex.EncodeToString(mh[:]))
var (
uri = d.addURI + "?" + params.Encode()
)
bs, err := json.Marshal(ap)
if err != nil {
log.Error("json.Marshal error(%v) | ap(%v) ap.Mid(%d) ap.videos(%v)", err, ap, ap.Mid, ap.Videos)
return
}
req, err := http.NewRequest("POST", uri, bytes.NewReader(bs))
if err != nil {
log.Error("http.NewRequest error(%v) | uri(%s) ap.Mid(%d)", err, uri, ap.Mid)
return
}
req.Header.Set("X-BACKEND-BILI-REAL-IP", ip)
var res struct {
Code int `json:"code"`
Message string `json:"message"`
Data struct {
Aid int64 `json:"aid"`
} `json:"data"`
}
if err = d.httpW.Do(c, req, &res); err != nil {
log.Error("d.Add error(%v) | uri(%s) ap(%+v)", err, uri, ap)
err = ecode.CreativeArchiveAPIErr
return
}
if res.Code != 0 {
err = ecode.Error(ecode.Int(res.Code), res.Message)
log.Error("d.Add nq zero (%v)|(%v)|(%v)|(%v)|uri(%s),ap(%+v)", res.Code, res.Message, res.Data, err, uri, ap)
return
}
log.Info("d.Add (%s)|res.Data.Aid(%d) ip(%s) ", string(bs), res.Data.Aid, ip)
aid = res.Data.Aid
return
}
// Edit edit archive and videos.
func (d *Dao) Edit(c context.Context, ap *archive.ArcParam, ip string) (err error) {
params := url.Values{}
params.Set("appkey", conf.Conf.App.Key)
params.Set("ts", strconv.FormatInt(time.Now().Unix(), 10))
mh := md5.Sum([]byte(params.Encode() + d.c.App.Secret))
params.Set("sign", hex.EncodeToString(mh[:]))
// uri
var (
uri = d.editURI + "?" + params.Encode()
)
// new request
bs, err := json.Marshal(ap)
if err != nil {
log.Error("json.Marshal ap error (%v) | ap(%v)", err, ap)
return
}
req, err := http.NewRequest("POST", uri, bytes.NewReader(bs))
if err != nil {
log.Error("http.NewRequest error(%v) | uri(%s) ap(%v)", err, uri, ap)
return
}
req.Header.Set("X-BACKEND-BILI-REAL-IP", ip)
var res struct {
Code int `json:"code"`
Message string `json:"message"`
}
if err = d.httpW.Do(c, req, &res); err != nil {
log.Error("d.Edit error(%v) | uri(%s) ap(%+v)", err, uri, ap)
err = ecode.CreativeArchiveAPIErr
return
}
if res.Code != 0 {
err = ecode.Error(ecode.Int(res.Code), res.Message)
log.Error("d.Add nq zero (%v)|(%v)|(%v)|uri(%s),ap(%+v)", res.Code, res.Message, err, uri, ap)
return
}
log.Info("d.Edit(%s) | ip(%s)", string(bs), ip)
return
}
// DescFormat fn
func (d *Dao) DescFormat(c context.Context) (descFormats map[int]*archive.DescFormat, err error) {
var res struct {
Code int `json:"code"`
Message string `json:"message"`
Data []*archive.DescFormat `json:"data"`
}
descFormats = make(map[int]*archive.DescFormat)
if err = d.httpR.Get(c, d.descFormatURI, "", nil, &res); err != nil {
log.Error("videoup descFormat error(%v) | descFormatURI(%s) err(%v)", err, d.descFormatURI, err)
err = ecode.CreativeArchiveAPIErr
return
}
if res.Code != 0 {
err = ecode.Error(ecode.Int(res.Code), res.Message)
log.Error("videoup descFormat res.Code(%d) | descFormatURI(%s) res(%v) err(%v)", res.Code, d.descFormatURI, res, err)
return
}
for _, v := range res.Data {
descFormats[v.ID] = v
}
return
}
// TagUp fn
func (d *Dao) TagUp(c context.Context, aid int64, tag, ip string) (err error) {
params := url.Values{}
params.Set("aid", strconv.Itoa(int(aid)))
params.Set("tag", tag)
var res struct {
Code int `json:"code"`
}
if err = d.httpW.Post(c, d.tagUpURI, ip, params, &res); err != nil {
log.Error("Post(%s,%s,%s) err(%v)", d.tagUpURI, ip, params.Encode(), err)
err = ecode.CreativeArchiveAPIErr
return
}
if res.Code != 0 {
log.Error("Code(%s,%s,%s) err(%v), code(%d)", d.tagUpURI, ip, params.Encode(), err, res.Code)
err = ecode.CreativeArchiveAPIErr
return
}
return
}
// PorderCfgList fn
func (d *Dao) PorderCfgList(c context.Context) (cfgs map[int64]*pordermdl.Config, err error) {
cfgs = make(map[int64]*pordermdl.Config)
var res struct {
Code int `json:"code"`
Data []*pordermdl.Config `json:"data"`
}
if err = d.httpR.Get(c, d.porderConfigURL, "", nil, &res); err != nil {
log.Error("archive.porderConfigURL url(%s) error(%v)", d.porderConfigURL, err)
err = ecode.CreativeArchiveAPIErr
return
}
if res.Code != 0 {
log.Error("archive.porderConfigURL url(%s) res(%v)", d.porderConfigURL, res)
err = ecode.CreativeArchiveAPIErr
return
}
for _, cfg := range res.Data {
cfgs[cfg.ID] = cfg
}
return
}
// GameList fn
func (d *Dao) GameList(c context.Context) (gameMap map[int64]*pordermdl.Game, err error) {
gameMap = make(map[int64]*pordermdl.Game)
params := url.Values{}
params.Set("appkey", conf.Conf.Game.App.Key)
params.Set("appsecret", conf.Conf.Game.App.Secret)
params.Set("ts", strconv.FormatInt(time.Now().UnixNano()/1000000, 10))
var res struct {
Code int `json:"code"`
Data []*pordermdl.Game `json:"data"`
}
var (
query, _ = tool.Sign(params)
url string
)
url = d.gameListURL + "?" + query
req, err := http.NewRequest("GET", url, nil)
if err != nil {
log.Error("http.NewRequest(%s) error(%v), ", url, err)
err = ecode.CreativeGameOpenAPIErr
return
}
if err = d.httpR.Do(c, req, &res); err != nil {
log.Error("d.httpR.Do(%s) error(%v);", url, err)
err = ecode.CreativeGameOpenAPIErr
return
}
log.Info("GameList url(%+v)|gameLen(%+v)", url, len(res.Data))
if res.Code != 0 {
log.Error("GameList api url(%s) res(%v);, code(%d)", url, res, res.Code)
err = ecode.CreativeGameOpenAPIErr
return
}
for _, data := range res.Data {
gameMap[data.GameBaseID] = data
}
return
}
//StaffUps 联合投稿白名单
func (d *Dao) StaffUps(c context.Context) (ups map[int64]int64, err error) {
return d.UpSpecial(c, StaffWhiteGroupID)
}
// StaffTypeConfig 获取联合投稿分区配置
func (d *Dao) StaffTypeConfig(c context.Context) (isGary bool, typeConf map[int16]*archive.StaffTypeConf, err error) {
typeConf = make(map[int16]*archive.StaffTypeConf)
params := url.Values{}
var res struct {
Code int `json:"code"`
Data struct {
IsGary bool `json:"is_gary"`
TypeList []*archive.StaffTypeConf `json:"typelist"`
} `json:"data"`
}
if err = d.httpR.Get(c, d.staffConfigURI, "", params, &res); err != nil {
log.Error("StaffTypeConfig error(%v) | staffConfigURI(%s)", err, d.staffConfigURI)
err = ecode.CreativeArchiveAPIErr
return
}
log.Info("StaffTypeConfig url(%+v)|res(%+v)", d.staffConfigURI, res)
if res.Code != 0 || res.Data.TypeList == nil {
log.Error("StaffTypeConfig api url(%s) res(%+v);, code(%d)", d.staffConfigURI, res, res.Code)
err = ecode.CreativeArchiveAPIErr
return
}
isGary = res.Data.IsGary
for _, v := range res.Data.TypeList {
typeConf[v.TypeID] = v
}
return
}
// UpSpecial 获取UP主的特殊用户组
func (d *Dao) UpSpecial(c context.Context, gpid int64) (ups map[int64]int64, err error) {
var (
res *upapi.UpGroupMidsReply
page int
g errgroup.Group
l sync.RWMutex
)
if res, err = d.UpClient.UpGroupMids(c, &upapi.UpGroupMidsReq{
GroupID: gpid,
Pn: 1,
Ps: 1,
}); err != nil {
log.Error("UpSpecial d.UpSpecial gpid(%d)|error(%v)", gpid, err)
return
}
log.Warn("UpSpecial get total: gpid(%d)|total(%d)", gpid, res.Total)
if res.Total <= 0 {
return
}
ups = make(map[int64]int64, res.Total)
ps := int(10000)
pageNum := res.Total / ps
if res.Total%ps != 0 {
pageNum++
}
for page = 1; page <= pageNum; page++ {
tmpPage := page
g.Go(func() (err error) {
resgg, err := d.UpClient.UpGroupMids(c, &upapi.UpGroupMidsReq{
GroupID: gpid,
Pn: tmpPage,
Ps: ps,
})
if err != nil {
log.Error("d.UpGroupMids gg (%d,%d,%d) error(%v) ", gpid, tmpPage, ps, err)
err = nil
return
}
for _, mid := range resgg.Mids {
l.Lock()
ups[mid] = mid
l.Unlock()
}
return
})
}
g.Wait()
log.Warn("UpSpecial get result: gpid,total,midslen,upslens (%d)|(%d)|(%d)", gpid, res.Total, len(ups))
return
}

View File

@@ -0,0 +1,216 @@
package archive
import (
"context"
"go-common/app/interface/main/videoup/model/archive"
upapi "go-common/app/service/main/up/api/v1"
"go-common/library/ecode"
"testing"
"github.com/golang/mock/gomock"
. "github.com/smartystreets/goconvey/convey"
"gopkg.in/h2non/gock.v1"
)
func TestPing(t *testing.T) {
Convey("Ping", t, func(ctx C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx C) {
err := d.Ping(c)
ctx.Convey("Then err should be nil.a,vs should not be nil.", func(ctx C) {
ctx.So(err, ShouldNotBeNil)
})
})
})
}
func TestArchiveView(t *testing.T) {
Convey("View", t, func(ctx C) {
var (
c = context.Background()
aid = int64(10110826)
ip = "127.0.0.1"
)
ctx.Convey("When everything goes positive", func(ctx C) {
defer gock.OffAll()
httpMock("GET", d.viewURI).Reply(200).JSON(`{"code":20001,"data":""}`)
a, vs, err := d.View(c, aid, ip)
ctx.Convey("Then err should be nil.a,vs should not be nil.", func(ctx C) {
ctx.So(err, ShouldNotBeNil)
ctx.So(vs, ShouldBeNil)
ctx.So(a, ShouldBeNil)
})
})
})
}
func TestArchiveAdd(t *testing.T) {
Convey("Add", t, func(ctx C) {
var (
c = context.Background()
ap = &archive.ArcParam{}
ip = "127.0.0.1"
)
ctx.Convey("When everything goes positive", func(ctx C) {
defer gock.OffAll()
httpMock("Post", d.addURI).Reply(200).JSON(`{"code":20001,"data":""}`)
aid, err := d.Add(c, ap, ip)
ctx.Convey("Then err should be nil.aid should not be nil.", func(ctx C) {
ctx.So(err, ShouldNotBeNil)
ctx.So(aid, ShouldNotBeNil)
})
})
})
}
func TestArchiveEdit(t *testing.T) {
Convey("Edit", t, func(ctx C) {
var (
c = context.Background()
ap = &archive.ArcParam{}
ip = "127.0.0.1"
)
ctx.Convey("When everything goes positive", func(ctx C) {
defer gock.OffAll()
httpMock("Post", d.editURI).Reply(200).JSON(`{"code":20001,"data":""}`)
err := d.Edit(c, ap, ip)
ctx.Convey("Then err should be nil.", func(ctx C) {
ctx.So(err, ShouldNotBeNil)
})
})
})
}
func TestArchiveDescFormat(t *testing.T) {
Convey("DescFormat", t, func(ctx C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx C) {
descFormats, err := d.DescFormat(c)
ctx.Convey("Then err should be nil.descFormats should not be nil.", func(ctx C) {
ctx.So(err, ShouldBeNil)
ctx.So(descFormats, ShouldNotBeNil)
})
})
})
}
func TestArchiveTagUp(t *testing.T) {
Convey("TagUp", t, func(ctx C) {
var (
c = context.Background()
aid = int64(10110826)
tag = "iamatag"
ip = "127.0.0.1"
)
ctx.Convey("When everything goes positive", func(ctx C) {
err := d.TagUp(c, aid, tag, ip)
ctx.Convey("Then err should be nil.", func(ctx C) {
ctx.So(err, ShouldBeNil)
})
})
})
}
func TestArchivePorderCfgList(t *testing.T) {
Convey("PorderCfgList", t, func(ctx C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx C) {
cfgs, err := d.PorderCfgList(c)
ctx.Convey("Then err should be nil.cfgs should not be nil.", func(ctx C) {
ctx.So(err, ShouldBeNil)
ctx.So(cfgs, ShouldNotBeNil)
})
})
})
}
func TestArchiveGameList(t *testing.T) {
Convey("GameList", t, func(ctx C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx C) {
defer gock.OffAll()
httpMock("GET", d.viewURI).Reply(200).JSON(`{"code":20051,"data":""}`)
gameMap, err := d.GameList(c)
ctx.Convey("Then err should be nil.gameMap should not be nil.", func(ctx C) {
ctx.So(err, ShouldNotBeNil)
ctx.So(gameMap, ShouldNotBeNil)
})
})
})
}
func TestUpSpecial(t *testing.T) {
var (
c = context.Background()
res map[int64]int64
err error
)
Convey("UpSpecial", t, func(ctx C) {
res, err = d.UpSpecial(c, 17)
So(res, ShouldNotBeNil)
So(err, ShouldBeNil)
})
}
func TestDao_ApplyStaffs(t *testing.T) {
var (
c = context.Background()
aid = int64(10110826)
ip = "127.0.0.1"
err error
)
Convey("ApplyStaffs", t, func(ctx C) {
httpMock("GET", d.applyStaffs).Reply(200).JSON(`{"code":0}`)
_, err = d.ApplyStaffs(c, aid, ip)
So(err, ShouldBeNil)
})
}
func WithMock(t *testing.T, f func(mock *gomock.Controller)) func() {
return func() {
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
f(mockCtrl)
}
}
func TestDao_StaffUps(t *testing.T) {
Convey("StaffUps", t, WithMock(t, func(mockCtrl *gomock.Controller) {
var (
c = context.Background()
err error
ups map[int64]int64
)
mock := upapi.NewMockUpClient(mockCtrl)
d.UpClient = mock
mockReq := &upapi.UpGroupMidsReq{
GroupID: 1,
Pn: 1,
Ps: 1,
}
mock.EXPECT().UpGroupMids(gomock.Any(), mockReq).Return(nil, ecode.CreativeAccServiceErr)
ups, err = d.StaffUps(c)
So(err, ShouldNotBeNil)
So(ups, ShouldBeNil)
}))
}
func TestDao_StaffTypeConfig(t *testing.T) {
var (
c = context.Background()
err error
)
Convey("StaffTypeConfig", t, func(ctx C) {
httpMock("GET", d.staffConfigURI).Reply(200).JSON(`{"code":0,"data":{"is_gray":true,"typelist":[{"typeid":22,"max_staff":6}]}}`)
_, _, err = d.StaffTypeConfig(c)
So(err, ShouldBeNil)
})
}

View File

@@ -0,0 +1,87 @@
package archive
import (
"context"
"go-common/app/interface/main/videoup/conf"
upapi "go-common/app/service/main/up/api/v1"
"go-common/library/cache/redis"
bm "go-common/library/net/http/blademaster"
"time"
)
// Dao is archive dao.
type Dao struct {
c *conf.Config
// http
httpR *bm.Client
httpW *bm.Client
UpClient upapi.UpClient
// redis
redis *redis.Pool
redisExpire int32
// uri
viewURI string
addURI string
editURI string
typesURI string
descFormatURI string
tagUpURI string
staffConfigURI string
applyStaffs string
// ad check
porderConfigURL string
gameListURL string
}
const (
_descFormatURL = "/videoup/desc/format"
_porderConfig = "/videoup/porder/config/list"
_gameList = "/game/list"
_staffConfURI = "/x/internal/creative/staff/config"
)
// New new a dao.
func New(c *conf.Config) (d *Dao) {
d = &Dao{
c: c,
//filename redis
redis: redis.NewPool(c.Redis.Videoup.Config),
redisExpire: int32(time.Duration(c.Redis.Videoup.Expire) / time.Second),
// http client
httpR: bm.NewClient(c.HTTPClient.Read),
httpW: bm.NewClient(c.HTTPClient.Write),
// uri
viewURI: c.Host.Archive + _viewURL,
addURI: c.Host.Archive + _addURL,
editURI: c.Host.Archive + _editURL,
typesURI: c.Host.Archive + _typesURL,
descFormatURI: c.Host.Archive + _descFormatURL,
tagUpURI: c.Host.Archive + _tagUpURL,
staffConfigURI: c.Host.APICo + _staffConfURI,
applyStaffs: c.Host.Archive + _applyStaffs,
// ad
porderConfigURL: c.Host.Archive + _porderConfig,
gameListURL: c.Game.OpenHost + _gameList,
}
var err error
if d.UpClient, err = upapi.NewClient(c.UpClient); err != nil {
panic(err)
}
return d
}
// Ping ping success.
func (d *Dao) Ping(c context.Context) (err error) {
if err = d.pingRedis(c); err != nil {
return
}
return
}
// Close close resource.
func (d *Dao) Close() {
if d.redis != nil {
d.redis.Close()
}
}

View File

@@ -0,0 +1,45 @@
package archive
import (
"flag"
"go-common/app/interface/main/videoup/conf"
"os"
"strings"
"testing"
gock "gopkg.in/h2non/gock.v1"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.archive.videoup")
flag.Set("conf_token", "9772c9629b00ac09af29a23004795051")
flag.Set("tree_id", "2306")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
} else {
flag.Set("conf", "../../cmd/videoup.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
m.Run()
os.Exit(0)
}
func httpMock(method, url string) *gock.Request {
r := gock.New(url)
r.Method = strings.ToUpper(method)
d.httpR.SetTransport(gock.DefaultTransport)
return r
}

View File

@@ -0,0 +1,73 @@
package archive
import (
"context"
"strconv"
"time"
"go-common/app/interface/main/videoup/model/archive"
"go-common/library/cache/redis"
"go-common/library/log"
)
const (
_upFavTpsPrefix = "up_fav_tps_"
)
func keyUpFavTpsPrefix(mid int64) string {
return _upFavTpsPrefix + strconv.FormatInt(mid, 10)
}
// FilenameExpires get filename expire time.
func (d *Dao) FilenameExpires(c context.Context, vs []*archive.VideoParam) (ves []*archive.VideoExpire, err error) {
var conn = d.redis.Get(c)
defer conn.Close()
for _, v := range vs {
conn.Send("GET", v.Filename)
}
if err = conn.Flush(); err != nil {
log.Error("conn.Flush() error(%v) | vs(%#v)", err, vs)
return
}
for _, v := range vs {
var exp int64
if exp, err = redis.Int64(conn.Receive()); err != nil && err != redis.ErrNil {
log.Error("conn.Receive error(%+v) | filename(%s)", err, v.Filename)
return
}
err = nil // NOTE: maybe err==redis.ErrNil
ves = append(ves, &archive.VideoExpire{
Filename: v.Filename,
Expire: exp,
})
}
return
}
// FreshFavTypes fn
func (d *Dao) FreshFavTypes(c context.Context, mid int64, tp int) (err error) {
var (
conn = d.redis.Get(c)
score = time.Now().Unix()
)
defer conn.Close()
if err = conn.Send("ZADD", keyUpFavTpsPrefix(mid), score, strconv.Itoa(tp)); err != nil {
log.Error("conn.Send(ZADD, %s, %d) error(%v)", _upFavTpsPrefix, tp, err)
return
}
if err = conn.Flush(); err != nil {
log.Error("conn.Flush error(%v)", err)
return
}
if _, err = conn.Receive(); err != nil {
log.Error("conn.Receive() error(%v)", err)
}
return
}
func (d *Dao) pingRedis(c context.Context) (err error) {
conn := d.redis.Get(c)
_, err = conn.Do("SET", "PING", "PONG")
conn.Close()
return
}

View File

@@ -0,0 +1,69 @@
package archive
import (
"context"
"go-common/app/interface/main/videoup/model/archive"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestArchivekeyUpFavTpsPrefix(t *testing.T) {
convey.Convey("keyUpFavTpsPrefix", t, func(ctx convey.C) {
var (
mid = int64(2089809)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := keyUpFavTpsPrefix(mid)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestArchiveFilenameExpires(t *testing.T) {
convey.Convey("FilenameExpires", t, func(ctx convey.C) {
var (
c = context.Background()
vs = []*archive.VideoParam{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
ves, err := d.FilenameExpires(c, vs)
ctx.Convey("Then err should be nil.ves should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
ctx.So(ves, convey.ShouldBeNil)
})
})
})
}
func TestArchiveFreshFavTypes(t *testing.T) {
convey.Convey("FreshFavTypes", t, func(ctx convey.C) {
var (
c = context.Background()
mid = int64(2089809)
tp = int(162)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.FreshFavTypes(c, mid, tp)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
})
})
})
}
func TestArchivepingRedis(t *testing.T) {
convey.Convey("pingRedis", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.pingRedis(c)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
})
})
})
}

View File

@@ -0,0 +1,39 @@
package archive
import (
"context"
"go-common/app/interface/main/videoup/model/archive"
"go-common/library/ecode"
"go-common/library/log"
)
const (
_typesURL = "/videoup/types"
)
// TypeMapping is second types opposite first types.
func (d *Dao) TypeMapping(c context.Context) (rmap map[int16]*archive.Type, err error) {
var res struct {
Code int `json:"code"`
Message string `json:"message"`
Data map[int16]*archive.Type `json:"data"`
}
if err = d.httpR.Get(c, d.typesURI, "", nil, &res); err != nil {
log.Error("videoup view archive error(%v) | typesURI(%s)", err, d.typesURI)
err = ecode.CreativeArchiveAPIErr
return
}
if res.Code != 0 {
err = ecode.CreativeArchiveAPIErr
log.Error("get archive type failed res.Code(%d) | typesURI(%s) res(%v)", res.Code, d.typesURI, res)
return
}
rmap = make(map[int16]*archive.Type, len(res.Data))
for _, v := range res.Data {
if v.PID != 0 {
rmap[v.ID] = v
}
}
return
}

View File

@@ -0,0 +1,28 @@
package archive
import (
"context"
"testing"
"gopkg.in/h2non/gock.v1"
"github.com/smartystreets/goconvey/convey"
)
func TestArchiveTypeMapping(t *testing.T) {
convey.Convey("TypeMapping", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
defer gock.OffAll()
httpMock("GET", d.typesURI).Reply(200).JSON(`{"code":20001}`)
rmap, err := d.TypeMapping(c)
ctx.Convey("Then err should be nil.rmap should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
ctx.So(rmap, convey.ShouldBeNil)
})
})
})
}

View File

@@ -0,0 +1,45 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = ["dao_test.go"],
embed = [":go_default_library"],
tags = ["automanaged"],
deps = [
"//app/interface/main/videoup/conf:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = ["dao.go"],
importpath = "go-common/app/interface/main/videoup/dao/bfs",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/videoup/conf:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,98 @@
package bfs
import (
"context"
"crypto/hmac"
"crypto/sha1"
"encoding/base64"
"fmt"
"go-common/app/interface/main/videoup/conf"
"go-common/library/ecode"
"go-common/library/log"
"hash"
"io"
"net/http"
"strconv"
"time"
)
const (
_bucket = "archive"
_url = "http://bfs.bilibili.co/bfs/archive/"
_template = "%s\n%s\n\n%d\n"
_method = "PUT"
_key = "8d4e593ba7555502"
_secret = "0bdbd4c7caeeddf587c3c4daec0475"
)
// Dao is bfs dao.
type Dao struct {
c *conf.Config
client *http.Client
}
// New new a bfs dao.
func New(c *conf.Config) (d *Dao) {
d = &Dao{
c: c,
client: &http.Client{
Timeout: time.Duration(c.Bfs.Timeout),
},
}
return d
}
// Upload upload bfs.
func (d *Dao) Upload(c context.Context, fileType string, body io.Reader) (location string, err error) {
req, err := http.NewRequest(_method, _url, body)
if err != nil {
log.Error("http.NewRequest error (%v) | fileType(%s) body(%v)", err, fileType, body)
return
}
expire := time.Now().Unix()
authorization := authorize(_key, _secret, _method, _bucket, expire)
req.Header.Set("Host", _url)
req.Header.Add("Date", fmt.Sprint(expire))
req.Header.Add("Authorization", authorization)
req.Header.Add("Content-Type", fileType)
// timeout
c, cancel := context.WithTimeout(c, time.Duration(d.c.Bfs.Timeout))
req = req.WithContext(c)
defer cancel()
resp, err := d.client.Do(req)
if err != nil {
log.Error("d.Client.Do error(%v) | _url(%s) req(%v)", err, _url, req)
err = ecode.BfsUploadServiceUnavailable
return
}
if resp.StatusCode != http.StatusOK {
log.Error("Upload http.StatusCode nq http.StatusOK (%d) | url(%s)", resp.StatusCode, _url)
err = ecode.BfsUploadStatusErr
return
}
header := resp.Header
code := header.Get("Code")
if code != strconv.Itoa(http.StatusOK) {
log.Error("strconv.Itoa err, code(%s) | url(%s)", code, _url)
err = ecode.BfsUploadCodeErr
return
}
location = header.Get("Location")
return
}
// authorize returns authorization for upload file to bfs
func authorize(key, secret, method, bucket string, expire int64) (authorization string) {
var (
content string
mac hash.Hash
signature string
)
content = fmt.Sprintf(_template, method, bucket, expire)
mac = hmac.New(sha1.New, []byte(secret))
mac.Write([]byte(content))
signature = base64.StdEncoding.EncodeToString(mac.Sum(nil))
authorization = fmt.Sprintf("%s:%s:%d", key, signature, expire)
return
}

View File

@@ -0,0 +1,54 @@
package bfs
import (
"bytes"
"context"
"flag"
"go-common/app/interface/main/videoup/conf"
"os"
"testing"
"github.com/smartystreets/goconvey/convey"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.archive.videoup")
flag.Set("conf_token", "9772c9629b00ac09af29a23004795051")
flag.Set("tree_id", "2306")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
} else {
flag.Set("conf", "../cmd/videoup.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
m.Run()
os.Exit(0)
}
func Test_Upload(t *testing.T) {
var (
c = context.TODO()
err error
loc string
body = []byte{}
)
convey.Convey("Upload", t, func(ctx convey.C) {
loc, err = d.Upload(c, "jpeg", bytes.NewReader(body))
ctx.Convey("Then err should be nil should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
ctx.So(loc, convey.ShouldNotBeNil)
})
})
}

View File

@@ -0,0 +1,55 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"creative_test.go",
"dao_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/videoup/conf:go_default_library",
"//app/interface/main/videoup/model/archive:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
"//vendor/gopkg.in/h2non/gock.v1:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"creative.go",
"dao.go",
],
importpath = "go-common/app/interface/main/videoup/dao/creative",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/videoup/conf:go_default_library",
"//app/interface/main/videoup/model/archive:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,80 @@
package creative
import (
"bytes"
"context"
"crypto/md5"
"encoding/hex"
"encoding/json"
"go-common/app/interface/main/videoup/conf"
"go-common/app/interface/main/videoup/model/archive"
"go-common/library/log"
"net/http"
"net/url"
"strconv"
"time"
)
const (
_setWatermark = "/x/internal/creative/watermark/set"
_uploadMaterial = "/x/internal/creative/upload/material"
)
// SetWatermark fn
func (d *Dao) SetWatermark(c context.Context, mid int64, state, ty, pos int8, ip string) (err error) {
params := url.Values{}
params.Set("mid", strconv.FormatInt(mid, 10))
params.Set("state", strconv.Itoa(int(state)))
params.Set("type", strconv.Itoa(int(ty)))
params.Set("position", strconv.Itoa(int(pos)))
var res struct {
Code int `json:"code"`
}
if err = d.httpW.Post(c, d.setWatermarkURL, ip, params, &res); err != nil {
log.Error("d.httpW.Post(%s) error(%v)", d.setWatermarkURL+"?"+params.Encode(), err)
return
}
log.Info("SetWatermark url(%s) code(%d)", d.setWatermarkURL+"?"+params.Encode(), res.Code)
if res.Code != 0 {
log.Error("url(%s) code(%d)", d.setWatermarkURL+"?"+params.Encode(), res.Code)
}
return
}
// UploadMaterial fn
func (d *Dao) UploadMaterial(c context.Context, editors []*archive.Editor, aid, mid int64, ip string) (err error) {
params := url.Values{}
params.Set("appkey", conf.Conf.App.Key)
params.Set("ts", strconv.FormatInt(time.Now().Unix(), 10))
params.Set("mid", strconv.FormatInt(mid, 10))
params.Set("aid", strconv.FormatInt(aid, 10))
mh := md5.Sum([]byte(params.Encode() + d.c.App.Secret))
params.Set("sign", hex.EncodeToString(mh[:]))
var (
uri = d.uploadMaterialURL + "?" + params.Encode()
)
bs, err := json.Marshal(editors)
if err != nil {
log.Error("UploadMaterial json.Marshal error(%+v)|editor(%+v)", err, editors)
return
}
req, err := http.NewRequest("POST", uri, bytes.NewReader(bs))
if err != nil {
log.Error("UploadMaterial http.NewRequest error(%v) | uri(%s) bs(%+v)", err, uri, bs)
return
}
req.Header.Set("X-BACKEND-BILI-REAL-IP", ip)
var res struct {
Code int `json:"code"`
Message string `json:"message"`
}
if err = d.httpW.Do(c, req, &res); err != nil {
log.Error("UploadMaterial do error(%v)|uri(%s)", err, uri)
return
}
log.Info("UploadMaterial url(%s) code(%d)", uri, res.Code)
if res.Code != 0 {
log.Error("url(%s) code(%d)", uri, res.Code)
}
return
}

View File

@@ -0,0 +1,51 @@
package creative
import (
"context"
"go-common/app/interface/main/videoup/model/archive"
"testing"
"github.com/smartystreets/goconvey/convey"
gock "gopkg.in/h2non/gock.v1"
)
func TestCreativeSetWatermark(t *testing.T) {
convey.Convey("SetWatermark", t, func(ctx convey.C) {
var (
c = context.Background()
mid = int64(2089809)
state = int8(1)
ty = int8(3)
pos = int8(1)
ip = "127.0.0.1"
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
defer gock.OffAll()
httpMock("Post", d.setWatermarkURL).Reply(200).JSON(`{"code":0,"data":{"id":53,"mid":27515310,"uname":"1qs314567","state":2,"type":2,"position":4,"url":"http://i0.hdslb.com/bfs/article/578a61e7caf47b5deaa80940b2806f1d9ce53dde.png","md5":"79d02f08c2b7b0d2b30a6b6a4f61c97e","info":"{\"width\":325,\"height\":50}","ctime":1499764110,"mtime":1499828335},"message":"","ttl":1}`)
err := d.SetWatermark(c, mid, state, ty, pos, ip)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestCreativeUploadMaterial(t *testing.T) {
convey.Convey("UploadMaterial", t, func(ctx convey.C) {
var (
c = context.Background()
editors = []*archive.Editor{}
aid = int64(10110826)
mid = int64(2089809)
ip = "127.0.0.1"
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
defer gock.OffAll()
httpMock("Post", d.uploadMaterialURL).Reply(200).JSON(`{"code":0,"data":""}`)
err := d.UploadMaterial(c, editors, aid, mid, ip)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}

View File

@@ -0,0 +1,32 @@
package creative
import (
"context"
"go-common/app/interface/main/videoup/conf"
bm "go-common/library/net/http/blademaster"
)
// Dao is elec dao.
type Dao struct {
c *conf.Config
httpW *bm.Client
setWatermarkURL string
uploadMaterialURL string
}
// New new a elec dao.
func New(c *conf.Config) (d *Dao) {
d = &Dao{
c: c,
httpW: bm.NewClient(c.HTTPClient.Write),
setWatermarkURL: c.Host.APICo + _setWatermark,
uploadMaterialURL: c.Host.APICo + _uploadMaterial,
}
return d
}
// Ping ping success.
func (d *Dao) Ping(c context.Context) (err error) {
return
}

View File

@@ -0,0 +1,45 @@
package creative
import (
"flag"
"go-common/app/interface/main/videoup/conf"
"os"
"strings"
"testing"
gock "gopkg.in/h2non/gock.v1"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.archive.videoup")
flag.Set("conf_token", "9772c9629b00ac09af29a23004795051")
flag.Set("tree_id", "2306")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
} else {
flag.Set("conf", "../cmd/videoup.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
m.Run()
os.Exit(0)
}
func httpMock(method, url string) *gock.Request {
r := gock.New(url)
r.Method = strings.ToUpper(method)
d.httpW.SetTransport(gock.DefaultTransport)
return r
}

View File

@@ -0,0 +1,48 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = ["dao.go"],
importpath = "go-common/app/interface/main/videoup/dao/dynamic",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/videoup/conf:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
go_test(
name = "go_default_test",
srcs = ["dao_test.go"],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/videoup/conf:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
"//vendor/gopkg.in/h2non/gock.v1:go_default_library",
],
)

View File

@@ -0,0 +1,86 @@
package dynamic
import (
"context"
"net/url"
"strconv"
"go-common/app/interface/main/videoup/conf"
"go-common/library/ecode"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
)
const (
_userCheckURI = "/lottery_svr/v0/lottery_svr/user_check"
_lotteryBindURI = "/lottery_svr/v0/lottery_svr/bind"
)
// Dao define
type Dao struct {
c *conf.Config
client *bm.Client
LotteryBindURL string
UserCheckURL string
}
// New init dao
func New(c *conf.Config) (d *Dao) {
d = &Dao{
c: c,
client: bm.NewClient(c.HTTPClient.Write),
LotteryBindURL: c.Host.Dynamic + _lotteryBindURI,
UserCheckURL: c.Host.Dynamic + _userCheckURI,
}
return
}
// LotteryBind fn
func (d *Dao) LotteryBind(c context.Context, lotteryID, aid, mid int64, ip string) (err error) {
params := url.Values{}
params.Set("lottery_id", strconv.FormatInt(lotteryID, 10))
params.Set("business_type", "8")
params.Set("business_id", strconv.FormatInt(aid, 10))
params.Set("sender_uid", strconv.FormatInt(mid, 10))
var res struct {
Code int `json:"code"`
}
if err = d.client.Post(c, d.LotteryBindURL, ip, params, &res); err != nil {
log.Error("LotteryBind url(%s) response(%s) error(%v)", d.LotteryBindURL+"?"+params.Encode(), res, err)
err = ecode.CreativeLotteryAPIErr
return
}
log.Info("LotteryBind d.LotteryBindURL url(%s)", d.LotteryBindURL+"?"+params.Encode(), res.Code)
if res.Code != 0 {
log.Error("LotteryBind url(%s) res(%v)", d.LotteryBindURL, res)
err = ecode.CreativeLotteryAPIErr
return
}
return
}
// UserCheck fn
func (d *Dao) UserCheck(c context.Context, mid int64, ip string) (ret int, err error) {
params := url.Values{}
params.Set("sender_uid", strconv.FormatInt(mid, 10))
params.Set("business_type", "8")
var res struct {
Code int `json:"code"`
Data struct {
Result int `json:"result"`
} `json:"data"`
}
if err = d.client.Get(c, d.UserCheckURL, ip, params, &res); err != nil {
log.Error("UserCheck url(%s) response(%s) error(%v)", d.UserCheckURL+"?"+params.Encode(), res, err)
err = ecode.CreativeLotteryAPIErr
return
}
log.Info("UserCheck d.UserCheckURL url(%s)", d.UserCheckURL+"?"+params.Encode(), res.Code)
if res.Code != 0 {
log.Error("UserCheck url(%s) res(%v)", d.UserCheckURL, res)
err = ecode.CreativeLotteryAPIErr
return
}
ret = res.Data.Result
return
}

View File

@@ -0,0 +1,87 @@
package dynamic
import (
"context"
"flag"
"go-common/app/interface/main/videoup/conf"
"os"
"strings"
"testing"
"github.com/smartystreets/goconvey/convey"
gock "gopkg.in/h2non/gock.v1"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.archive.videoup")
flag.Set("conf_token", "9772c9629b00ac09af29a23004795051")
flag.Set("tree_id", "2306")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
} else {
flag.Set("conf", "../cmd/videoup.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
m.Run()
os.Exit(0)
}
func httpMock(method, url string) *gock.Request {
r := gock.New(url)
r.Method = strings.ToUpper(method)
d.client.SetTransport(gock.DefaultTransport)
return r
}
func Test_LotteryBind(t *testing.T) {
convey.Convey("LotteryBind", t, func(ctx convey.C) {
var (
c = context.Background()
aid = int64(10110826)
mid = int64(2089809)
lid = int64(111)
ip = "127.0.0.1"
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
defer gock.OffAll()
httpMock("Post", d.LotteryBindURL).Reply(200).JSON(`{"code":0,"data":""}`)
err := d.LotteryBind(c, lid, aid, mid, ip)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func Test_UserCheck(t *testing.T) {
convey.Convey("UserCheck", t, func(ctx convey.C) {
var (
err error
c = context.Background()
mid = int64(2089809)
ip = "127.0.0.1"
ret int
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
defer gock.OffAll()
httpMock("GET", d.UserCheckURL).Reply(200).JSON(`{"code":0,"data":{"result":1}}`)
ret, err = d.UserCheck(c, mid, ip)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(ret, convey.ShouldNotBeNil)
})
})
})
}

View File

@@ -0,0 +1,54 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"api_test.go",
"dao_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/videoup/conf:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
"//vendor/gopkg.in/h2non/gock.v1:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"api.go",
"dao.go",
],
importpath = "go-common/app/interface/main/videoup/dao/elec",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/videoup/conf:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,71 @@
package elec
import (
"context"
"net/url"
"strconv"
"go-common/library/ecode"
"go-common/library/log"
)
const (
_showURL = "/internal/member/show"
_arcOpenURI = "/internal/archice/partin"
_arcCloseURI = "/internal/archice/exit"
)
// ArcShow return archive elec show, contains rank.
func (d *Dao) ArcShow(c context.Context, mid, aid int64, ip string) (show bool, err error) {
params := url.Values{}
params.Set("upmid", strconv.FormatInt(mid, 10))
params.Set("aid", strconv.FormatInt(aid, 10))
params.Set("nolist", "0")
var res struct {
Code int `json:"code"`
Data struct {
Show bool `json:"show"`
} `json:"data"`
}
if err = d.client.Get(c, d.showURI, ip, params, &res); err != nil {
log.Error("elec url(%s) error(%v)", d.showURI+"?"+params.Encode(), err)
err = ecode.CreativeElecErr
return
}
log.Info("ArcShow d.showURI url(%s)|res(%+v)", d.showURI+"?"+params.Encode(), res)
if res.Code != 0 {
log.Error("d.client.Get(%s) code(%d) error(%v)", d.showURI+"?"+params.Encode(), res.Code, err)
err = ecode.Int(res.Code)
return
}
show = res.Data.Show
return
}
// ArcUpdate arc open or close elec.
func (d *Dao) ArcUpdate(c context.Context, mid, aid int64, openElec int8, ip string) (err error) {
params := url.Values{}
params.Set("mid", strconv.FormatInt(mid, 10))
params.Set("aid", strconv.FormatInt(aid, 10))
var url string
if openElec == 1 {
url = d.arcOpenURL
} else if openElec == 0 {
url = d.arcCloseURL
}
var res struct {
Code int `json:"code"`
}
if err = d.client.Post(c, url, ip, params, &res); err != nil {
log.Error("d.client.Do uri(%s) aid(%d) mid(%d) orderID(%d) code(%d) error(%v)", url+"?"+params.Encode(), mid, aid, openElec, res.Code, err)
err = ecode.CreativeElecErr
return
}
log.Info("dealElec ArcUpdate url(%s)", url+"?"+params.Encode())
if res.Code != 0 {
log.Error("arc elec update state url(%s) res(%v); mid(%d), aid(%d), ip(%s), code(%d), error(%v)", url, res, mid, aid, ip, res.Code, err)
err = ecode.Int(res.Code)
return
}
return
}

View File

@@ -0,0 +1,52 @@
package elec
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
gock "gopkg.in/h2non/gock.v1"
)
func TestElecArcShow(t *testing.T) {
convey.Convey("ArcShow", t, func(ctx convey.C) {
var (
c = context.Background()
mid = int64(2089809)
aid = int64(10110826)
ip = "127.0.0.1"
err error
show bool
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
defer gock.OffAll()
httpMock("GET", d.showURI).Reply(200).JSON(`{"code":20004,"data":""}`)
show, err = d.ArcShow(c, mid, aid, ip)
ctx.Convey("Then err should be nil.show should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
ctx.So(show, convey.ShouldNotBeNil)
})
})
})
}
func TestElecArcUpdate(t *testing.T) {
convey.Convey("ArcUpdate", t, func(ctx convey.C) {
var (
c = context.Background()
mid = int64(2089809)
aid = int64(10110826)
openElec = int8(1)
ip = "127.0.0.1"
err error
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
defer gock.OffAll()
httpMock("GET", d.arcOpenURL).Reply(200).JSON(`{"code":20004,"data":""}`)
err = d.ArcUpdate(c, mid, aid, openElec, ip)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
})
})
})
}

View File

@@ -0,0 +1,38 @@
package elec
import (
"context"
"go-common/app/interface/main/videoup/conf"
bm "go-common/library/net/http/blademaster"
)
// Dao is elec dao.
type Dao struct {
c *conf.Config
// http
client *bm.Client
// uri
showURI string
arcOpenURL string
arcCloseURL string
}
// New new a elec dao.
func New(c *conf.Config) (d *Dao) {
d = &Dao{
c: c,
// http client
client: bm.NewClient(c.HTTPClient.Write),
// uri
showURI: c.Host.Elec + _showURL,
arcOpenURL: c.Host.Elec + _arcOpenURI,
arcCloseURL: c.Host.Elec + _arcCloseURI,
}
return d
}
// Ping ping success.
func (d *Dao) Ping(c context.Context) (err error) {
return
}

View File

@@ -0,0 +1,45 @@
package elec
import (
"flag"
"go-common/app/interface/main/videoup/conf"
"os"
"strings"
"testing"
gock "gopkg.in/h2non/gock.v1"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.archive.videoup")
flag.Set("conf_token", "9772c9629b00ac09af29a23004795051")
flag.Set("tree_id", "2306")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
} else {
flag.Set("conf", "../cmd/videoup.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
m.Run()
os.Exit(0)
}
func httpMock(method, url string) *gock.Request {
r := gock.New(url)
r.Method = strings.ToUpper(method)
d.client.SetTransport(gock.DefaultTransport)
return r
}

View File

@@ -0,0 +1,50 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = ["dao_test.go"],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/videoup/conf:go_default_library",
"//app/interface/main/videoup/model/archive:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
"//vendor/gopkg.in/h2non/gock.v1:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = ["dao.go"],
importpath = "go-common/app/interface/main/videoup/dao/filter",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/videoup/conf:go_default_library",
"//app/interface/main/videoup/model/archive:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,97 @@
package filter
import (
"context"
"net/url"
"go-common/app/interface/main/videoup/conf"
"go-common/app/interface/main/videoup/model/archive"
"go-common/library/ecode"
"go-common/library/log"
httpx "go-common/library/net/http/blademaster"
)
const (
_postFilter = "/x/internal/filter/post"
_postMFilter = "/x/internal/filter/mpost"
)
// Dao define
type Dao struct {
c *conf.Config
client *httpx.Client
postFilterURI string
postMFilterURI string
}
// New init dao
func New(c *conf.Config) (d *Dao) {
d = &Dao{
c: c,
client: httpx.NewClient(c.HTTPClient.FastRead),
postFilterURI: c.Host.APICo + _postFilter,
postMFilterURI: c.Host.APICo + _postMFilter,
}
return
}
// VideoFilter fn
func (d *Dao) VideoFilter(c context.Context, msg, ip string) (resData *archive.FilterData, hit []string, err error) {
params := url.Values{}
params.Set("area", "video_submit")
params.Set("msg", msg)
var res struct {
Code int `json:"code"`
Data *archive.FilterData `json:"data"`
Message string `json:"message"`
}
if err = d.client.Post(c, d.postFilterURI, ip, params, &res); err != nil {
log.Error("d.client.Post uri(%s) msg(%s) ip(%s)", d.postFilterURI+"?"+params.Encode(), msg, ip, err)
err = ecode.VideoupFilterServiceErr
return
}
log.Info("VideoupFilterService url(%s)", d.postFilterURI+"?"+params.Encode())
if res.Code != 0 {
log.Error("d.client.Post uri(%s) msg(%s) ip(%s)", d.postFilterURI+"?"+params.Encode(), msg, ip, err)
err = ecode.VideoupFilterServiceErr
return
}
hit = res.Data.Hit
resData = res.Data
return
}
// VideoMultiFilter 批量过滤
func (d *Dao) VideoMultiFilter(c context.Context, msgs []string, ip string) (resDatas []*archive.FilterData, hit []string, err error) {
if len(msgs) == 0 {
return
}
params := url.Values{}
params.Set("area", "video_submit")
for _, v := range msgs {
params.Add("msg", v)
}
var res struct {
Code int `json:"code"`
Data []*archive.FilterData `json:"data"`
Message string `json:"message"`
}
if err = d.client.Post(c, d.postMFilterURI, ip, params, &res); err != nil {
log.Error("d.client.Post uri(%s) msg(%v) ip(%s)", d.postMFilterURI+"?"+params.Encode(), msgs, ip, err)
err = ecode.VideoupFilterServiceErr
return
}
log.Info("VideoupFilterService url(%s)", d.postMFilterURI+"?"+params.Encode())
if res.Code != 0 {
log.Error("d.client.Post uri(%s) msg(%v) ip(%s)", d.postMFilterURI+"?"+params.Encode(), msgs, ip, err)
err = ecode.VideoupFilterServiceErr
return
}
resDatas = res.Data
for _, v := range resDatas {
if len(v.Hit) != 0 {
hit = append(hit, v.Hit...)
}
}
return
}

View File

@@ -0,0 +1,93 @@
package filter
import (
"context"
"flag"
"go-common/app/interface/main/videoup/conf"
"go-common/app/interface/main/videoup/model/archive"
"os"
"strings"
"testing"
. "github.com/smartystreets/goconvey/convey"
gock "gopkg.in/h2non/gock.v1"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.archive.videoup")
flag.Set("conf_token", "9772c9629b00ac09af29a23004795051")
flag.Set("tree_id", "2306")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
} else {
flag.Set("conf", "../../cmd/videoup.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
m.Run()
os.Exit(0)
}
func httpMock(method, url string) *gock.Request {
r := gock.New(url)
r.Method = strings.ToUpper(method)
d.client.SetTransport(gock.DefaultTransport)
return r
}
func Test_VideoFilter(t *testing.T) {
Convey("VideoFilter", t, func(ctx C) {
var (
err error
c = context.Background()
ip = "127.0.0.1"
msg = "iamamsg"
resData *archive.FilterData
hit []string
)
ctx.Convey("When everything goes positive", func(ctx C) {
defer gock.OffAll()
httpMock("Post", d.postFilterURI).Reply(200).JSON(`{"code":21064,"data":""}`)
resData, hit, err = d.VideoFilter(c, msg, ip)
ctx.Convey("Then err should be nil.", func(ctx C) {
ctx.So(err, ShouldNotBeNil)
ctx.So(resData, ShouldBeNil)
ctx.So(hit, ShouldBeNil)
})
})
})
}
func TestDao_VideoMultiFilter(t *testing.T) {
Convey("VideoFilter", t, func(ctx C) {
var (
err error
c = context.Background()
ip = "127.0.0.1"
msgs = []string{"李可强"}
resData []*archive.FilterData
hit []string
)
ctx.Convey("When everything goes positive", func(ctx C) {
defer gock.OffAll()
httpMock("Post", d.postMFilterURI).Reply(200).JSON(`{"code":0,"message":"0","ttl":1,"data":[{"msg":"李可强","level":0,"typeid":[],"hit":[],"limit":0,"ai":{"scores":null,"threshold":0,"note":""}}]}`)
resData, hit, err = d.VideoMultiFilter(c, msgs, ip)
ctx.Convey("Then err should be nil.", func(ctx C) {
ctx.So(err, ShouldBeNil)
ctx.So(resData, ShouldNotBeNil)
ctx.So(hit, ShouldBeNil)
})
})
})
}

View File

@@ -0,0 +1,50 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = ["dao_test.go"],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/videoup/conf:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
"//vendor/gopkg.in/h2non/gock.v1:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = ["dao.go"],
importpath = "go-common/app/interface/main/videoup/dao/geetest",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/videoup/conf:go_default_library",
"//app/interface/main/videoup/model/geetest:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/metadata:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,67 @@
package geetest
import (
"context"
"net/http"
"net/url"
"strconv"
"strings"
"time"
"go-common/app/interface/main/videoup/conf"
"go-common/app/interface/main/videoup/model/geetest"
"go-common/library/ecode"
"go-common/library/log"
httpx "go-common/library/net/http/blademaster"
"go-common/library/net/metadata"
)
const (
_validate = "/validate.php"
)
// Dao is account dao.
type Dao struct {
c *conf.Config
// url
validateURI string
// http client
clientX *httpx.Client
}
// New new a dao.
func New(c *conf.Config) (d *Dao) {
d = &Dao{
c: c,
validateURI: c.Host.Geetest + _validate,
clientX: httpx.NewClient(c.HTTPClient.Read),
}
return
}
// Validate recheck the challenge code and get to seccode
func (d *Dao) Validate(c context.Context, challenge, seccode, clientType, captchaID string, mid int64) (res *geetest.ValidateRes, err error) {
params := url.Values{}
params.Set("seccode", seccode)
params.Set("challenge", challenge)
params.Set("captchaid", captchaID)
params.Set("client_type", clientType)
params.Set("ip_address", metadata.String(c, metadata.RemoteIP))
params.Set("json_format", "1")
params.Set("sdk", "golang_3.0.0")
params.Set("user_id", strconv.FormatInt(mid, 10))
params.Set("timestamp", strconv.FormatInt(time.Now().Unix(), 10))
req, err := http.NewRequest("POST", d.validateURI, strings.NewReader(params.Encode()))
if err != nil {
log.Error("http.NewRequest error(%v) | uri(%s) params(%s)", err, d.validateURI, params.Encode())
err = ecode.CreativeGeetestAPIErr
return
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
if err = d.clientX.Do(c, req, &res); err != nil {
log.Error("d.client.Do error(%v)", err)
err = ecode.CreativeGeetestAPIErr
return
}
return
}

View File

@@ -0,0 +1,69 @@
package geetest
import (
"context"
"flag"
"go-common/app/interface/main/videoup/conf"
"os"
"strings"
"testing"
"github.com/smartystreets/goconvey/convey"
gock "gopkg.in/h2non/gock.v1"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.archive.videoup")
flag.Set("conf_token", "9772c9629b00ac09af29a23004795051")
flag.Set("tree_id", "2306")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
} else {
flag.Set("conf", "../cmd/videoup.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
m.Run()
os.Exit(0)
}
func httpMock(method, url string) *gock.Request {
r := gock.New(url)
r.Method = strings.ToUpper(method)
d.clientX.SetTransport(gock.DefaultTransport)
return r
}
func Test_Validate(t *testing.T) {
convey.Convey("Validate", t, func(ctx convey.C) {
var (
err error
c = context.Background()
mid = int64(2089809)
challenge = "iamchallenge"
seccode = "iamseccode"
clientType = "iamclientType"
captchaID = "iamcaptchaID"
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
defer gock.OffAll()
httpMock("Post", d.validateURI).Reply(200).JSON(`{"code":20054,"data":""}`)
_, err = d.Validate(c, challenge, seccode, clientType, captchaID, mid)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}

View File

@@ -0,0 +1,54 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"dao_test.go",
"mission_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/videoup/conf:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"dao.go",
"mission.go",
],
importpath = "go-common/app/interface/main/videoup/dao/mission",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/videoup/conf:go_default_library",
"//app/interface/main/videoup/model/mission:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,34 @@
package mission
import (
"context"
"go-common/app/interface/main/videoup/conf"
bm "go-common/library/net/http/blademaster"
)
// Dao is mission dao.
type Dao struct {
c *conf.Config
httpR *bm.Client
missAllURL string
actOnlineByTypeURL string
}
// New new a mission dao.
func New(c *conf.Config) (d *Dao) {
d = &Dao{
c: c,
// client
httpR: bm.NewClient(c.HTTPClient.Read),
// uri
missAllURL: c.Host.WWW + _msAllURL,
actOnlineByTypeURL: c.Host.WWW + _actOnlineByTypeURI,
}
return d
}
// Ping ping success.
func (d *Dao) Ping(c context.Context) (err error) {
return
}

View File

@@ -0,0 +1,35 @@
package mission
import (
"flag"
"go-common/app/interface/main/videoup/conf"
"os"
"testing"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.archive.videoup")
flag.Set("conf_token", "9772c9629b00ac09af29a23004795051")
flag.Set("tree_id", "2306")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
} else {
flag.Set("conf", "../cmd/videoup.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
m.Run()
os.Exit(0)
}

View File

@@ -0,0 +1,85 @@
package mission
import (
"context"
"net/url"
"strconv"
"time"
"go-common/app/interface/main/videoup/model/mission"
"go-common/library/ecode"
"go-common/library/log"
)
const (
_msAllURL = "/activity/list/videoall"
_actOnlineByTypeURI = "/activity/online/by/type"
)
// Missions get missions.
func (d *Dao) Missions(c context.Context) (mm map[int]*mission.Mission, err error) {
var res struct {
Code int `json:"code"`
Data []*struct {
ID int `json:"id"`
Name string `json:"name"`
ETime string `json:"etime"`
Tags string `json:"tags"`
} `json:"data"`
}
if err = d.httpR.Get(c, d.missAllURL, "", nil, &res); err != nil {
log.Error("videoup mission list error(%v) | missAllURL(%s)", err, d.missAllURL)
return
}
if res.Code != 0 {
log.Error("videoup mission list res.Code nq zero error(%v) | missAllURL(%s) res(%v)", res.Code, d.missAllURL, res)
err = ecode.CreativeActivityErr
return
}
mm = make(map[int]*mission.Mission, len(res.Data))
for _, m := range res.Data {
miss := &mission.Mission{}
miss.ID = m.ID
miss.Name = m.Name
miss.ETime, _ = time.Parse("2006-01-02 15:04:05", m.ETime)
miss.Tags = m.Tags
mm[miss.ID] = miss
}
return
}
// MissionOnlineByTid fn, 这里默认会返回所有无投稿分区限制要求的通用活动,在做校验的时候允许此类活动投稿到任意分区
func (d *Dao) MissionOnlineByTid(c context.Context, tid int16) (mm map[int]*mission.Mission, err error) {
var res struct {
Code int `json:"code"`
Data []*struct {
ID int `json:"id"`
Name string `json:"name"`
ETime string `json:"etime"`
Tags string `json:"tags"`
} `json:"data"`
}
mm = make(map[int]*mission.Mission)
params := url.Values{}
params.Set("type", strconv.Itoa(int(tid)))
params.Set("plat", "1")
if err = d.httpR.Get(c, d.actOnlineByTypeURL, "", params, &res); err != nil {
log.Error("videoup actOnlineByTypeURL error(%v) | actOnlineByTypeURL(%s)", err, d.actOnlineByTypeURL+"?"+params.Encode())
err = ecode.CreativeActivityErr
return
}
if res.Code != 0 {
log.Error("videoup actOnlineByTypeURL res.Code nq zero error(%v) | actOnlineByTypeURL(%s) res(%v)", res.Code, d.actOnlineByTypeURL+"?"+params.Encode(), res)
err = ecode.CreativeActivityErr
return
}
for _, m := range res.Data {
miss := &mission.Mission{}
miss.ID = m.ID
miss.Name = m.Name
miss.ETime, _ = time.Parse("2006-01-02 15:04:05", m.ETime)
miss.Tags = m.Tags
mm[miss.ID] = miss
}
return
}

View File

@@ -0,0 +1,39 @@
package mission
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestMissionMissions(t *testing.T) {
convey.Convey("Missions", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
mm, err := d.Missions(c)
ctx.Convey("Then err should be nil.mm should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(mm, convey.ShouldNotBeNil)
})
})
})
}
func TestMissionMissionOnlineByTid(t *testing.T) {
convey.Convey("MissionOnlineByTid", t, func(ctx convey.C) {
var (
c = context.Background()
tid = int16(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
mm, err := d.MissionOnlineByTid(c, tid)
ctx.Convey("Then err should be nil.mm should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(mm, convey.ShouldNotBeNil)
})
})
})
}

View File

@@ -0,0 +1,49 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = ["dao_test.go"],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/videoup/conf:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
"//vendor/gopkg.in/h2non/gock.v1:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = ["dao.go"],
importpath = "go-common/app/interface/main/videoup/dao/order",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/videoup/conf:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/time:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,146 @@
package order
import (
"context"
"net/url"
"strconv"
"go-common/app/interface/main/videoup/conf"
"go-common/library/ecode"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
xtime "go-common/library/time"
)
const (
_executeOrders = "/api/open_api/v2/execute_orders"
_ups = "/api/open_api/v2/ups"
_launchtime = "/api/open_api/v2/execute_orders/launch_time"
_useExeOrder = "/api/open_api/v2/execute_orders/use"
)
// Dao define
type Dao struct {
c *conf.Config
// http
client *bm.Client
// uri
executeOrdersURI string
upsURI string
launchTimeURI string
useExeOrderURI string
}
// New init dao
func New(c *conf.Config) (d *Dao) {
d = &Dao{
c: c,
client: bm.NewClient(c.HTTPClient.Chaodian),
executeOrdersURI: c.Host.Chaodian + _executeOrders,
upsURI: c.Host.Chaodian + _ups,
launchTimeURI: c.Host.Chaodian + _launchtime,
useExeOrderURI: c.Host.Chaodian + _useExeOrder,
}
return
}
// ExecuteOrders execute order ids.
func (d *Dao) ExecuteOrders(c context.Context, mid int64, ip string) (orderIds map[int64]int64, err error) {
params := url.Values{}
params.Set("up_mid", strconv.FormatInt(mid, 10))
var res struct {
Code int `json:"code"`
Orders []*struct {
ExeOdID int64 `json:"execute_order_id"`
} `json:"data"`
}
if err = d.client.Get(c, d.executeOrdersURI, ip, params, &res); err != nil {
log.Error("chaodian url(%s) response(%+v) error(%v)", d.executeOrdersURI+"?"+params.Encode(), res, err)
err = ecode.VideoupOrderAPIErr
return
}
log.Info("chaodian url(%s)", d.executeOrdersURI+"?"+params.Encode())
if res.Code != 0 {
log.Error("chaodian url(%s) res(%v)", d.executeOrdersURI, res)
err = ecode.VideoupOrderAPIErr
return
}
orderIds = make(map[int64]int64)
for _, v := range res.Orders {
orderIds[v.ExeOdID] = v.ExeOdID
}
return
}
// Ups order ups.
func (d *Dao) Ups(c context.Context) (ups map[int64]int64, err error) {
params := url.Values{}
var res struct {
Code int `json:"code"`
Ups []int64 `json:"data"`
}
if err = d.client.Get(c, d.upsURI, "", params, &res); err != nil {
log.Error("chaodian url(%s) response(%+v) error(%v)", d.upsURI+"?"+params.Encode(), res, err)
err = ecode.VideoupOrderAPIErr
return
}
log.Info("chaodian url(%s)", d.upsURI+"?"+params.Encode())
if res.Code != 0 {
log.Error("chaodian url(%s) res(%v)", d.upsURI, res)
err = ecode.VideoupOrderAPIErr
return
}
ups = make(map[int64]int64)
for _, v := range res.Ups {
ups[v] = v
}
return
}
// BindOrder bind order with up.
func (d *Dao) BindOrder(c context.Context, mid, aid, orderID int64, ip string) (err error) {
params := url.Values{}
params.Set("execute_order_id", strconv.FormatInt(orderID, 10))
params.Set("av_id", strconv.FormatInt(aid, 10))
var res struct {
Code int `json:"code"`
Message string `json:"message"`
}
if err = d.client.Post(c, d.useExeOrderURI, ip, params, &res); err != nil {
log.Error("d.client.Do uri(%s) aid(%d) mid(%d) orderID(%d) error(%v)", d.useExeOrderURI+"?"+params.Encode(), mid, aid, orderID, err)
err = ecode.VideoupOrderAPIErr
return
}
log.Info("chaodian url(%s)", d.useExeOrderURI+"?"+params.Encode())
if res.Code != 0 {
log.Error("d.client.Do uri(%s) aid(%d) mid(%d) orderID(%d) res.code(%d) error(%v)", d.useExeOrderURI+"?"+params.Encode(), mid, aid, orderID, res.Code, err)
err = ecode.VideoupOrderAPIErr
return
}
return
}
// PubTime publish time from order id.
func (d *Dao) PubTime(c context.Context, mid, orderID int64, ip string) (ptime xtime.Time, err error) {
params := url.Values{}
params.Set("execute_order_id", strconv.FormatInt(orderID, 10))
var res struct {
Code int `json:"code"`
Data struct {
BeginDate xtime.Time `json:"begin_date"`
} `json:"data"`
}
if err = d.client.Get(c, d.launchTimeURI, "", params, &res); err != nil {
log.Error("chaodian url(%s) response(%+v) error(%v)", d.launchTimeURI+"?"+params.Encode(), res, err)
err = ecode.VideoupOrderAPIErr
return
}
log.Info("chaodian url(%s)", d.launchTimeURI+"?"+params.Encode())
if res.Code != 0 {
log.Error("chaodian url(%s) res(%v)", d.launchTimeURI, res)
err = ecode.VideoupOrderAPIErr
return
}
ptime = res.Data.BeginDate
return
}

View File

@@ -0,0 +1,124 @@
package order
import (
"context"
"flag"
"go-common/app/interface/main/videoup/conf"
"os"
"strings"
"testing"
"github.com/smartystreets/goconvey/convey"
gock "gopkg.in/h2non/gock.v1"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.archive.videoup")
flag.Set("conf_token", "9772c9629b00ac09af29a23004795051")
flag.Set("tree_id", "2306")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
} else {
flag.Set("conf", "../cmd/videoup.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
m.Run()
os.Exit(0)
}
func httpMock(method, url string) *gock.Request {
r := gock.New(url)
r.Method = strings.ToUpper(method)
d.client.SetTransport(gock.DefaultTransport)
return r
}
func Test_PubTime(t *testing.T) {
convey.Convey("PubTime", t, func(ctx convey.C) {
var (
err error
c = context.Background()
mid = int64(2089809)
orderID = int64(111)
ip = "127.0.0.1"
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
defer gock.OffAll()
httpMock("Post", d.launchTimeURI).Reply(200).JSON(`{"code":21022,"data":""}`)
_, err = d.PubTime(c, mid, orderID, ip)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
})
})
})
}
func Test_BindOrder(t *testing.T) {
convey.Convey("BindOrder", t, func(ctx convey.C) {
var (
err error
c = context.Background()
mid = int64(2089809)
aid = int64(10110826)
orderID = int64(111)
ip = "127.0.0.1"
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
defer gock.OffAll()
httpMock("Post", d.useExeOrderURI).Reply(200).JSON(`{"code":21022,"data":""}`)
err = d.BindOrder(c, mid, aid, orderID, ip)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
})
})
})
}
func Test_Ups(t *testing.T) {
convey.Convey("Ups", t, func(ctx convey.C) {
var (
err error
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
defer gock.OffAll()
httpMock("GET", d.upsURI).Reply(200).JSON(`{"code":21022,"data":""}`)
_, err = d.Ups(c)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
})
})
})
}
func Test_ExecuteOrders(t *testing.T) {
convey.Convey("ExecuteOrders", t, func(ctx convey.C) {
var (
err error
c = context.Background()
mid = int64(2089809)
ip = "127.0.0.1"
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
defer gock.OffAll()
httpMock("GET", d.executeOrdersURI).Reply(200).JSON(`{"code":21022,"data":""}`)
_, err = d.ExecuteOrders(c, mid, ip)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
})
})
})
}

View File

@@ -0,0 +1,56 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"api_test.go",
"dao_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/videoup/conf:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"api.go",
"dao.go",
],
importpath = "go-common/app/interface/main/videoup/dao/pay",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/videoup/conf:go_default_library",
"//app/interface/main/videoup/model/archive:go_default_library",
"//library/database/elastic:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/queue/databus/report:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,104 @@
package pay
import (
"context"
"go-common/app/interface/main/videoup/model/archive"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/queue/databus/report"
"net/url"
"strconv"
)
const (
_assRegURI = "/x/internal/ugcpay/asset/register"
_assURI = "/x/internal/ugcpay/asset"
)
// AssReg 注册付费内容
func (d *Dao) AssReg(c context.Context, mid, aid int64, bp int, ip string) (err error) {
params := url.Values{}
params.Set("mid", strconv.FormatInt(mid, 10))
params.Set("oid", strconv.FormatInt(aid, 10))
params.Set("price", strconv.Itoa(bp*100))
params.Set("otype", "archive")
params.Set("platform", "web")
params.Set("currency", "bp")
var res struct {
Code int `json:"code"`
}
if err = d.client.Post(c, d.assRegURI, ip, params, &res); err != nil {
log.Error("d.client.Do uri(%s) aid(%d) mid(%d) bp(%d) code(%d) error(%v)", d.assRegURI+"?"+params.Encode(), mid, aid, bp, res.Code, err)
err = ecode.VideoupPayAPIErr
return
}
log.Info("UgcPay AssReg url(%s)", d.assRegURI+"?"+params.Encode())
if res.Code != 0 {
log.Error("UgcPay asset register url(%s) res(%+v); mid(%d),aid(%d),bp(%d),ip(%s),code(%d),error(%v)", d.assRegURI, res, mid, aid, bp, ip, res.Code, err)
err = ecode.VideoupPayAPIErr
return
}
return
}
// Ass 查看付费信息
// UGCPayAssetInvalid = New(88001) // ugcpay 内容无效
func (d *Dao) Ass(c context.Context, aid int64, ip string) (assert *archive.PayAsset, registed bool, err error) {
params := url.Values{}
params.Set("oid", strconv.FormatInt(aid, 10))
params.Set("otype", "archive")
params.Set("currency", "bp")
var res struct {
Code int `json:"code"`
Data *archive.PayAsset `json:"data"`
}
if err = d.client.Get(c, d.assURI, ip, params, &res); err != nil {
log.Error("d.client.Do uri(%s) aid(%d) code(%d) error(%v)", d.assURI+"?"+params.Encode(), aid, res.Code, err)
err = ecode.VideoupPayAPIErr
return
}
log.Info("UgcPay AssView url(%s)", d.assURI+"?"+params.Encode())
if res.Code != 0 {
if res.Code == ecode.UGCPayAssetInvalid.Code() {
log.Warn("UgcPay asset UGCPayAssetInvalid url(%s) res(%+v); aid(%d),ip(%s),error(%v)", d.assURI, res, aid, ip, err)
return nil, false, nil
}
err = ecode.VideoupPayAPIErr
log.Error("VideoupPayAPIErr AssView url(%s) res(%+v); aid(%d),ip(%s),code(%d),error(%v)", d.assURI, res, aid, ip, res.Code, err)
return
}
if res.Data != nil {
assert = res.Data
assert.Price = res.Data.Price / 100
registed = true
}
return
}
// UserAcceptProtocol fn: 判断当前的协议是否已经同意过,前端必须传递当前的投稿协议ID
func (d *Dao) UserAcceptProtocol(c context.Context, protocolID string, mid int64) (accept bool, err error) {
type Res struct {
Page *struct {
Num int `json:"num"`
Size int `json:"size"`
Total int `json:"total"`
} `json:"page"`
Result []*report.UserActionLog `json:"result"`
}
res := &Res{}
r := d.es.NewRequest("log_user_action")
r.Index("log_user_action_83_all").Pn(1).Ps(2000).OrderScoreFirst(true)
r.WhereEq("str_0", protocolID).WhereEq("mid", mid)
r.Order("ctime", "desc")
log.Info("UserAcceptProtocol params(%s)", r.Params())
if err = r.Scan(c, res); err != nil {
log.Error("UserAcceptProtocol r.Scan params(%s)|error(%v)", r.Params(), err)
return
}
if res.Page.Total == 0 {
accept = false
} else {
accept = true
}
return
}

View File

@@ -0,0 +1,61 @@
package pay
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestPayAssReg(t *testing.T) {
convey.Convey("AssReg", t, func(ctx convey.C) {
var (
c = context.Background()
mid = int64(2089809)
aid = int64(10110826)
bp = int(5)
ip = "127.0.0.1"
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.AssReg(c, mid, aid, bp, ip)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestPayAss(t *testing.T) {
convey.Convey("Ass", t, func(ctx convey.C) {
var (
c = context.Background()
aid = int64(10110826)
ip = "127.0.0.1"
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
assert, registed, err := d.Ass(c, aid, ip)
ctx.Convey("Then err should be nil.assert,registed should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(registed, convey.ShouldNotBeNil)
ctx.So(assert, convey.ShouldNotBeNil)
})
})
})
}
func TestPayUserAcceptProtocol(t *testing.T) {
convey.Convey("UserAcceptProtocol", t, func(ctx convey.C) {
var (
c = context.Background()
protocolID = "iamhashstring"
mid = int64(2089809)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
accept, err := d.UserAcceptProtocol(c, protocolID, mid)
ctx.Convey("Then err should be nil.accept should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(accept, convey.ShouldNotBeNil)
})
})
})
}

View File

@@ -0,0 +1,38 @@
package pay
import (
"context"
"go-common/app/interface/main/videoup/conf"
"go-common/library/database/elastic"
bm "go-common/library/net/http/blademaster"
)
// Dao str
type Dao struct {
c *conf.Config
client *bm.Client
assRegURI string
assURI string
es *elastic.Elastic
}
// New fn
func New(c *conf.Config) (d *Dao) {
d = &Dao{
c: c,
client: bm.NewClient(c.HTTPClient.Write),
assRegURI: c.Host.APICo + _assRegURI,
assURI: c.Host.APICo + _assURI,
es: elastic.NewElastic(&elastic.Config{
Host: c.Host.MainSearch,
HTTPClient: c.HTTPClient.Read,
}),
}
return d
}
// Ping fn
func (d *Dao) Ping(c context.Context) (err error) {
return
}

View File

@@ -0,0 +1,35 @@
package pay
import (
"flag"
"go-common/app/interface/main/videoup/conf"
"os"
"testing"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.archive.videoup")
flag.Set("conf_token", "9772c9629b00ac09af29a23004795051")
flag.Set("tree_id", "2306")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
} else {
flag.Set("conf", "../cmd/videoup.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
m.Run()
os.Exit(0)
}

View File

@@ -0,0 +1,53 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = [
"dao.go",
"subtitle.go",
],
importpath = "go-common/app/interface/main/videoup/dao/subtitle",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/dm2/model:go_default_library",
"//app/interface/main/dm2/rpc/client:go_default_library",
"//app/interface/main/videoup/conf:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
go_test(
name = "go_default_test",
srcs = [
"dao_test.go",
"subtitle_test.go",
],
embed = [":go_default_library"],
tags = ["automanaged"],
deps = [
"//app/interface/main/videoup/conf:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)

View File

@@ -0,0 +1,21 @@
package subtitle
import (
"go-common/app/interface/main/dm2/rpc/client"
"go-common/app/interface/main/videoup/conf"
)
// Dao fn
type Dao struct {
c *conf.Config
sub *client.Service
}
// New fn
func New(c *conf.Config) (d *Dao) {
d = &Dao{
c: c,
sub: client.New(c.SubRPC),
}
return
}

View File

@@ -0,0 +1,35 @@
package subtitle
import (
"flag"
"go-common/app/interface/main/videoup/conf"
"os"
"testing"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.archive.videoup")
flag.Set("conf_token", "9772c9629b00ac09af29a23004795051")
flag.Set("tree_id", "2306")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
} else {
flag.Set("conf", "../cmd/videoup.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
m.Run()
os.Exit(0)
}

View File

@@ -0,0 +1,22 @@
package subtitle
import (
"context"
"go-common/app/interface/main/dm2/model"
"go-common/library/ecode"
"go-common/library/log"
)
// Update fn
func (d *Dao) Update(c context.Context, aid int64, open bool, lan string) (err error) {
var arg = &model.ArgSubtitleAllowSubmit{
Aid: aid,
AllowSubmit: open,
Lan: lan,
}
if err = d.sub.SubtitleSujectSubmit(c, arg); err != nil {
log.Error("d.sub.SubtitleSujectSubmit (%+v) error(%v)", arg, err)
err = ecode.CreativeSubtitleAPIErr
}
return
}

View File

@@ -0,0 +1,25 @@
package subtitle
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestSubtitleUpdate(t *testing.T) {
convey.Convey("Update", t, func(ctx convey.C) {
var (
c = context.Background()
aid = int64(10110826)
open bool
lan = ""
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.Update(c, aid, open, lan)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}

View File

@@ -0,0 +1,55 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"dao_test.go",
"tag_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/videoup/conf:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
"//vendor/gopkg.in/h2non/gock.v1:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"dao.go",
"tag.go",
],
importpath = "go-common/app/interface/main/videoup/dao/tag",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/creative/model/tag:go_default_library",
"//app/interface/main/videoup/conf:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,36 @@
package tag
import (
"context"
"go-common/app/interface/main/videoup/conf"
bm "go-common/library/net/http/blademaster"
)
// Dao is elec dao.
type Dao struct {
c *conf.Config
// http
httpW *bm.Client
// uri
upBindURL string
TagCheckURL string
}
// New new a elec dao.
func New(c *conf.Config) (d *Dao) {
d = &Dao{
c: c,
// http client
httpW: bm.NewClient(c.HTTPClient.Write),
// uri
upBindURL: c.Host.Tag + _upBindURI,
TagCheckURL: c.Host.Tag + _tagCheck,
}
return d
}
// Ping ping success.
func (d *Dao) Ping(c context.Context) (err error) {
return
}

View File

@@ -0,0 +1,45 @@
package tag
import (
"flag"
"go-common/app/interface/main/videoup/conf"
"os"
"strings"
"testing"
gock "gopkg.in/h2non/gock.v1"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.archive.videoup")
flag.Set("conf_token", "9772c9629b00ac09af29a23004795051")
flag.Set("tree_id", "2306")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
} else {
flag.Set("conf", "../cmd/videoup.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
m.Run()
os.Exit(0)
}
func httpMock(method, url string) *gock.Request {
r := gock.New(url)
r.Method = strings.ToUpper(method)
d.httpW.SetTransport(gock.DefaultTransport)
return r
}

View File

@@ -0,0 +1,62 @@
package tag
import (
"context"
"go-common/app/interface/main/creative/model/tag"
"go-common/library/ecode"
"go-common/library/log"
"net/url"
"strconv"
)
const (
_upBindURI = "/x/internal/tag/archive/upbind"
_tagCheck = "/x/internal/tag/check"
)
// UpBind update bind tag.
func (d *Dao) UpBind(c context.Context, mid, aid int64, tags, regionName, ip string) (err error) {
params := url.Values{}
params.Set("mid", strconv.FormatInt(mid, 10))
params.Set("aid", strconv.FormatInt(aid, 10))
params.Set("tnames", tags)
params.Set("region_name", regionName)
var res struct {
Code int `json:"code"`
}
if err = d.httpW.Post(c, d.upBindURL, ip, params, &res); err != nil {
log.Error("d.httpW.Post(%s) error(%v)", d.upBindURL+"?"+params.Encode(), err)
err = ecode.CreativeTagErr
return
}
log.Info("url(%s) code(%d)", d.upBindURL+"?"+params.Encode(), res.Code)
if res.Code != 0 {
log.Error("url(%s) code(%d)", d.upBindURL+"?"+params.Encode(), res.Code)
err = ecode.CreativeTagErr
}
return
}
// TagCheck tag check
func (d *Dao) TagCheck(c context.Context, mid int64, tagName string) (t *tag.Tag, err error) {
var res struct {
Code int `json:"code"`
Data *tag.Tag `json:"data"`
}
params := url.Values{}
params.Set("tag_name", tagName)
params.Set("mid", strconv.FormatInt(mid, 10))
if err = d.httpW.Get(c, d.TagCheckURL, "", params, &res); err != nil {
log.Error("TagCheck url(%s) p(%+v) response(%s) error(%v)", d.TagCheckURL, params.Encode(), res, err)
err = ecode.CreativeTagErr
return
}
log.Info("TagCheck mid(%d) url(%s) res(%v)", mid, d.TagCheckURL, res)
if res.Code != 0 {
log.Error("TagCheck url(%s) res(%v)", d.TagCheckURL, res)
err = ecode.Int(res.Code)
return
}
t = res.Data
return
}

View File

@@ -0,0 +1,50 @@
package tag
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
gock "gopkg.in/h2non/gock.v1"
)
func TestTagUpBind(t *testing.T) {
convey.Convey("UpBind", t, func(ctx convey.C) {
var (
err error
c = context.Background()
mid = int64(2089809)
aid = int64(10110826)
tags = "LOL"
regionName = "游戏"
ip = "127.0.0.1"
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
defer gock.OffAll()
httpMock("POST", d.upBindURL).Reply(200).JSON(`{"code":20042,"data":""}`)
err = d.UpBind(c, mid, aid, tags, regionName, ip)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
})
})
})
}
func TestTagCheck(t *testing.T) {
convey.Convey("TagCheck", t, func(ctx convey.C) {
var (
c = context.Background()
mid = int64(2089809)
tagName = "LOL"
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
defer gock.OffAll()
httpMock("Get", d.TagCheckURL).Reply(200).JSON(`{"code":20042,"data":""}`)
no, err := d.TagCheck(c, mid, tagName)
ctx.Convey("Then err should be nil.no should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
ctx.So(no, convey.ShouldBeNil)
})
})
})
}

View File

@@ -0,0 +1,48 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"app.go",
"client.go",
"creator.go",
"http.go",
"local.go",
"web.go",
"web_v2.go",
],
importpath = "go-common/app/interface/main/videoup/http",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/videoup/conf:go_default_library",
"//app/interface/main/videoup/model/archive:go_default_library",
"//app/interface/main/videoup/service:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/http/blademaster/middleware/antispam:go_default_library",
"//library/net/http/blademaster/middleware/auth:go_default_library",
"//library/net/http/blademaster/middleware/verify:go_default_library",
"//library/time:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,282 @@
package http
import (
"encoding/json"
"io/ioutil"
"net/http"
"strconv"
"go-common/app/interface/main/videoup/model/archive"
"go-common/library/ecode"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/time"
)
func appEdit(c *bm.Context) {
var (
aid int64
ap = &archive.ArcParam{}
cp = &archive.ArcParam{}
err error
)
mobi := c.Request.Form.Get("mobi_app")
build := c.Request.Form.Get("build")
midI, _ := c.Get("mid")
mid, ok := midI.(int64)
if !ok || mid <= 0 {
c.JSON(nil, ecode.RequestErr)
return
}
bs, err := ioutil.ReadAll(c.Request.Body)
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
c.Request.Body.Close()
if mobi == "iphone" && (build == "4470" || build == "4430") {
err = iosUnmarshal(bs, ap)
err = iosUnmarshal(bs, cp)
} else {
err = json.Unmarshal(bs, ap)
err = json.Unmarshal(bs, cp)
}
if err != nil {
c.JSON(nil, ecode.VideoupParamErr)
return
}
aid = ap.Aid
ap.Mid = mid
// 老的只编辑基础信息, 不需要按照平台自动转换
ap.UpFrom = archive.UpFromAPP
defer func() {
cp.Aid = ap.Aid
cp.Mid = ap.Mid
cp.UpFrom = ap.UpFrom
cp.IPv6 = ap.IPv6
build, buvid := getBuildInfo(c)
vdpSvc.SendArchiveLog(aid, build, buvid, "edit", "app", cp, err)
}()
err = vdpSvc.AppEdit(c, ap, mid)
if err != nil {
c.JSON(nil, err)
log.Error("editErr err(%+v)|ap(%+v)", err, ap)
return
}
c.JSON(map[string]interface{}{
"aid": ap.Aid,
}, nil)
}
func iosUnmarshal(bs []byte, ap *archive.ArcParam) (err error) {
var apStr = struct {
Aid string `json:"aid"`
Copyright string `json:"copyright"`
Cover string `json:"cover"`
Title string `json:"title"`
TypeID string `json:"tid"`
Tag string `json:"tag"`
Desc string `json:"desc"`
MissionID string `json:"mission_id"`
OpenElec string `json:"open_elec"`
DTime string `json:"dtime"`
}{}
if err = json.Unmarshal(bs, &apStr); err != nil {
return
}
aid, err := strconv.ParseInt(apStr.Aid, 10, 64)
if err != nil {
return
}
copyright, err := strconv.ParseInt(apStr.Copyright, 10, 8)
if err != nil {
return
}
typeID, err := strconv.ParseInt(apStr.TypeID, 10, 16)
if err != nil {
return
}
missionID, err := strconv.ParseInt(apStr.MissionID, 10, 10)
if err != nil {
return
}
openElec, err := strconv.ParseInt(apStr.OpenElec, 10, 8)
if err != nil {
return
}
dtime, err := strconv.ParseInt(apStr.DTime, 10, 64)
if err != nil {
return
}
ap.Aid = aid
ap.Copyright = int8(copyright)
ap.TypeID = int16(typeID)
ap.MissionID = int(missionID)
ap.OpenElec = int8(openElec)
ap.DTime = time.Time(dtime)
ap.Cover = apStr.Cover
ap.Title = apStr.Title
ap.Tag = apStr.Tag
ap.Desc = apStr.Desc
return
}
func appUpCover(c *bm.Context) {
midI, _ := c.Get("mid")
mid, ok := midI.(int64)
if !ok || mid <= 0 {
c.JSON(nil, ecode.RequestErr)
return
}
file, _, err := c.Request.FormFile("file")
if err != nil {
log.Error("c.Request().FormFile(\"file\") error(%v) | ", err)
c.JSON(nil, ecode.RequestErr)
return
}
bs, err := ioutil.ReadAll(file)
file.Close()
if err != nil {
log.Error("ioutil.ReadAll(c.Request().Body) error(%v)", err)
c.JSON(nil, ecode.RequestErr)
return
}
ftype := http.DetectContentType(bs)
if ftype != "image/jpeg" && ftype != "image/png" && ftype != "image/webp" {
log.Error("filetype not allow file type(%s)", ftype)
c.JSON(nil, ecode.RequestErr)
return
}
url, err := vdpSvc.AppUpCover(c, ftype, bs, mid)
if err != nil {
c.JSON(nil, err)
return
}
c.JSON(map[string]interface{}{
"url": url,
}, nil)
}
func appAdd(c *bm.Context) {
var (
aid int64
ap = &archive.ArcParam{}
cp = &archive.ArcParam{}
err error
)
form := c.Request.Form
ar := &archive.AppRequest{
Build: form.Get("build"),
MobiApp: form.Get("mobi_app"),
Platform: form.Get("platform"),
Device: form.Get("device"),
}
midI, _ := c.Get("mid")
mid, ok := midI.(int64)
if !ok || mid <= 0 {
c.JSON(nil, ecode.RequestErr)
return
}
bs, err := ioutil.ReadAll(c.Request.Body)
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
c.Request.Body.Close()
err = json.Unmarshal(bs, ap)
err = json.Unmarshal(bs, cp)
if err != nil {
c.JSON(nil, ecode.VideoupParamErr)
return
}
ap.Aid = 0
ap.Mid = mid
ap.UpFrom = appUpFrom(ar.Platform, ar.Device)
defer func() {
cp.Aid = ap.Aid
cp.Mid = ap.Mid
cp.UpFrom = ap.UpFrom
cp.IPv6 = ap.IPv6
build, buvid := getBuildInfo(c)
vdpSvc.SendArchiveLog(aid, build, buvid, "add", ar.Platform, cp, err)
}()
if err == nil {
aid, err = vdpSvc.AppAdd(c, mid, ap, ar)
}
if err != nil {
log.Error("AppAdd Err mid(%+d)|ap(%+v)|err(%+v)", mid, ap, err)
c.JSON(nil, err)
return
}
c.JSON(map[string]interface{}{
"aid": aid,
}, nil)
}
func appEditFull(c *bm.Context) {
var (
aid int64
ap = &archive.ArcParam{}
cp = &archive.ArcParam{}
err error
)
form := c.Request.Form
ar := &archive.AppRequest{
Build: form.Get("build"),
MobiApp: form.Get("mobi_app"),
Platform: form.Get("platform"),
Device: form.Get("device"),
}
buildStr := form.Get("build")
buildNum, _ := strconv.ParseInt(buildStr, 10, 64)
midI, _ := c.Get("mid")
mid, _ := midI.(int64)
ap = &archive.ArcParam{}
bs, err := ioutil.ReadAll(c.Request.Body)
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
c.Request.Body.Close()
err = json.Unmarshal(bs, ap)
err = json.Unmarshal(bs, cp)
if err != nil {
c.JSON(nil, ecode.VideoupParamErr)
return
}
aid = ap.Aid
ap.Mid = mid
ap.UpFrom = appUpFrom(ar.Platform, ar.Device)
defer func() {
cp.Aid = ap.Aid
cp.Mid = ap.Mid
cp.UpFrom = ap.UpFrom
cp.IPv6 = ap.IPv6
build, buvid := getBuildInfo(c)
vdpSvc.SendArchiveLog(aid, build, buvid, "edit", ar.Platform, cp, err)
}()
err = vdpSvc.AppEditFull(c, ap, mid, buildNum, ar)
if err != nil {
log.Error("AppEditFull Err mid(%+d)|ap(%+v)|err(%+v)", mid, ap, err)
c.JSON(nil, err)
return
}
c.JSON(map[string]interface{}{
"aid": ap.Aid,
}, nil)
}
func appUpFrom(platfrom, device string) (res int8) {
if platfrom == "ios" {
if device == "pad" {
res = archive.UpFromIpad
} else {
res = archive.UpFromAPPiOS
}
} else if platfrom == "android" {
res = archive.UpFromAPPAndroid
} else {
res = archive.UpFromAPP
}
return
}

View File

@@ -0,0 +1,146 @@
package http
import (
"encoding/json"
"io/ioutil"
"net/http"
"go-common/app/interface/main/videoup/model/archive"
"go-common/library/ecode"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
)
func clientAdd(c *bm.Context) {
var (
aid int64
ap = &archive.ArcParam{}
cp = &archive.ArcParam{}
err error
)
midI, _ := c.Get("mid")
mid, ok := midI.(int64)
if !ok || mid <= 0 {
c.JSON(nil, ecode.RequestErr)
return
}
bs, err := ioutil.ReadAll(c.Request.Body)
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
c.Request.Body.Close()
err = json.Unmarshal(bs, ap)
err = json.Unmarshal(bs, cp)
if err != nil {
c.JSON(nil, ecode.VideoupParamErr)
return
}
ap.Aid = 0
ap.Mid = mid
ap.UpFrom = archive.UpFromWindows
defer func() {
cp.Aid = ap.Aid
cp.Mid = ap.Mid
cp.IPv6 = ap.IPv6
cp.UpFrom = ap.UpFrom
build, buvid := getBuildInfo(c)
vdpSvc.SendArchiveLog(aid, build, buvid, "add", "windows", cp, err)
}()
aid, err = vdpSvc.ClientAdd(c, mid, ap)
if err != nil {
c.JSON(nil, err)
log.Error("addErr err(%+v)|ap(%+v)", err, ap)
return
}
c.JSON(map[string]interface{}{
"aid": aid,
}, nil)
}
func clientEdit(c *bm.Context) {
var (
aid int64
ap = &archive.ArcParam{}
cp = &archive.ArcParam{}
err error
)
midI, _ := c.Get("mid")
mid, ok := midI.(int64)
if !ok || mid <= 0 {
c.JSON(nil, ecode.RequestErr)
return
}
bs, err := ioutil.ReadAll(c.Request.Body)
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
c.Request.Body.Close()
err = json.Unmarshal(bs, ap)
err = json.Unmarshal(bs, cp)
if err != nil {
c.JSON(nil, ecode.VideoupParamErr)
return
}
aid = ap.Aid
ap.Mid = mid
ap.UpFrom = archive.UpFromWindows
defer func() {
cp.Aid = ap.Aid
cp.Mid = ap.Mid
cp.UpFrom = ap.UpFrom
cp.IPv6 = ap.IPv6
build, buvid := getBuildInfo(c)
vdpSvc.SendArchiveLog(aid, build, buvid, "edit", "windows", cp, err)
}()
err = vdpSvc.ClientEdit(c, ap, mid)
if err != nil {
c.JSON(nil, err)
log.Error("editErr err(%+v)|ap(%+v)", err, ap)
return
}
c.JSON(map[string]interface{}{
"aid": ap.Aid,
}, nil)
}
func clientUpCover(c *bm.Context) {
midI, _ := c.Get("mid")
mid, ok := midI.(int64)
if !ok || mid <= 0 {
c.JSON(nil, ecode.RequestErr)
return
}
file, _, err := c.Request.FormFile("file")
if err != nil {
log.Error("c.Request().FormFile(\"file\") error(%v) | ", err)
c.JSON(nil, ecode.RequestErr)
return
}
bs, err := ioutil.ReadAll(file)
file.Close()
if err != nil {
log.Error("ioutil.ReadAll(c.Request().Body) error(%v)", err)
c.JSON(nil, ecode.RequestErr)
return
}
ftype := http.DetectContentType(bs)
if ftype != "image/jpeg" && ftype != "image/png" && ftype != "image/webp" {
log.Error("filetype not allow file type(%s)", ftype)
c.JSON(nil, ecode.RequestErr)
return
}
url, err := vdpSvc.ClientUpCover(c, ftype, bs, mid)
if err != nil {
c.JSON(nil, err)
return
}
c.JSON(map[string]interface{}{
"url": url,
}, nil)
}

View File

@@ -0,0 +1,143 @@
package http
import (
"io/ioutil"
"net/http"
"encoding/json"
"go-common/app/interface/main/videoup/model/archive"
"go-common/library/ecode"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
)
func creatorEdit(c *bm.Context) {
var (
aid int64
ap = &archive.ArcParam{}
cp = &archive.CreatorParam{}
err error
)
defer func() {
//特例 creatorEdit
ap.Title = cp.Title
ap.Aid = cp.Aid
ap.Tag = cp.Tag
ap.Desc = cp.Desc
ap.OpenElec = cp.OpenElec
build, buvid := getBuildInfo(c)
vdpSvc.SendArchiveLog(aid, build, buvid, "edit", "creator", ap, err)
}()
midI, _ := c.Get("mid")
mid, _ := midI.(int64)
if err = c.Bind(cp); err != nil {
err = ecode.VideoupParamErr
return
}
if cp.Aid == 0 {
err = ecode.VideoupParamErr
return
}
aid = cp.Aid
ap.Aid = cp.Aid
ap.Title = cp.Title
ap.Desc = cp.Desc
ap.Tag = cp.Tag
ap.OpenElec = cp.OpenElec
err = vdpSvc.CreatorEdit(c, mid, cp)
if err != nil {
c.JSON(nil, err)
log.Error("addErr err(%+v)|cp(%+v)", err, cp)
return
}
c.JSON(map[string]interface{}{
"aid": cp.Aid,
}, nil)
}
func creatorAdd(c *bm.Context) {
var (
aid int64
ap = &archive.ArcParam{}
cp = &archive.ArcParam{}
err error
)
midI, _ := c.Get("mid")
mid, ok := midI.(int64)
if !ok || mid <= 0 {
c.JSON(nil, ecode.RequestErr)
return
}
bs, err := ioutil.ReadAll(c.Request.Body)
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
c.Request.Body.Close()
err = json.Unmarshal(bs, ap)
err = json.Unmarshal(bs, cp)
if err != nil {
c.JSON(nil, ecode.VideoupParamErr)
return
}
ap.Mid = mid
ap.UpFrom = archive.UpFromCreator
defer func() {
cp.IPv6 = ap.IPv6
cp.Aid = ap.Aid
cp.UpFrom = ap.UpFrom
cp.Mid = ap.Mid
build, buvid := getBuildInfo(c)
vdpSvc.SendArchiveLog(aid, build, buvid, "add", "creator", cp, err)
}()
if err == nil {
aid, err = vdpSvc.CreatorAdd(c, mid, ap)
}
if err != nil {
c.JSON(nil, err)
log.Error("addErr err(%+v)|ap(%+v)", err, ap)
return
}
c.JSON(map[string]interface{}{
"aid": aid,
}, nil)
}
func creatorUpCover(c *bm.Context) {
midI, _ := c.Get("mid")
mid, ok := midI.(int64)
if !ok || mid <= 0 {
c.JSON(nil, ecode.RequestErr)
return
}
file, _, err := c.Request.FormFile("file")
if err != nil {
log.Error("c.Request().FormFile(\"file\") error(%v) | ", err)
c.JSON(nil, ecode.RequestErr)
return
}
bs, err := ioutil.ReadAll(file)
file.Close()
if err != nil {
log.Error("ioutil.ReadAll(c.Request().Body) error(%v)", err)
c.JSON(nil, ecode.RequestErr)
return
}
ftype := http.DetectContentType(bs)
if ftype != "image/jpeg" && ftype != "image/png" && ftype != "image/webp" {
log.Error("filetype not allow file type(%s)", ftype)
c.JSON(nil, ecode.RequestErr)
return
}
url, err := vdpSvc.CreatorUpCover(c, ftype, bs, mid)
if err != nil {
c.JSON(nil, err)
return
}
c.JSON(map[string]interface{}{
"url": url,
}, nil)
}

View File

@@ -0,0 +1,87 @@
package http
import (
"go-common/app/interface/main/videoup/conf"
"go-common/app/interface/main/videoup/service"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/middleware/antispam"
"go-common/library/net/http/blademaster/middleware/auth"
"go-common/library/net/http/blademaster/middleware/verify"
)
var (
vdpSvc *service.Service
antiSvc *antispam.Antispam
verifySvc *verify.Verify
authSvc *auth.Auth
)
// Init fn
func Init(c *conf.Config, s *service.Service) {
initService(c)
engineOuter := bm.DefaultServer(c.BM)
outerRouter(engineOuter)
if err := engineOuter.Start(); err != nil {
log.Error("engineOuter.Start() error(%v) | config(%v)", err, c)
panic(err)
}
}
// initService init service
func initService(c *conf.Config) {
verifySvc = verify.New(nil)
authSvc = auth.New(nil)
vdpSvc = service.New(c)
antiSvc = antispam.New(c.UpCoverAnti)
}
// outerRouter ForLogic port:6321
func outerRouter(e *bm.Engine) {
e.GET("/monitor/ping", ping)
g := e.Group("/x/vu")
{
client := g.Group("/client")
{
client.POST("/add", authSvc.UserMobile, clientAdd)
client.POST("/edit", authSvc.UserMobile, clientEdit)
client.POST("/cover/up", authSvc.UserMobile, antiSvc.Handler(), clientUpCover)
}
web := g.Group("/web")
{
web.POST("/add", authSvc.UserWeb, webAdd)
web.POST("/edit", authSvc.UserWeb, webEdit)
web.POST("/cover/up", authSvc.UserWeb, antiSvc.Handler(), webUpCover)
web.POST("/filter", authSvc.UserWeb, webFilter)
web.POST("/staff-title/filter", authSvc.UserWeb, webStaffTitleFilter)
web.POST("/cm/add", authSvc.UserWeb, webCmAdd)
web.POST("/v2/add", authSvc.UserWeb, webV2Add)
}
app := g.Group("/app")
{
app.POST("/edit", authSvc.UserMobile, appEdit)
//new feature
app.POST("/add", authSvc.UserMobile, appAdd)
app.POST("/edit/full", authSvc.UserMobile, appEditFull)
app.POST("/cover/up", authSvc.UserMobile, antiSvc.Handler(), appUpCover)
}
creator := g.Group("/creator")
{
creator.POST("/add", authSvc.UserMobile, creatorAdd)
creator.POST("/edit", authSvc.UserMobile, creatorEdit)
creator.POST("/cover/up", authSvc.UserMobile, antiSvc.Handler(), creatorUpCover)
}
}
}
func getBuildInfo(c *bm.Context) (build, buvid string) {
buvid = c.Request.Header.Get("Buvid")
if buvid == "" {
buvidCookie, _ := c.Request.Cookie("buvid3")
if buvidCookie != nil {
buvid = buvidCookie.Value
}
}
build = c.Request.Form.Get("build")
return
}

View File

@@ -0,0 +1,15 @@
package http
import (
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"net/http"
)
func ping(c *bm.Context) {
var err error
if err = vdpSvc.Ping(c); err != nil {
log.Error("videoup-interface ping error(%v)", err)
c.AbortWithStatus(http.StatusServiceUnavailable)
}
}

View File

@@ -0,0 +1,253 @@
package http
import (
"encoding/base64"
"encoding/json"
"io/ioutil"
"net/http"
"strings"
"go-common/app/interface/main/videoup/model/archive"
"go-common/library/ecode"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
)
func webAdd(c *bm.Context) {
var (
aid int64
ap = &archive.ArcParam{}
cp = &archive.ArcParam{}
err error
)
midI, _ := c.Get("mid")
mid, ok := midI.(int64)
if !ok || mid <= 0 {
c.JSON(nil, ecode.CreativeNotLogin)
return
}
bs, err := ioutil.ReadAll(c.Request.Body)
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
c.Request.Body.Close()
err = json.Unmarshal(bs, ap)
err = json.Unmarshal(bs, cp)
if err != nil {
c.JSON(nil, ecode.VideoupParamErr)
return
}
ap.Aid = 0
ap.Mid = mid
ap.UpFrom = archive.UpFromWeb
// code, msg, data := vdpSvc.WebFilterArcParam(c, ap, ip)
// if code != 0 {
// c.Error = ecode.VideoupFieldFilterForbid
// c.Render(http.StatusOK, render.MapJSON(map[string]interface{}{
// "code": code,
// "message": msg,
// "data": data,
// }))
// return
// }
defer func() {
cp.Aid = ap.Aid
cp.Mid = ap.Mid
cp.IPv6 = ap.IPv6
cp.UpFrom = ap.UpFrom
build, buvid := getBuildInfo(c)
vdpSvc.SendArchiveLog(aid, build, buvid, "add", "web", cp, err)
}()
aid, err = vdpSvc.WebAdd(c, mid, ap, false)
if err != nil {
log.Error("vdpSvc.WebAdd Err mid(%+d)|ap(%+v)|err(%+v)", mid, ap, err)
c.JSON(nil, err)
return
}
c.JSON(map[string]interface{}{
"aid": aid,
}, nil)
}
func webEdit(c *bm.Context) {
var (
aid int64
ap = &archive.ArcParam{}
cp = &archive.ArcParam{}
err error
)
midI, _ := c.Get("mid")
mid, ok := midI.(int64)
if !ok || mid <= 0 {
c.JSON(nil, ecode.CreativeNotLogin)
return
}
bs, err := ioutil.ReadAll(c.Request.Body)
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
c.Request.Body.Close()
err = json.Unmarshal(bs, ap)
err = json.Unmarshal(bs, cp)
if err != nil {
c.JSON(nil, ecode.VideoupParamErr)
return
}
aid = ap.Aid
ap.Mid = mid
ap.UpFrom = archive.UpFromWeb
// code, msg, data := vdpSvc.WebFilterArcParam(c, ap, ip)
// if code != 0 {
// c.Error = ecode.VideoupFieldFilterForbid
// c.Render(http.StatusOK, render.MapJSON(map[string]interface{}{
// "code": code,
// "message": msg,
// "data": data,
// }))
// return
// }
defer func() {
cp.Aid = ap.Aid
cp.Mid = ap.Mid
cp.UpFrom = ap.UpFrom
cp.IPv6 = ap.IPv6
build, buvid := getBuildInfo(c)
vdpSvc.SendArchiveLog(aid, build, buvid, "edit", "web", cp, err)
}()
err = vdpSvc.WebEdit(c, ap, mid)
if err != nil {
log.Error("vdpSvc.WebEdit Err mid(%+d)|ap(%+v)|err(%+v)", mid, ap, err)
c.JSON(nil, err)
return
}
c.JSON(map[string]interface{}{
"aid": ap.Aid,
}, nil)
}
func webUpCover(c *bm.Context) {
midI, _ := c.Get("mid")
mid, ok := midI.(int64)
if !ok || mid <= 0 {
c.JSON(nil, ecode.CreativeNotLogin)
return
}
cover := c.Request.Form.Get("cover")
c.Request.Form.Del("cover")
ss := strings.Split(cover, ",")
if len(ss) != 2 || len(ss[1]) == 0 {
log.Error("cover(%s) format error", cover)
c.JSON(nil, ecode.RequestErr)
return
}
bs, err := base64.StdEncoding.DecodeString(ss[1])
if err != nil {
log.Error("base64.StdEncoding.DecodeString(%s) error(%v)", ss[1], err)
c.JSON(nil, ecode.RequestErr)
return
}
ftype := http.DetectContentType(bs)
if ftype != "image/jpeg" && ftype != "image/png" && ftype != "image/webp" {
log.Error("file type not allow file type(%s)", ftype)
c.JSON(nil, ecode.RequestErr)
return
}
url, err := vdpSvc.WebUpCover(c, ftype, bs, mid)
if err != nil {
c.JSON(nil, err)
return
}
c.JSON(map[string]interface{}{
"url": url,
}, nil)
}
func webFilter(c *bm.Context) {
midI, _ := c.Get("mid")
mid, ok := midI.(int64)
if !ok || mid <= 0 {
c.JSON(nil, ecode.CreativeNotLogin)
return
}
var (
err error
)
// msg := c.Request.Form.Get("msg")
// if len(msg) != 0 {
// _, err = vdpSvc.WebSingleFilter(c, msg)
// }
c.JSON(nil, err)
}
// staffTitleFilter 过滤联合投稿职能
func webStaffTitleFilter(c *bm.Context) {
midI, _ := c.Get("mid")
mid, ok := midI.(int64)
if !ok || mid <= 0 {
c.JSON(nil, ecode.CreativeNotLogin)
return
}
var (
err error
)
title := c.Request.Form.Get("title")
if len(title) != 0 {
var hit []string
_, hit, err = vdpSvc.WebSingleFilter(c, title)
if len(hit) > 0 {
err = ecode.VideoupStaffTitleFilter
}
}
c.JSON(nil, err)
}
func webCmAdd(c *bm.Context) {
var (
aid int64
ap = &archive.ArcParam{}
cp = &archive.ArcParam{}
err error
)
midI, _ := c.Get("mid")
mid, ok := midI.(int64)
if !ok || mid <= 0 {
c.JSON(nil, ecode.CreativeNotLogin)
return
}
bs, err := ioutil.ReadAll(c.Request.Body)
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
c.Request.Body.Close()
err = json.Unmarshal(bs, ap)
err = json.Unmarshal(bs, cp)
if err != nil {
c.JSON(nil, ecode.VideoupParamErr)
return
}
ap.Mid = mid
ap.UpFrom = archive.UpFromCM
defer func() {
cp.Aid = ap.Aid
cp.Mid = ap.Mid
cp.IPv6 = ap.IPv6
cp.UpFrom = ap.UpFrom
build, buvid := getBuildInfo(c)
vdpSvc.SendArchiveLog(aid, build, buvid, "add", "cm", cp, err)
}()
aid, err = vdpSvc.WebCmAdd(c, mid, ap)
if err != nil {
log.Error("vdpSvc.WebCmAdd Err mid(%+d)|ap(%+v)|err(%+v)", mid, ap, err)
c.JSON(nil, err)
return
}
c.JSON(map[string]interface{}{
"aid": aid,
}, nil)
}

View File

@@ -0,0 +1,64 @@
package http
import (
"encoding/json"
"io/ioutil"
"go-common/app/interface/main/videoup/model/archive"
"go-common/library/ecode"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
)
func webV2Add(c *bm.Context) {
var (
aid int64
ap = &archive.ArcParam{}
cp = &archive.ArcParam{}
err error
validated bool
)
midI, _ := c.Get("mid")
mid, ok := midI.(int64)
if !ok || mid <= 0 {
c.JSON(nil, ecode.RequestErr)
return
}
bs, err := ioutil.ReadAll(c.Request.Body)
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
c.Request.Body.Close()
err = json.Unmarshal(bs, ap)
err = json.Unmarshal(bs, cp)
if err != nil {
c.JSON(nil, ecode.VideoupParamErr)
return
}
defer func() {
cp.Aid = ap.Aid
cp.Mid = ap.Mid
cp.IPv6 = ap.IPv6
cp.UpFrom = ap.UpFrom
build, buvid := getBuildInfo(c)
vdpSvc.SendArchiveLog(aid, build, buvid, "add", "web/v2", cp, err)
}()
validated, err = vdpSvc.Validate(c, ap.Geetest, "web", mid)
if validated || err == ecode.CreativeGeetestAPIErr {
ap.Mid = mid
ap.UpFrom = archive.UpFromWeb
aid, err = vdpSvc.WebAdd(c, mid, ap, validated)
if err != nil {
log.Error("vdpSvc.WebAdd Err mid(%+d)|ap(%+v)|err(%+v)", mid, ap, err)
c.JSON(nil, err)
return
}
c.JSON(map[string]interface{}{
"aid": aid,
}, nil)
} else {
c.JSON(nil, ecode.CreativeGeetestErr)
}
}

View File

@@ -0,0 +1,35 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"archive.go",
"lbs.go",
"param.go",
"staff.go",
"video.go",
],
importpath = "go-common/app/interface/main/videoup/model/archive",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = ["//library/time:go_default_library"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,165 @@
package archive
import (
"go-common/library/time"
)
// State + Attr + Copyright + Upfrom
const (
// open state
StateOpen = int8(0)
StateOrange = int8(1)
// forbit state
StateForbidWait = int8(-1)
StateForbidRecicle = int8(-2)
StateForbidPolice = int8(-3)
StateForbidLock = int8(-4)
StateForbidFackLock = int8(-5)
StateForbidFixed = int8(-6)
StateForbidLater = int8(-7)
// StateForbidPatched = int8(-8)
StateForbidWaitXcode = int8(-9)
StateForbidAdminDelay = int8(-10)
StateForbidFixing = int8(-11)
// StateForbidStorageFail = int8(-12)
StateForbidOnlyComment = int8(-13)
// StateForbidTmpRecicle = int8(-14)
StateForbidDispatch = int8(-15)
StateForbidXcodeFail = int8(-16)
StateForbidSubmit = int8(-30)
StateForbidUserDelay = int8(-40)
StateForbidUpDelete = int8(-100)
// attribute yes and no
AttrYes = int32(1)
AttrNo = int32(0)
// attribute bit
AttrBitNoRank = uint(0)
AttrBitNoIndex = uint(1)
AttrBitNoWeb = uint(2)
AttrBitNoMobile = uint(3)
AttrBitNoSearch = uint(4)
AttrBitOverseaLock = uint(5)
AttrBitNoRecommend = uint(6)
// AttrBitHideCoins = uint(7)
AttrBitHasHD5 = uint(8)
// AttrBitVisitorDm = uint(9)
AttrBitAllowBp = uint(10)
AttrBitIsBangumi = uint(11)
// AttrBitAllowDownload = uint(12)
AttrBitHideClick = uint(13)
AttrBitAllowTag = uint(14)
AttrBitIsFromArcAPI = uint(15)
AttrBitJumpURL = uint(16)
AttrBitIsMovie = uint(17)
AttrBitBadgepay = uint(18)
AttrBitStaff = uint(24) //联合投稿
// copyright state
CopyrightUnknow = int8(0)
CopyrightOriginal = int8(1)
CopyrightCopy = int8(2)
//up_from
UpFromWeb = int8(0)
UpFromPGC = int8(1)
UpFromWindows = int8(2)
UpFromAPP = int8(3)
UpFromMAC = int8(4)
UpFromSecretPGC = int8(5)
UpFromCoopera = int8(6)
UpFromCreator = int8(7) // 创作姬
UpFromAPPAndroid = int8(8) // 安卓主APP
UpFromAPPiOS = int8(9) // iOS主APP
UpFromCM = int8(10) // Web商单用户投稿
UpFromIpad = int8(11) // ipad投稿的用户
AdvertisingTypeID = 166 // 广告分区的typeid
)
var (
_copyright = map[int8]int8{
CopyrightUnknow: CopyrightUnknow,
CopyrightOriginal: CopyrightOriginal,
CopyrightCopy: CopyrightCopy,
}
)
// InCopyrights check copyright in all copyrights.
func InCopyrights(cp int8) (ok bool) {
_, ok = _copyright[cp]
return
}
// Archive is archive model.
type Archive struct {
Aid int64 `json:"aid"`
Mid int64 `json:"mid"`
TypeID int16 `json:"tid"`
// HumanRank int `json:"-"`
Title string `json:"title"`
Author string `json:"author"`
Cover string `json:"cover"`
Tag string `json:"tag"`
Duration int64 `json:"duration"`
Copyright int8 `json:"copyright"`
Source string `json:"source"`
NoReprint int8 `json:"no_reprint"`
UgcPay int8 `json:"ugcpay"`
OrderID int64 `json:"order_id"`
Desc string `json:"desc"`
MissionID int `json:"mission_id"`
// Round int8 `json:"-"`
// Forward int64 `json:"-"`
Attribute int32 `json:"attribute"`
// Access int16 `json:"-"`
// desc_format
DescFormatID int `json:"desc_format_id,omitempty"`
State int8 `json:"state"`
StateDesc string `json:"state_desc"`
// dynamic
Dynamic string `json:"dynamic"`
Porder *Porder `json:"porder"`
// time
DTime time.Time `json:"dtime"`
PTime time.Time `json:"ptime"`
CTime time.Time `json:"ctime"`
// MTime time.Time `json:"-"`
}
// NotAllowUp check archive is or not allow update state.
func (a *Archive) NotAllowUp() bool {
return a.State == StateForbidUpDelete || a.State == StateForbidLock || a.State == StateForbidPolice
}
// AttrVal get attribute.
func (a *Archive) AttrVal(bit uint) int32 {
return (a.Attribute >> bit) & int32(1)
}
// Type type from archive
type Type struct {
ID int16 `json:"id"`
PID int16 `json:"pid"`
Name string `json:"name"`
Description string `json:"description"`
}
// DescFormat str
type DescFormat struct {
ID int `json:"id"`
TypeID int16 `json:"typeid"`
Copyright int8 `json:"copyright"`
Lang int8 `json:"lang"`
}
// FilterData filter-service data
type FilterData struct {
Level int64 `json:"level"`
Limit int64 `json:"limit"`
Msg string `json:"msg"`
TypeID []int64 `json:"typeid"`
Hit []string `json:"hit"`
}
// PayAsset str
type PayAsset struct {
Price int `json:"price"`
PlatformPrice map[string]int `json:"platform_price"`
}

View File

@@ -0,0 +1,35 @@
package archive
// PoiObj str
type PoiObj struct {
POI string `json:"poi"`
Type int32 `json:"type"`
Addr string `json:"address"`
ShowTitle string `json:"show_title"`
Title string `json:"title"`
AdInfo *AdInfo `json:"ad_info"`
Ancestors []*Ancestor `json:"ancestors"`
Distance float64 `json:"distance"`
ShowDistrance string `json:"show_distance"`
Location *Location `json:"location"`
}
// AdInfo str
type AdInfo struct {
Nation string `json:"nation"`
Provin string `json:"province"`
Distri string `json:"district"`
City string `json:"city"`
}
// Ancestor str
type Ancestor struct {
POI string `json:"poi"`
Type int32 `json:"type"`
}
// Location str
type Location struct {
Lat float64 `json:"lat"`
Lng float64 `json:"lng"`
}

View File

@@ -0,0 +1,232 @@
package archive
import (
"go-common/library/time"
)
// ArchiveAddLogID
const (
// ArchiveAddLogID 投稿日志
ArchiveAddLogID = int(81)
// UgcpayAddarcProtocol ugc新增稿件时候记录的协议版本
UgcpayAddarcProtocol = int(83)
// LogTypeSuccess 投稿成功
LogTypeSuccess = int(0)
// LogTypeFail 投稿失败
LogTypeFail = int(1)
)
// AppRequest str
type AppRequest struct {
MobiApp string
Platform string
Build string
Device string
}
// ArcParam str
type ArcParam struct {
Aid int64 `json:"aid"`
Mid int64 `json:"mid"`
Author string `json:"author"`
TypeID int16 `json:"tid"`
Title string `json:"title"`
Cover string `json:"cover"`
Tag string `json:"tag"`
Copyright int8 `json:"copyright"`
NoReprint int8 `json:"no_reprint"`
OrderID int64 `json:"order_id"`
Desc string `json:"desc"`
Source string `json:"source"`
Attribute int32 `json:"-"` // NOTE: not allow user
OpenElec int8 `json:"open_elec"`
MissionID int `json:"mission_id"`
FromIP int64 `json:"from_ip"`
IPv6 []byte `json:"ipv6"`
UpFrom int8 `json:"up_from"`
BizFrom int8 `json:"biz_from"`
DTime time.Time `json:"dtime"`
Videos []*VideoParam `json:"videos"`
Body string `json:"body,omitempty"`
CodeMode bool `json:"code_mode,omitempty"`
DescFormatID int `json:"desc_format_id,omitempty"`
Dynamic string `json:"dynamic,omitempty"`
Porder *Porder `json:"porder"`
Lang string `json:"lang"`
Watermark *Watermark `json:"watermark"`
Geetest *Geetest `json:"geetest"`
LotteryID int64 `json:"lottery_id"`
Subtitle *Subtitle `json:"subtitle"`
Pay *Pay `json:"pay"`
UgcPay int8 `json:"ugcpay"` // videoup-service 需要按照这个字段转成attribute
FollowMids []int64 `json:"follow_mids"`
PoiObj *PoiObj `json:"poi_object"`
Staffs []*Staff `json:"staffs"`
HandleStaff bool `json:"handle_staff"`
Vote *Vote `json:"vote"`
}
// Vote str
type Vote struct {
VoteID int64 `json:"vote_id"`
VoteTitle string `json:"vote_title"`
}
// Pay str
type Pay struct {
Open int8 `json:"open"`
Price int `json:"price"`
ProtocolID string `json:"protocol_id"`
ProtocolAccept int8 `json:"protocol_accept"`
RefuseUpdate bool `json:"-"`
}
// Subtitle str only for web add and edit
type Subtitle struct {
Open int8 `json:"open"`
Lan string `json:"lan"`
}
// Geetest str
type Geetest struct {
Challenge string `json:"challenge"`
Validate string `json:"validate"`
Seccode string `json:"seccode"`
Success int `json:"success"`
}
// Watermark str
type Watermark struct {
State int8 `json:"state"`
Ty int8 `json:"type"`
Pos int8 `json:"position"`
}
// Porder str
// new porder, ads provoder
type Porder struct {
FlowID uint `json:"flow_id"` // 0/1 是否确实参加了广告平台
IndustryID int64 `json:"industry_id"` // 2 (游戏)
BrandName string `json:"brand_name"` // FGO游戏
BrandID int64 `json:"brand_id"` // 2
Official int8 `json:"official"` // 0/1
ShowType string `json:"show_type"` // 2,3,4
}
// VideoParam str
type VideoParam struct {
Title string `json:"title"`
Desc string `json:"desc"`
Filename string `json:"filename"`
Cid int64 `json:"cid"`
Sid int64 `json:"sid"`
Editor *Editor `json:"editor"`
}
// Editor str
type Editor struct {
CID int64 `json:"cid"`
UpFrom int8 `json:"upfrom"` // filled by backend
// ids set
Filters interface{} `json:"filters"` // 滤镜
Fonts interface{} `json:"fonts"` //字体
Subtitles interface{} `json:"subtitles"` //字幕
Bgms interface{} `json:"bgms"` //bgm
Stickers interface{} `json:"stickers"` //3d拍摄贴纸
VideoupStickers interface{} `json:"videoup_stickers"` //2d投稿贴纸
Transitions interface{} `json:"trans"` //视频转场特效
// add from app535
Themes interface{} `json:"themes"` //编辑器的主题使用相关
Cooperates interface{} `json:"cooperates"` //拍摄之稿件合拍
// switch env 0/1
AudioRecord int8 `json:"audio_record"` //录音
Camera int8 `json:"camera"` //拍摄
Speed int8 `json:"speed"` //变速
CameraRotate int8 `json:"camera_rotate"` //摄像头翻转
// count from app536
PicCount uint16 `json:"pic_count"` // 图片个数
VideoCount uint16 `json:"video_count"` // 视频个数
}
// VideoExpire str
type VideoExpire struct {
Filename string `json:"filename"`
Expire int64 `json:"expire"`
}
// CreatorParam struct
type CreatorParam struct {
Aid int64 `form:"aid" validate:"required"`
Title string `form:"title" validate:"required"`
Desc string `form:"desc" validate:"required"`
Tag string `form:"tag" validate:"required"`
OpenElec int8 `form:"open_elec"`
Build string `form:"build" validate:"required"`
Platform string `form:"platform" validate:"required"`
}
// Staff 稿件提交时的联合投稿人
type Staff struct {
Title string `json:"title"`
Mid int64 `json:"mid"`
}
// StaffView Archive staff
type StaffView struct {
ID int64 `json:"id"`
ApMID int64 `json:"apply_staff_mid"`
ApTitle string `json:"apply_title"`
ApAID int64 `json:"apply_aid"`
ApType int `json:"apply_type"`
ApState int `json:"apply_state"`
ApStaffID int64 `json:"apply_asid"` //Staff表的主键ID
StaffState int `json:"staff_state"`
StaffTitle string `json:"staff_title"`
}
// ForbidMultiVideoType fun
// 欧美电影,日本电影,国产电影,其他国家
func (ap *ArcParam) ForbidMultiVideoType() bool {
return ap.TypeID == 145 || ap.TypeID == 146 || ap.TypeID == 147 || ap.TypeID == 83
}
// ForbidAddVideoType fun
// 连载剧集15 完结剧集34 电视剧相关128 电影相关82
func (ap *ArcParam) ForbidAddVideoType() bool {
return ap.TypeID == 15 || ap.TypeID == 34 || ap.TypeID == 128 || ap.TypeID == 82
}
// ForbidCopyrightAndTypes fun
// // 32 完结动画; 33 连载动画
func (ap *ArcParam) ForbidCopyrightAndTypes() bool {
return (ap.Copyright == CopyrightOriginal) && (ap.TypeID == 32 || ap.TypeID == 33)
}
// EmptyVideoEditInfo fn
func (ap *ArcParam) EmptyVideoEditInfo() {
if (ap.UpFrom != UpFromAPPiOS) && (ap.UpFrom != UpFromAPPAndroid) {
for _, v := range ap.Videos {
v.Editor = nil
}
}
}
// NilPoiObj fn
func (ap *ArcParam) NilPoiObj() {
if (ap.UpFrom != UpFromAPPiOS) && (ap.UpFrom != UpFromAPPAndroid) {
ap.PoiObj = nil
}
}
// DisableVideoDesc fn
func (ap *ArcParam) DisableVideoDesc(vs []*Video) {
nvsMap := make(map[string]string)
for _, v := range vs {
nvsMap[v.Filename] = v.Desc
}
for _, pv := range ap.Videos {
if nvFilename, ok := nvsMap[pv.Filename]; ok {
pv.Desc = nvFilename
}
}
}

View File

@@ -0,0 +1,7 @@
package archive
//联合投稿的分区配置
type StaffTypeConf struct {
TypeID int16 `json:"typeid"`
MaxStaff int `json:"max_staff"`
}

View File

@@ -0,0 +1,47 @@
package archive
import "go-common/library/time"
// VideoStatus
const (
VideoUploadInfo = int8(0)
VideoXcodeSDFail = int8(1)
VideoXcodeSDFinish = int8(2)
VideoXcodeHDFail = int8(3)
VideoXcodeHDFinish = int8(4)
VideoDispatchRunning = int8(5)
VideoDispatchFinish = int8(6)
VideoStatusOpen = int16(0)
VideoStatusAccess = int16(10000)
VideoStatusWait = int16(-1)
VideoStatusRecicle = int16(-2)
VideoStatusLock = int16(-4)
VideoStatusXcodeFail = int16(-16)
VideoStatusSubmit = int16(-30)
VideoStatusDelete = int16(-100)
XcodeFailZero = 0
)
// Video is archive_video model.
type Video struct {
// ID int64 `json:"-"`
Aid int64 `json:"aid"`
Title string `json:"title"`
Desc string `json:"desc"`
Filename string `json:"filename"`
// SrcType string `json:"-"`
// Cid int64 `json:"-"`
// Duration int64 `json:"-"`
// Filesize int64 `json:"-"`
// Resolutions string `json:"-"`
Index int `json:"index"`
// Playurl string `json:"-"`
Status int16 `json:"status"`
StatusDesc string `json:"status_desc"`
FailCode int8 `json:"fail_code"`
FailDesc string `json:"fail_desc"`
// XcodeState int8 `json:"-"`
// Attribute int32 `json:"-"`
CTime time.Time `json:"ctime"`
// MTime time.Time `json:"-"`
}

View File

@@ -0,0 +1,28 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["geetest.go"],
importpath = "go-common/app/interface/main/videoup/model/geetest",
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,12 @@
package geetest
type ProcessRes struct {
Success int8 `json:"success"`
CaptchaID string `json:"gt"`
Challenge string `json:"challenge"`
NewCaptcha int `json:"new_captcha"`
}
type ValidateRes struct {
Seccode string `json:"seccode"`
}

View File

@@ -0,0 +1,27 @@
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
package(default_visibility = ["//visibility:public"])
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
go_library(
name = "go_default_library",
srcs = ["mission.go"],
importpath = "go-common/app/interface/main/videoup/model/mission",
tags = ["automanaged"],
)

View File

@@ -0,0 +1,21 @@
package mission
import "time"
type Mission struct {
ID int `json:"id"`
Name string `json:"name"`
Tags string `json:"tags"`
ETime time.Time `json:"etime"`
}
// ActInfo act proctocol & tag.
type ActInfo struct {
ID string `json:"id"`
SID string `json:"sid"`
Protocol string `json:"protocol"`
Types string `json:"types"`
Tag string `json:"tags"`
CTime string `json:"ctime"`
MTime string `json:"mtime"`
}

View File

@@ -0,0 +1,27 @@
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
package(default_visibility = ["//visibility:public"])
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
go_library(
name = "go_default_library",
srcs = ["porder.go"],
importpath = "go-common/app/interface/main/videoup/model/porder",
tags = ["automanaged"],
)

View File

@@ -0,0 +1,20 @@
package porder
// OfficialIndustryMaps map
var OfficialIndustryMaps = map[int64]int64{
1: 1,
}
// Config str
type Config struct {
ID int64 `json:"id"`
Tp int8 `json:"type"`
Name string `json:"name"`
}
// Game str
type Game struct {
GameBaseID int64 `json:"game_base_id"`
GameName string `json:"game_name"`
Source int8 `json:"source"`
}

View File

@@ -0,0 +1,94 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"archive_test.go",
"service_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/videoup/conf:go_default_library",
"//app/interface/main/videoup/model/archive:go_default_library",
"//library/ecode:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"allow.go",
"app.go",
"check.go",
"check_staff.go",
"client.go",
"creator.go",
"deal.go",
"filter.go",
"geetest.go",
"infoc.go",
"log.go",
"pay.go",
"pre.go",
"service.go",
"subtitle.go",
"web.go",
],
importpath = "go-common/app/interface/main/videoup/service",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/creative/model/tag:go_default_library",
"//app/interface/main/videoup/conf:go_default_library",
"//app/interface/main/videoup/dao/account:go_default_library",
"//app/interface/main/videoup/dao/archive:go_default_library",
"//app/interface/main/videoup/dao/bfs:go_default_library",
"//app/interface/main/videoup/dao/creative:go_default_library",
"//app/interface/main/videoup/dao/dynamic:go_default_library",
"//app/interface/main/videoup/dao/elec:go_default_library",
"//app/interface/main/videoup/dao/filter:go_default_library",
"//app/interface/main/videoup/dao/geetest:go_default_library",
"//app/interface/main/videoup/dao/mission:go_default_library",
"//app/interface/main/videoup/dao/order:go_default_library",
"//app/interface/main/videoup/dao/pay:go_default_library",
"//app/interface/main/videoup/dao/subtitle:go_default_library",
"//app/interface/main/videoup/dao/tag:go_default_library",
"//app/interface/main/videoup/model/archive:go_default_library",
"//app/interface/main/videoup/model/geetest:go_default_library",
"//app/interface/main/videoup/model/mission:go_default_library",
"//app/interface/main/videoup/model/porder:go_default_library",
"//app/service/main/account/api:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/log/infoc:go_default_library",
"//library/net/metadata:go_default_library",
"//library/queue/databus/report:go_default_library",
"//library/sync/errgroup:go_default_library",
"//library/time:go_default_library",
"//library/xstr:go_default_library",
"//vendor/github.com/microcosm-cc/bluemonday:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,111 @@
package service
import (
"context"
"strings"
"time"
"unicode/utf8"
"go-common/app/interface/main/videoup/model/archive"
"go-common/library/log"
xtime "go-common/library/time"
)
// forbidTopTypesForAll fn 175=>ASMR
func (s *Service) forbidTopTypesForAll(tid int16) bool {
return tid == 175
}
func (s *Service) allowOrderUps(mid int64) (ok bool) {
if mid <= 0 {
ok = false
return
}
_, ok = s.orderUps[mid]
return
}
func (s *Service) allowType(typeid int16) (ok bool) {
_, ok = s.typeCache[typeid]
if s.forbidTopTypesForAll(typeid) {
ok = false
}
return
}
func (s *Service) allowCopyright(cp int8) (ok bool) {
ok = archive.InCopyrights(cp)
return
}
func (s *Service) allowSource(cp int8, source string) (ok bool) {
ok = cp == archive.CopyrightOriginal || (cp == archive.CopyrightCopy && len(strings.TrimSpace(source)) > 0)
return
}
func (s *Service) allowTag(tag string) (ok bool) {
if len(tag) == 0 {
return
}
for _, reg := range _emptyUnicodeReg {
if reg.MatchString(tag) {
return
}
}
tags := strings.Split(tag, ",")
if len(tags) > 12 {
return
}
for _, t := range tags {
if utf8.RuneCountInString(t) > 30 {
return
}
}
ok = true
return
}
func (s *Service) allowDelayTime(dtime xtime.Time) (ok bool) {
if dtime == 0 {
ok = true
return
}
const (
min = int64(4 * time.Hour / time.Second)
max = int64(15 * 24 * time.Hour / time.Second)
)
diff := int64(dtime) - time.Now().Unix()
ok = min < diff && diff < max
return
}
func (s *Service) allowHalfMin(c context.Context, mid int64) (ok bool) {
// 活动等其他业务方运营需要,接触半分钟的限速
if _, white := s.exemptHalfMinUps[mid]; white {
return true
}
log.Info("halfMin start | mid(%d).", mid)
exist, _, _ := s.acc.HalfMin(c, mid)
log.Info("halfMin from cache | mid(%d) exist(%v).", mid, exist)
//先判断缓存,ok取反,如果存在则不允许,继续等冷却时间;如果缓存不存在,则默认继续添加冷却时间窗口
if ok = !exist; ok {
log.Info("halfMin not exist | mid(%d)", mid)
s.acc.AddHalfMin(c, mid)
log.Info("halfMin add cache | mid(%d).", mid)
}
log.Info("halfMin end | mid(%d).", mid)
return
}
func (s *Service) allowRepeat(c context.Context, mid int64, title string) (ok bool) {
log.Info("allowRepeat check start | mid(%d) title(%s).", mid, title)
exist, _ := s.acc.SubmitCache(c, mid, title)
log.Info("allowRepeat from cache | mid(%d) title(%s) exist(%d).", mid, title, exist)
if ok = exist == 0; ok {
log.Info("allowRepeat not exist | mid(%d) title(%s)", mid, title)
s.acc.AddSubmitCache(c, mid, title)
log.Info("allowRepeat add cache | mid(%d) title(%s).", mid, title)
}
log.Info("allowRepeat check end | mid(%d) title(%s).", mid, title)
return
}

View File

@@ -0,0 +1,223 @@
package service
import (
"bytes"
"context"
"net"
"strings"
"go-common/app/interface/main/videoup/model/archive"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/net/metadata"
"go-common/library/sync/errgroup"
)
// AppEdit edit archive by appclient.
func (s *Service) AppEdit(c context.Context, ap *archive.ArcParam, mid int64) (err error) {
ip := metadata.String(c, metadata.RemoteIP)
ap.IPv6 = net.ParseIP(ip)
if err = s.checkIdentify(c, mid, ip); err != nil {
log.Error("s.CheckIdentify mid(%d) ap(%+v) error(%v)", mid, ap, err)
return
}
var (
a = &archive.Archive{}
vs = []*archive.Video{}
)
if a, vs, err = s.arc.View(c, ap.Aid, ip); err != nil {
log.Error("s.arc.View err(%v) | aid(%d) ip(%s)", err, ap.Aid, ip)
return
}
if a == nil {
log.Error("s.arc.View(%d) not found", mid)
err = ecode.ArchiveNotExist
return
}
// pre check
if err = s.preEdit(c, mid, a, vs, ap, ip, ap.UpFrom); err != nil {
return
}
// edit
if err = s.arc.Edit(c, ap, ip); err != nil {
return
}
g := &errgroup.Group{}
ctx := context.TODO()
g.Go(func() error {
s.dealElec(ctx, ap.OpenElec, ap.Aid, mid, ip)
return nil
})
g.Wait()
return
}
// AppUpCover main app upload cover.
func (s *Service) AppUpCover(c context.Context, fileType string, body []byte, mid int64) (url string, err error) {
if len(body) == 0 {
err = ecode.FileNotExists
log.Error("AppEcode FileNotExists mid(%d) error(%v)", mid, err)
return
}
if len(body) > s.c.Bfs.MaxFileSize {
err = ecode.FileTooLarge
log.Error("AppEcode FileTooLarge mid(%d) error(%v)", mid, err)
return
}
url, err = s.bfs.Upload(c, fileType, bytes.NewReader(body))
if err != nil {
log.Error("AppEcode s.bfs.Upload error(%v)", err)
}
return
}
func (s *Service) freshAppMissionByFirstTag(ap *archive.ArcParam) (res *archive.ArcParam) {
if ap.MissionID == 0 {
firstTag := strings.Split(ap.Tag, ",")[0]
if missionID, ok := s.missTagsCache[firstTag]; ok {
ap.MissionID = missionID
}
}
res = ap
return
}
// AppAdd add archive by main app.
func (s *Service) AppAdd(c context.Context, mid int64, ap *archive.ArcParam, ar *archive.AppRequest) (aid int64, err error) {
ip := metadata.String(c, metadata.RemoteIP)
ap.IPv6 = net.ParseIP(ip)
defer func() {
if err != nil && err != ecode.VideoupCanotRepeat {
s.acc.DelSubmitCache(c, ap.Mid, ap.Title)
}
}()
ap = s.freshAppMissionByFirstTag(ap)
if err = s.checkIdentify(c, mid, ip); err != nil {
log.Error("s.CheckIdentify mid(%d) ap(%+v) error(%v)", mid, ap, err)
return
}
// pre check
if err = s.preAdd(c, mid, ap, ip, ap.UpFrom); err != nil {
return
}
if ap.PoiObj != nil {
log.Warn("poi_object is not nil, mid(%d),upfrom(%d),poi_object(%+v)", mid, ap.UpFrom, ap.PoiObj)
}
if aid, err = s.arc.Add(c, ap, ip); err != nil || aid == 0 {
return
}
ap.Aid = aid
g := &errgroup.Group{}
ctx := context.TODO()
g.Go(func() error {
s.dealOrder(ctx, mid, aid, ap.OrderID, ip)
return nil
})
g.Go(func() error {
s.dealWaterMark(ctx, mid, ap.Watermark, ip)
return nil
})
g.Go(func() error {
s.freshFavs(ctx, mid, ap, ip)
return nil
})
g.Go(func() error {
s.dealElec(ctx, 1, aid, mid, ip)
return nil
})
g.Go(func() error {
s.uploadVideoEditInfo(ctx, ap, aid, mid, ip)
return nil
})
g.Go(func() error {
s.lotteryBind(ctx, ap.LotteryID, aid, mid, ip)
return nil
})
g.Go(func() error {
s.addFollowing(ctx, mid, ap.FollowMids, ap.UpFrom, ip)
return nil
})
g.Go(func() error {
s.VideoInfoc(ctx, ap, ar)
return nil
})
g.Wait()
return
}
// AppEditFull fn
func (s *Service) AppEditFull(c context.Context, ap *archive.ArcParam, mid, buildNum int64, ar *archive.AppRequest) (err error) {
ip := metadata.String(c, metadata.RemoteIP)
ap.IPv6 = net.ParseIP(ip)
platform := ar.Platform
if err = s.checkIdentify(c, mid, ip); err != nil {
log.Error("s.CheckIdentify mid(%d) ap(%+v) error(%v)", mid, ap, err)
return
}
var (
a = &archive.Archive{}
vs = []*archive.Video{}
)
if a, vs, err = s.arc.View(c, ap.Aid, ip); err != nil {
log.Error("s.arc.View err(%v) | aid(%d) ip(%s)", err, ap.Aid, ip)
return
}
if a == nil {
log.Error("s.arc.View(%d) not found", mid)
err = ecode.ArchiveNotExist
return
}
if nvsCnt := s.checkVideosMaxLimitForEdit(vs, ap.Videos); nvsCnt > s.c.MaxAddVsCnt {
log.Error("checkVideosMaxLimitForEdit, vsCnt(%d), limit(%d), nvsCnt(%d)", len(vs), s.c.MaxAddVsCnt, nvsCnt)
err = ecode.VideoupVideosMaxLimit
return
}
ap = s.protectFeatureForApp(ap, a, buildNum, platform)
// pre check
if err = s.preEdit(c, mid, a, vs, ap, ip, ap.UpFrom); err != nil {
return
}
// edit
if err = s.arc.Edit(c, ap, ip); err != nil {
return
}
g := &errgroup.Group{}
ctx := context.TODO()
g.Go(func() error {
s.dealElec(ctx, ap.OpenElec, ap.Aid, mid, ip)
return nil
})
g.Go(func() error {
s.uploadVideoEditInfo(ctx, ap, ap.Aid, mid, ip)
return nil
})
g.Go(func() error {
s.addFollowing(ctx, mid, ap.FollowMids, ap.UpFrom, ip)
return nil
})
g.Go(func() error {
s.VideoInfoc(ctx, ap, ar)
return nil
})
g.Wait()
return
}
// protectFeatureForApp fn
// feature list: porder,order,desc_format_id
func (s *Service) protectFeatureForApp(origin *archive.ArcParam, a *archive.Archive, buildNum int64, platform string) (res *archive.ArcParam) {
res = origin
res.Porder = a.Porder
res.OrderID = a.OrderID
res.DescFormatID = a.DescFormatID
// android except 5.26 5260000
if buildNum < 5260000 && platform == "android" {
res.Dynamic = a.Dynamic
res.MissionID = a.MissionID
// ios include 5.25.1 6680
} else if buildNum <= 6680 && platform == "ios" {
res.Dynamic = a.Dynamic
res.MissionID = a.MissionID
}
return
}

View File

@@ -0,0 +1,65 @@
package service
import (
"context"
"encoding/json"
"testing"
"go-common/app/interface/main/videoup/model/archive"
. "github.com/smartystreets/goconvey/convey"
)
func Test_Ping(t *testing.T) {
var (
c = context.Background()
err error
)
Convey("Ping", t, WithService(func(s *Service) {
err = s.Ping(c)
So(err, ShouldBeNil)
}))
}
func Test_Close(t *testing.T) {
Convey("Close", t, WithService(func(s *Service) {
s.Close()
}))
}
func Test_WebAdd(t *testing.T) {
var (
c = context.Background()
err error
MID = int64(27515256)
body = `{"copyright":1,"cover":"","title":"test","tid":130,"tag":"音乐选集","no_reprint":1,"upos":0,"lang":"zh-CN","mission_id":0,"porder":{},"desc":"123","dynamic":"123","videos":[{"desc":"","filename":"g180126072jadys8fuaz74u18hkxwvnf","title":""}]}
`
aid int64
)
var ap = &archive.ArcParam{}
if err = json.Unmarshal([]byte(body), ap); err != nil {
return
}
Convey("webAdd", t, WithService(func(s *Service) {
aid, err = s.WebAdd(c, MID, ap, true)
So(err, ShouldBeNil)
So(aid, ShouldNotBeNil)
}))
}
func Test_WebEdit(t *testing.T) {
var (
c = context.Background()
err error
MID = int64(27515256)
body = `{"copyright":1,"cover":"","title":"test","tid":130,"tag":"音乐选集","no_reprint":1,"upos":0,"lang":"zh-CN","mission_id":0,"porder":{},"desc":"123","dynamic":"123","videos":[{"desc":"","filename":"g180126072jadys8fuaz74u18hkxwvnf","title":""}]}
`
)
var ap = &archive.ArcParam{}
if err = json.Unmarshal([]byte(body), ap); err != nil {
return
}
Convey("webEdit", t, WithService(func(s *Service) {
err = s.WebEdit(c, ap, MID)
So(err, ShouldBeNil)
}))
}

View File

@@ -0,0 +1,460 @@
package service
import (
"context"
"go-common/app/interface/main/creative/model/tag"
"go-common/app/interface/main/videoup/model/archive"
"go-common/app/interface/main/videoup/model/mission"
"go-common/app/interface/main/videoup/model/porder"
accapi "go-common/app/service/main/account/api"
"go-common/library/ecode"
"go-common/library/log"
xtime "go-common/library/time"
"go-common/library/xstr"
"net/url"
"regexp"
"strings"
"time"
"unicode/utf8"
)
var (
_emptyUnicodeRegForTitle = []*regexp.Regexp{
regexp.MustCompile(`[\x{202e}]+`), // right-to-left override
regexp.MustCompile(`[\x{200b}]+`), // zeroWithChar
regexp.MustCompile(`[\x{1f6ab}]+`), // no_entry_sign
regexp.MustCompile(`[\n]+`), // newline
regexp.MustCompile(`[\r]+`), // newline
}
_emptyUnicodeReg = []*regexp.Regexp{
regexp.MustCompile(`[\x{202e}]+`), // right-to-left override
regexp.MustCompile(`[\x{200b}]+`), // zeroWithChar
regexp.MustCompile(`[\x{1f6ab}]+`), // no_entry_sign
}
_nocharReg = []*regexp.Regexp{
regexp.MustCompile(`[\p{Hangul}]+`), // kr
regexp.MustCompile(`[\p{Tibetan}]+`), // tibe
regexp.MustCompile(`[\p{Arabic}]+`), // arabic
}
_filenameReg = regexp.MustCompile(`^[A-Z0-9a-z]+$`) // only letter digital.
_staffNameReg = regexp.MustCompile("^[\u4e00-\u9fa5a-zA-Z0-9]+$") //职能:数字、字母、中文
)
func (s *Service) checkMission(c context.Context, ap *archive.ArcParam) (err error) {
if ap.MissionID <= 0 {
log.Warn("MissionID(%d) error", ap.MissionID)
ap.MissionID = 0
return
}
missionID := ap.MissionID
tid := ap.TypeID
m, ok := s.missCache[missionID]
if !ok || m.ID == 0 {
err = ecode.VideoupMissionErr
return
}
if m.ETime.Before(time.Now()) {
log.Error("VideoupMissionEtimeInvalid err, tid(%d)|etime(%+v)", tid, m.ETime)
err = ecode.VideoupMissionEtimeInvalid
return
}
var missionTys map[int]*mission.Mission
if missionTys, err = s.miss.MissionOnlineByTid(c, tid); err != nil {
log.Error("MissionOnlineByTid err, s.tid(%+v)|err(%+v)", tid, err)
err = nil
return
}
// case: 这是活动全下架,还想参加活动
if len(missionTys) == 0 {
log.Error("missionTys already empty, tid(%d)|missionTys(%+v)", tid, missionTys)
err = ecode.VideoupMissionNoMatch
return
}
// 包含对分区无限制的活动
if _, ok := missionTys[missionID]; !ok {
log.Error("VideoupMissionNoMatch err, tid(%d)|missionID(%d)", tid, missionID)
err = ecode.VideoupMissionNoMatch
return
}
if ap.Copyright == archive.CopyrightCopy {
log.Error("VideoupCopyForbidJoinMission err, copyright(%d)|missionID(%d)", ap.Copyright, ap.MissionID)
err = ecode.VideoupCopyForbidJoinMission
return
}
return
}
func (s *Service) checkMissionTag(srcTag string, missionID int) (dstTag string, err error) {
var ctags = strings.Split(srcTag, ",")
dstTag = srcTag
// 交叉对比剔除掉当前活动已经使用的tag内容
if len(s.missTagsCache) != 0 {
var tags = make([]string, 0, len(ctags))
for _, t := range ctags {
if _, ok := s.missTagsCache[t]; !ok {
tags = append(tags, t)
}
}
dstTag = strings.Join(tags, ",")
}
// 校验
// 两种情况报错提示用户: 1. 未参加活动,只提交一个tag且是活动tag, 2. 参加活动只提交了一个tag且是其他活动的活动tag
if dstTag == "" && missionID == 0 {
log.Error("forbidMissionTagWithoutJoinMission srcTag(%s), MissionID(%d),s.missCache(%+v),s.missTagsCache(%+v)", srcTag, missionID, s.missCache, s.missTagsCache)
err = ecode.VideoupTagForbidNotJoinMission
return
}
// 未参加活动就直接返回校验后的tag内容
m, ok := s.missCache[missionID]
if !ok {
return
}
// 如果参加了当前有效的活动就会把对应的活动第一个tag拼接在头部, 对于活动id和tag不匹配的会做校验
var singleMissionTag string
if m.Tags != "" {
singleMissionTag = strings.Split(m.Tags, ",")[0]
} else {
singleMissionTag = m.Name
}
if len(dstTag) > 0 {
dstTag = singleMissionTag + "," + dstTag
} else {
dstTag = singleMissionTag
}
return
}
func (s *Service) checkVideo(ap *archive.ArcParam) (err error) {
vds := make([]*archive.VideoParam, 0)
fnMap := make(map[string]int)
var ok bool
for i, v := range ap.Videos {
if v == nil {
continue
}
if v.Title, ok = s.checkTitle(v.Title); !ok {
newErr := ecode.VideoupVideoTitleErr
err = ecode.Errorf(newErr, newErr.Message(), i+1)
log.Error("ap.Videos checkTitle err(%+v)|Title(%s)", err, v.Title)
return
}
if v.Desc, ok = s.checkDesc(v.Desc); !ok {
newErr := ecode.VideoupVideoDescErr
err = ecode.Errorf(newErr, newErr.Message(), i+1)
log.Error("ap.Videos checkDesc err(%+v)|Desc(%s)", err, v.Desc)
return
}
if ok = _filenameReg.MatchString(v.Filename); !ok {
newErr := ecode.VideoupVideoFilenameErr
err = ecode.Errorf(newErr, newErr.Message(), i+1)
log.Error("ap.Videos _filenameReg err(%+v)|filename(%s)", err, v.Filename)
return
}
if v.Cid == 0 && v.Filename == "" { // NOTE: cid>0 means code mode
newErr := ecode.VideoupVideoFilenameErr
err = ecode.Errorf(newErr, newErr.Message(), i+1)
log.Error("ap.Videos err(%+v)|Filename(%s)|Cid(%d)", err, v.Filename, v.Cid)
return
}
if _, ok := fnMap[v.Filename]; ok {
err = ecode.VideoupFilenameCanotRepeat
log.Error("ecode.VideoupFilenameCanotRepeat err(%+v)|Filename(%s)|index(%d)", err, v.Filename, i)
return
}
vds = append(vds, v)
fnMap[v.Filename] = 1
}
ap.Videos = vds
return
}
func (s *Service) checkCover(cover string) (cv string, ok bool) {
if cover == "" {
ok = true
return
}
uri, err := url.Parse(cover)
if err != nil {
return
}
if strings.Contains(uri.Host, "hdslb.com") {
cv = uri.Path
ok = true
return
} else if strings.Contains(uri.Host, "acgvideo.com") {
cv = cover
ok = true
return
}
return
}
func (s *Service) checkDynamicLen233(dynamic string) (dyn string, ok bool) {
dyn = strings.TrimSpace(dynamic)
var _emptyDynUnicodeReg = []*regexp.Regexp{
regexp.MustCompile(`[\x{FFFC}]+`), // obj
}
for _, reg := range _emptyDynUnicodeReg {
dyn = reg.ReplaceAllString(dyn, "")
}
if utf8.RuneCountInString(dyn) > 233 {
return
}
ok = true
return
}
func (s *Service) checkTitle(title string) (ct string, ok bool) {
ct = strings.TrimSpace(title)
if utf8.RuneCountInString(ct) > 80 {
return
}
for _, reg := range _nocharReg {
if reg.MatchString(ct) {
return
}
}
for _, reg := range _emptyUnicodeRegForTitle {
ct = reg.ReplaceAllString(ct, "")
}
ok = true
return
}
func (s *Service) checkDesc(desc string) (cd string, ok bool) {
cd = strings.TrimSpace(desc)
for _, reg := range _emptyUnicodeReg {
cd = reg.ReplaceAllString(cd, "")
}
if utf8.RuneCountInString(cd) > 2000 {
return
}
ok = true
return
}
func (s *Service) checkAccount(c context.Context, mid int64, ip string) (p *accapi.Profile, err error) {
if p, err = s.acc.Profile(c, mid, ip); err != nil {
return
}
if p.Silence == 1 {
err = ecode.UserDisabled
} else if p.Level < 1 {
err = ecode.UserLevelLow
}
if _, ok := s.exemptZeroLevelAndAnswerUps[mid]; ok && err == ecode.UserLevelLow {
log.Info("s.exemptZeroLevelAndAnswerUps, (%s),(%d),(%+v)", ip, mid, err)
err = nil
}
return
}
func (s *Service) checkOrderID(c context.Context, mid, orderID int64, ip string) (err error) {
orderIDs, err := s.order.ExecuteOrders(c, mid, ip)
if err != nil {
log.Error("s.order.ExecuteOrders mid(%d) ip(%s) error(%v)", mid, err)
err = ecode.VideoupOrderAPIErr
return
}
if _, ok := orderIDs[orderID]; !ok {
err = ecode.VideoupOrderIDNotAllow
}
return
}
func (s *Service) checkIdentify(c context.Context, mid int64, ip string) (err error) {
if _, ok := s.exemptIDCheckUps[mid]; ok {
log.Info("s.exemptIDCheckUps, (%s),(%d),(%+v)", ip, mid, err)
return
}
// fault-tolerant for service interruption
if err = s.acc.IdentifyInfo(c, ip, mid); err != nil {
if err != ecode.UserCheckNoPhone && err != ecode.UserCheckInvalidPhone {
log.Warn("s.accIdentifyInfo, account service maybe in interruption,(%s),(%d),(%+v)", ip, mid, err)
return nil
}
log.Error("s.accIdentifyInfo, (%s),(%d),(%+v)", ip, mid, err)
return
}
return
}
// checkPorderForAdd
func (s *Service) checkPorderForAdd(c context.Context, ap *archive.ArcParam, mid int64) (err error) {
// 防止脏数据, 强制计算和校验Porder的数据
ap.Porder.FlowID = 1
log.Info("ap.Porder (%+v)", ap.Porder)
// showType check
if len(ap.Porder.ShowType) > 0 {
var showTypes []int64
if showTypes, err = xstr.SplitInts(ap.Porder.ShowType); err != nil {
log.Error("SplitInts ShowType err, (%s),(%+v)", ap.Porder.ShowType, err)
return
}
//广告的展现形式太多或者太少
if len(showTypes) == 0 {
err = ecode.VideoupAdShowTypeErr
log.Error("check showTypes (%+v)|err(%+v)", ap.Porder, err)
return
}
for _, showType := range showTypes {
if showType > 0 {
if _, ok := s.PorderCfgs[showType]; !ok {
err = ecode.VideoupAdShowTypeErr
log.Error("VideoupAdShowTypeErr Porder(%+v)|err(%+v)", ap.Porder.ShowType, err)
return
}
}
}
}
// Official check
if ap.Porder.Official == 1 {
if _, ok := porder.OfficialIndustryMaps[ap.Porder.IndustryID]; !ok {
err = ecode.VideoupAdOfficialIndustryIDErr
log.Error("VideoupAdOfficialIndustryIDErr Porder(%+v)|err(%+v)", ap.Porder, err)
return
}
if ap.Porder.BrandID < 0 {
err = ecode.VideoupAdBrandIDErr
log.Error("VideoupAdBrandIDErr Porder(%+v)|err(%+v)", ap.Porder, err)
return
}
// logic map to OfficialIndustryMaps waiting for add other official industry
if _, ok := s.PorderGames[ap.Porder.BrandID]; !ok {
err = ecode.VideoupAdBrandIDErr
log.Error("VideoupAdBrandIDErr Porder(%+v)|err(%+v)", ap.Porder, err)
return
}
}
// Industry check
if ap.Porder.IndustryID > 0 {
if _, ok := s.PorderCfgs[ap.Porder.IndustryID]; !ok {
err = ecode.VideoupAdIndustryIDErr
log.Error("VideoupAdIndustryIDErr Porder(%+v)|err(%+v)", ap.Porder, err)
return
}
}
return
}
// checkDescForLength fn
func (s *Service) checkDescForLength(desc string, descFormatID int, typeID int16, copyright int8) (err error) {
if descFormatID == 0 {
if utf8.RuneCountInString(desc) > 250 {
err = ecode.VideoupFmDesLenOverLimit
log.Error("ecode.VideoupFmDesLenOverLimit, desc(%s),formatID(%d)", desc, descFormatID)
return
}
return
}
if utf8.RuneCountInString(desc) > 2000 {
err = ecode.VideoupFmDesLenOverLimit
log.Error("ecode.VideoupFmDesLenOverLimit, desc(%s),formatID(%d)", desc, descFormatID)
return
}
return
}
// checkVideos, 1: check len(video) == ? 0 , 2: check typeID in (145,146,147,83) and with multi Videos
func (s *Service) checkVideos(c context.Context, ap *archive.ArcParam) (err error) {
if len(ap.Videos) == 0 {
log.Error("checkVideos vds length 0")
err = ecode.VideoupZeroVideos
return
}
if len(ap.Videos) > 1 && ap.ForbidMultiVideoType() {
log.Error("checkVideos vds ForbidMultiVideoType, len(%d), type(%d) ", len(ap.Videos), ap.TypeID)
err = ecode.VideoupForbidMultiVideoForTypes
return
}
return
}
// tagsCheck fn
func (s *Service) tagsCheck(c context.Context, mid int64, tagName, ip string) (err error) {
var t *tag.Tag
tags := strings.Split(tagName, ",")
for i, tagStr := range tags {
if t, err = s.tag.TagCheck(c, mid, tagStr); err != nil {
log.Error("s.tag.TagCheck(%d, %+v, %s) error(%+v)", mid, t, ip, err)
err = nil
return
}
if t != nil && (t.State == tag.TagStateDel || t.State == tag.TagStateHide || t.Type == tag.OfficailActiveTag) {
newErr := ecode.VideoupTagForbid
err = ecode.Errorf(newErr, newErr.Message(), i+1)
log.Error("s.tag.VideoupTagForbid (%d, %+v, %s) error(%+v)", mid, t, ip, err)
return
}
}
return
}
// checkVideosMaxLimitForEdit fn
func (s *Service) checkVideosMaxLimitForEdit(vs []*archive.Video, pvideos []*archive.VideoParam) (addCnt int) {
fnMaps := make(map[string]string)
for _, v := range vs {
fnMaps[v.Filename] = v.Filename
}
for _, v := range pvideos {
if _, exist := fnMaps[v.Filename]; len(v.Filename) > 0 && !exist {
addCnt++
}
}
return
}
// checkPay fn
func (s *Service) checkAddPay(c context.Context, ap *archive.ArcParam, ip string) (err error) {
if err = s.checkPayProtocol(c, ap.Pay, ap.Mid); err != nil {
log.Error("s.checkAddPayProtocol (ap %+v) error(%+v)", ap, err)
return
}
if err = s.checkPayLimit(c, ap); err != nil {
log.Error("s.checkAddPayLimit (ap %+v) error(%+v)", ap, err)
return
}
if err = s.checkPayWithOrder(c, ap.Porder, ap.Pay, ap.OrderID, ap.Mid); err != nil {
log.Error("s.checkAddPayWithOrder (ap %+v) error(%+v)", ap, err)
return
}
return
}
// checkEditPay fn
// 关于RefuseUpdate
// 1.当ctime==ptime的时候也就是尚未稿件一审都是可以update付费模块的
// 2.开放过的,打回的稿件可以在任何时间点进行付费修改
// 3.开放过的非打回的稿件想要修改只能等60天时间过了之后(时间锁是为了保护普通用户的收看权利),否则自己申诉付费审核人员,要求强制打回
func (s *Service) checkEditPay(c context.Context, ap *archive.ArcParam, a *archive.Archive, ip string) (err error) {
_, registed, _ := s.pay.Ass(c, a.Aid, ip)
// 只要注册过付费信息都允许自主修改付费模块
if registed {
if err = s.checkPayProtocol(c, ap.Pay, ap.Mid); err != nil {
log.Error("s.checkAddPayProtocol (ap %+v) error(%+v)", ap, err)
return
}
if err = s.checkPayLimit(c, ap); err != nil {
log.Error("s.checkAddPayLimit (ap %+v) error(%+v)", ap, err)
return
}
if err = s.checkPayWithOrder(c, ap.Porder, ap.Pay, ap.OrderID, ap.Mid); err != nil {
log.Error("s.checkAddPayWithOrder (ap %+v) error(%+v)", ap, err)
return
}
//如果其他端都不传付费信息,那么就用现在有的来进行最后覆盖
if ap.Pay == nil {
ap.UgcPay = a.UgcPay
return
}
updateDeadLine := xtime.Time(a.PTime.Time().AddDate(0, 0, s.c.UgcPayAllowEditDays).Unix())
if ap.Pay != nil &&
a.CTime != a.PTime &&
a.State != archive.StateForbidRecicle &&
xtime.Time(time.Now().Unix()) < updateDeadLine {
log.Warn("checkEditPay ap.Pay.RefuseUpdate updateDeadLine (%+v)|(%+v)|(%+v)", a.Aid, a.CTime, a.PTime)
ap.Pay.RefuseUpdate = true
}
}
return
}

View File

@@ -0,0 +1,419 @@
package service
import (
"context"
"fmt"
"go-common/app/interface/main/videoup/model/archive"
accapi "go-common/app/service/main/account/api"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/sync/errgroup"
"strings"
"sync"
"unicode/utf8"
)
// checkAddStaff 新增稿件:检查联合投稿参数
func (s *Service) checkAddStaff(c context.Context, ap *archive.ArcParam, mid int64, ip string) (err error) {
var (
_logs []string
_logs2 []string
)
defer func() {
logStr := strings.Join(_logs, "\n")
if err != nil {
log.Error("s.checkAddStaff ap: %+v \nmid: %d \nlogs\n:%s", ap, mid, logStr)
} else {
log.Info("s.checkAddStaff ap: %+v \nmid: %d \nlogs\n%s", ap, mid, logStr)
}
}()
ap.HandleStaff = false
//新增稿件时如果没填写Staffs则不是联合投稿跳过检查
if len(ap.Staffs) == 0 {
ap.Staffs = make([]*archive.Staff, 0)
_logs = append(_logs, "INFO:非联合投稿,忽略")
return
}
//如果不是自制稿件不允许传Staffs
if ap.Copyright != archive.CopyrightOriginal && len(ap.Staffs) != 0 {
_logs = append(_logs, "ERR非自制稿件不允许传Staffs。")
err = ecode.VideoupStaffCopyright
return
}
//非全量的情况下检查当前UP主是在白名单中
_logs = append(_logs, fmt.Sprintf("INFO灰度开关 %v。分区配置 %v 注意这里打出的数据可能不是最新的有可能后面重新Load了", s.staffGary, s.staffTypeCache))
if err = s.checkStaffGray(ap.TypeID, mid); err != nil {
_logs = append(_logs, fmt.Sprintf("INFOUP主(%d)不在灰度名单中。", mid))
return
}
_logs2, err = s.checkStaffData(c, ap.TypeID, ap.Staffs, []*archive.Staff{}, ip)
_logs = append(_logs, _logs2...)
if err != nil {
return
}
//检查拉黑情况
_logs2, _, err = s.checkStaffRelation(c, mid, ap.Staffs, ip)
_logs = append(_logs, _logs2...)
if err != nil {
return
}
ap.HandleStaff = true
_logs = append(_logs, "INFO:通过")
return
}
// checkEditStaff 稿件编辑:检查联合投稿相关参数
func (s *Service) checkEditStaff(c context.Context, ap *archive.ArcParam, mid int64, a *archive.Archive, ip string) (err error) {
var (
cStaffs []*archive.Staff //当前稿件的联合投稿人
diffStaffs []*archive.Staff //变更的联合投稿人
_logs []string
_logs2 []string
)
defer func() {
logStr := strings.Join(_logs, "\n")
if err != nil {
log.Error("s.checkEditStaff ap: %+v \nmid: %d \narchive:%+v \nlogs:\n%v", ap, mid, a, logStr)
} else {
log.Info("s.checkEditStaff ap: %+v \nmid: %d \narchive:%+v \nlogs\n%v", ap, mid, a, logStr)
}
}()
ap.HandleStaff = false
//如果UP主不在白名单中不修改Staff数据
_logs = append(_logs, fmt.Sprintf("INFO灰度开关 %v分区配置 %v 注意这里打出的数据可能不是最新的有可能后面重新Load了", s.staffGary, s.staffTypeCache))
if err = s.checkStaffGray(ap.TypeID, mid); err != nil {
_logs = append(_logs, fmt.Sprintf("INFO:UP主(%d)不在灰度中", mid))
//如果UP主不在白名单中则将staff置空不修改staff
ap.Staffs = []*archive.Staff{}
ap.HandleStaff = false
err = nil
return
}
//获取当前稿件的Staff信息
if cStaffs, err = s.arc.ApplyStaffs(c, a.Aid, ip); err != nil {
_logs = append(_logs, fmt.Sprintf("ERR:获取线上Staffs失败err:%v", err))
return
}
if len(ap.Staffs) == 0 { //删除Staffs
_logs2, _, err = s.checkStaffRelation(c, mid, cStaffs, ip)
_logs = append(_logs, _logs2...)
if err != nil {
return
}
_logs = append(_logs, "INFO:UP主删除所有Staff")
ap.HandleStaff = true
return
}
//preEdit()的时候已经加上了以下"移区"、"换类型"的判断逻辑,这里冗余一下
//联合投稿不允许自制稿件改成非自制
if a.Copyright == archive.CopyrightOriginal && ap.Copyright != archive.CopyrightOriginal && a.AttrVal(archive.AttrBitStaff) == archive.AttrYes {
_logs = append(_logs, "ERROR:联合投稿不允许自制稿件改成非自制")
err = ecode.VideoupStaffChangeCopyright
return
}
_logs2, err = s.checkStaffData(c, ap.TypeID, ap.Staffs, cStaffs, ip)
_logs = append(_logs, _logs2...)
if err != nil {
return
}
//只验证修改过的Staff信息
changes, _logs2 := s.getStaffChanges(cStaffs, ap.Staffs)
_logs = append(_logs, _logs2...)
_logs = append(_logs, fmt.Sprintf("INFO:当前Staffs%+v 提交Staffs%+v 修改的Staffs%+v", cStaffs, ap.Staffs, changes))
for _, v := range changes {
for _, m := range v {
diffStaffs = append(diffStaffs, m)
}
}
_logs2, _, err = s.checkStaffRelation(c, mid, diffStaffs, ip)
_logs = append(_logs, _logs2...)
if err != nil {
return
}
ap.HandleStaff = true
_logs = append(_logs, "INFO:通过")
return
}
// checkStaffGray
func (s *Service) checkStaffGray(typeid int16, mid int64) (err error) {
if s.staffGary {
if _, ok := s.staffUps[mid]; !ok {
log.Error("当前Up主(%d)不在联合投稿白名单中。", mid)
err = ecode.VideoupStaffAuth
return
}
var ok1, ok2 bool
_, ok1 = s.staffTypeCache[typeid]
_, ok2 = s.staffTypeCache[0]
if ok1 && s.staffTypeCache[typeid].MaxStaff <= 0 {
log.Error("当前分区(%d)在联合投稿黑名单中。", typeid)
err = ecode.VideoupStaffTypeNotExists
return
}
if !ok1 && !ok2 {
log.Error("当前分区(%d)不在联合投稿白名单中。", typeid)
err = ecode.VideoupStaffTypeNotExists
return
}
}
return
}
// checkStaffData 检查联合投稿人的数据格式全量验证不管UP主有没有编辑都会走这个验证
func (s *Service) checkStaffData(c context.Context, typeid int16, staffs, cStaffs []*archive.Staff, ip string) (_logs []string, err error) {
var (
titles []string
cards map[int64]*accapi.Card
staffMids []int64
staffMap, cStaffMap map[int64]string
maxStaff int
)
staffMap = make(map[int64]string)
cStaffMap = make(map[int64]string)
if len(cStaffs) != 0 {
for _, v := range cStaffs {
cStaffMap[v.Mid] = v.Title
}
}
//检查分区的配置
if conf, ok := s.staffTypeCache[typeid]; ok {
maxStaff = conf.MaxStaff
} else if conf, ok := s.staffTypeCache[0]; ok {
maxStaff = conf.MaxStaff
} else {
_logs = append(_logs, fmt.Sprintf("ERR分区%d不在配置里。配置%v", typeid, s.staffTypeCache))
err = ecode.VideoupStaffTypeNotExists
return
}
if maxStaff == 0 {
_logs = append(_logs, fmt.Sprintf("ERR分区%d是黑名单。配置%v", typeid, s.staffTypeCache))
err = ecode.VideoupStaffTypeNotExists
return
}
//检查Staff数量
if len(staffs) > maxStaff {
_logs = append(_logs, fmt.Sprintf("ERRStaff数量超限。最多%d传递%d", maxStaff, len(staffs)))
err = ecode.VideoupStaffCountLimit
return
}
//检查Staff职能、Mid
for i, v := range staffs {
staffs[i].Title = strings.TrimSpace(v.Title)
v.Title = staffs[i].Title
if v.Mid == 0 {
_logs = append(_logs, "ERRStaff Mid为0。")
err = ecode.VideoupStaffMidInvalid
return
}
tl := utf8.RuneCountInString(v.Title)
if tl < 2 {
_logs = append(_logs, fmt.Sprintf("ERR职能(%v)长度不合法,长度:%d。", v.Title, tl))
err = ecode.VideoupStaffTitleShort
return
}
if tl > 4 {
_logs = append(_logs, fmt.Sprintf("ERR职能(%v)长度不合法,长度:%d。", v.Title, tl))
err = ecode.VideoupStaffTitleLength
return
}
if !_staffNameReg.MatchString(v.Title) {
_logs = append(_logs, fmt.Sprintf("ERR职能(%v)字符不合法。", v.Title))
err = ecode.VideoupStaffTitleChar
return
}
//不校验未修改的职能
if cTitle, ok := cStaffMap[v.Mid]; !ok || cTitle != v.Title {
titles = append(titles, v.Title)
}
staffMap[v.Mid] = v.Title
staffMids = append(staffMids, v.Mid)
}
if len(staffMap) != len(staffs) {
_logs = append(_logs, fmt.Sprintf("ERRStaff存在重复。传递%v去重后%v", staffs, staffMap))
err = ecode.VideoupStaffMidRepeat
return
}
//职能名称敏感词
_, hit, err := s.filter.VideoMultiFilter(c, titles, ip)
if err != nil {
_logs = append(_logs, fmt.Sprintf("ERR职能敏感词接口失败。error%v", err))
return
}
if len(hit) > 0 {
_logs = append(_logs, fmt.Sprintf("ERR职能存在敏感词。敏感词%v", hit))
err = ecode.VideoupStaffTitleFilter
return
}
//Staff Mid合法性检查
if cards, err = s.acc.Cards(c, staffMids, ip); err != nil {
_logs = append(_logs, fmt.Sprintf("ERRStaff账号信息获取失败。error%v", err))
return
}
for _, v := range staffMids {
if _, ok := cards[v]; !ok {
_logs = append(_logs, fmt.Sprintf("ERRStaff Mid(%d)不存在。", v))
err = ecode.VideoupStaffMidInvalid
return
}
}
return
}
// checkStaffRelation 检查联合投稿人拉黑关系
func (s *Service) checkStaffRelation(c context.Context, mid int64, staffs []*archive.Staff, ip string) (_logs []string, blocked []*archive.Staff, err error) {
var (
mids []int64
rels map[int64]int //relations
pass = true
staffMap map[int64]*archive.Staff
cards map[int64]*accapi.Card
)
blocked = make([]*archive.Staff, 0)
staffMap = make(map[int64]*archive.Staff)
for _, v := range staffs {
mids = append(mids, v.Mid)
staffMap[v.Mid] = v
}
if rels, err = s.FRelations(c, mid, mids, ip); err != nil {
_logs = append(_logs, fmt.Sprintf("ERR获取拉黑信息失败error:%v", err))
return
}
for k, v := range rels {
if v >= 128 {
_logs = append(_logs, fmt.Sprintf("ERRStaff(%d)在黑名单中", k))
pass = false
blocked = append(blocked, staffMap[k])
continue
}
}
cards, err = s.acc.Cards(c, mids, ip)
if !pass {
if err != nil {
_logs = append(_logs, fmt.Sprintf("ERR账号(%v)信息获取失败 error:%v", mids, err))
err = ecode.Errorf(ecode.VideoupStaffBlocked, ecode.VideoupStaffBlocked.Message(), "")
return
}
var bNames []string
for _, v := range blocked {
if _, ok := cards[v.Mid]; ok {
bNames = append(bNames, cards[v.Mid].Name)
} else {
_logs = append(_logs, fmt.Sprintf("ERR账号(%d)信息获取失败 error:%v", v.Mid, err))
}
}
err = ecode.Errorf(ecode.VideoupStaffBlocked, ecode.VideoupStaffBlocked.Message(), strings.Join(bNames, "、"))
}
for _, staff := range staffs {
if _, ok := cards[staff.Mid]; !ok {
_logs = append(_logs, fmt.Sprintf("ERR账号(%d)信息获取失败 error:%v", staff.Mid, err))
err = ecode.Errorf(ecode.CreativeAccServiceErr, "参与者(%d)信息获取失败", staff.Mid)
return
}
if cards[staff.Mid].Silence == 1 {
_logs = append(_logs, fmt.Sprintf("ERRStaff Mid(%d)被封禁。", staff.Mid))
err = ecode.Errorf(ecode.VideoupStaffUpSilence, ecode.VideoupStaffUpSilence.Message(), cards[staff.Mid].Name)
return
}
}
return
}
// getStaffChanges 获取联合投稿人的变更
func (s *Service) getStaffChanges(oS, nS []*archive.Staff) (changes map[string]map[int64]*archive.Staff, _logs []string) {
var (
allS = make([]*archive.Staff, 0)
oMap = make(map[int64]*archive.Staff)
nMap = make(map[int64]*archive.Staff)
)
str := ""
for _, v := range oS {
str += fmt.Sprintf("%d %s;", v.Mid, v.Title)
oMap[v.Mid] = v
}
_logs = append(_logs, " 原Staffs"+str)
str = ""
for _, v := range nS {
str += fmt.Sprintf("%d %s;", v.Mid, v.Title)
nMap[v.Mid] = v
}
_logs = append(_logs, " 提交Staffs"+str)
changes = make(map[string]map[int64]*archive.Staff)
changes["add"] = make(map[int64]*archive.Staff)
changes["edit"] = make(map[int64]*archive.Staff)
changes["del"] = make(map[int64]*archive.Staff)
allS = append(allS, oS...)
allS = append(allS, nS...)
for _, v := range allS {
if _, ok := oMap[v.Mid]; !ok {
changes["add"][v.Mid] = v
} else if _, ok := nMap[v.Mid]; !ok {
changes["del"][v.Mid] = v
} else if oMap[v.Mid].Title != nMap[v.Mid].Title {
changes["edit"][v.Mid] = v
}
}
return
}
// FRelations 获取用户与mid的关系Relations的反向
func (s *Service) FRelations(c context.Context, mid int64, fids []int64, ip string) (res map[int64]int, err error) {
var (
g, ctx = errgroup.WithContext(c)
sm sync.RWMutex
)
res = make(map[int64]int)
for _, v := range fids {
g.Go(func() error {
var r map[int64]int
if r, err = s.acc.Relations(ctx, v, []int64{mid}, ip); err != nil {
return err
}
sm.Lock()
res[v] = r[mid]
sm.Unlock()
return nil
})
}
if err = g.Wait(); err != nil {
log.Error("s.FRelations(%d,%v) error(%v)", mid, fids, err)
}
return
}
// checkStaffMoveType 联合投稿不允许移区和转载类型有申请的Staff时都不允许移区
func (s *Service) checkStaffMoveType(c context.Context, ap *archive.ArcParam, a *archive.Archive, ip string) (err error) {
var (
_logs []string
)
defer func() {
if err != nil {
log.Error("s.checkStaffMoveType ap: %+v, archive:%+v logs(%v)", ap, a, _logs)
} else {
log.Info("s.checkStaffMoveType ap: %+v, archive:%+v logs(%v)", ap, a, _logs)
}
}()
//如果没发生移区和修改转载类型,则直接通过
if ap.TypeID == a.TypeID && a.Copyright == ap.Copyright {
_logs = append(_logs, "INFO:没有修改分区和转载类型")
return
}
var (
cStaffs []*archive.Staff //当前稿件的联合投稿人
)
if cStaffs, err = s.arc.ApplyStaffs(c, a.Aid, ip); err != nil {
_logs = append(_logs, fmt.Sprintf("ERR:获取Staff失败。error:%v", err))
log.Error("checkStaffMoveType() 获取线上Staffs失败err:%v", err)
return
}
if len(cStaffs) != 0 {
_logs = append(_logs, fmt.Sprintf("ERR: 不允许操作。当前Staffs(%v)", cStaffs))
err = ecode.VideoupStaffChangeTypeCopyright
return
}
_logs = append(_logs, "INFO:通过")
return
}

View File

@@ -0,0 +1,123 @@
package service
import (
"bytes"
"context"
"net"
"go-common/app/interface/main/videoup/model/archive"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/net/metadata"
"go-common/library/sync/errgroup"
)
// ClientAdd add archive by client.
func (s *Service) ClientAdd(c context.Context, mid int64, ap *archive.ArcParam) (aid int64, err error) {
ip := metadata.String(c, metadata.RemoteIP)
ap.IPv6 = net.ParseIP(ip)
defer func() {
if err != nil && err != ecode.VideoupCanotRepeat {
s.acc.DelSubmitCache(c, ap.Mid, ap.Title)
}
}()
if err = s.checkIdentify(c, mid, ip); err != nil {
log.Error("s.CheckIdentify mid(%d) ap(%+v) error(%v)", mid, ap, err)
return
}
if err = s.tagsCheck(c, mid, ap.Tag, ip); err != nil {
log.Error("s.tagsCheck mid(%d) ap(%+v) error(%v)", mid, ap.Tag, err)
return
}
// pre check
if err = s.preAdd(c, mid, ap, ip, archive.UpFromWindows); err != nil {
return
}
// add
if aid, err = s.arc.Add(c, ap, ip); err != nil || aid == 0 {
return
}
g := &errgroup.Group{}
ctx := context.TODO()
g.Go(func() error {
s.dealOrder(ctx, mid, aid, ap.OrderID, ip)
return nil
})
g.Go(func() error {
s.freshFavs(ctx, mid, ap, ip)
return nil
})
g.Go(func() error {
s.dealElec(ctx, ap.OpenElec, aid, mid, ip)
return nil
})
g.Wait()
return
}
// ClientEdit edit archive by client.
func (s *Service) ClientEdit(c context.Context, ap *archive.ArcParam, mid int64) (err error) {
ip := metadata.String(c, metadata.RemoteIP)
ap.IPv6 = net.ParseIP(ip)
if err = s.checkIdentify(c, mid, ip); err != nil {
log.Error("s.CheckIdentify mid(%d) ap(%+v) error(%v)", mid, ap, err)
return
}
if err = s.tagsCheck(c, mid, ap.Tag, ip); err != nil {
log.Error("s.tagsCheck mid(%d) ap(%+v) error(%v)", mid, ap.Tag, err)
return
}
var (
a = &archive.Archive{}
vs = []*archive.Video{}
)
if a, vs, err = s.arc.View(c, ap.Aid, ip); err != nil {
log.Error("s.arc.View err(%v) | aid(%d) ip(%s)", err, ap.Aid, ip)
return
}
if a == nil {
log.Error("s.arc.View(%d) not found", mid)
err = ecode.ArchiveNotExist
return
}
if nvsCnt := s.checkVideosMaxLimitForEdit(vs, ap.Videos); nvsCnt > s.c.MaxAddVsCnt {
log.Error("checkVideosMaxLimitForEdit, vsCnt(%d), limit(%d), nvsCnt(%d)", len(vs), s.c.MaxAddVsCnt, nvsCnt)
err = ecode.VideoupVideosMaxLimit
return
}
// pre check
if err = s.preEdit(c, mid, a, vs, ap, ip, archive.UpFromWindows); err != nil {
return
}
// edit
if err = s.arc.Edit(c, ap, ip); err != nil {
return
}
g := &errgroup.Group{}
ctx := context.TODO()
g.Go(func() error {
s.dealElec(ctx, ap.OpenElec, ap.Aid, mid, ip)
return nil
})
g.Wait()
return
}
// ClientUpCover client upload cover.
func (s *Service) ClientUpCover(c context.Context, fileType string, body []byte, mid int64) (url string, err error) {
if len(body) == 0 {
err = ecode.FileNotExists
return
}
if len(body) > s.c.Bfs.MaxFileSize {
err = ecode.FileTooLarge
return
}
url, err = s.bfs.Upload(c, fileType, bytes.NewReader(body))
if err != nil {
log.Error("s.bfs.Upload error(%v)", err)
}
return
}

View File

@@ -0,0 +1,191 @@
package service
import (
"bytes"
"context"
"go-common/library/net/metadata"
"hash/crc32"
"net"
"strconv"
"strings"
"go-common/app/interface/main/videoup/model/archive"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/sync/errgroup"
)
// CreatorEdit edit archive by creator.
func (s *Service) CreatorEdit(c context.Context, mid int64, cp *archive.CreatorParam) (err error) {
ip := metadata.String(c, metadata.RemoteIP)
if err = s.checkIdentify(c, mid, ip); err != nil {
log.Error("s.CheckIdentify mid(%d) ap(%+v) error(%v)", mid, cp, err)
return
}
var (
a = &archive.Archive{}
vs = make([]*archive.Video, 0)
)
if a, vs, err = s.arc.View(c, cp.Aid, ip); err != nil {
log.Error("s.arc.View err(%v) | aid(%d) ip(%s)", err, cp.Aid, ip)
return
}
if a == nil || vs == nil {
log.Error("s.arc.View(%d) not found", mid)
err = ecode.ArchiveNotExist
return
}
ap := &archive.ArcParam{
Aid: cp.Aid,
Tag: cp.Tag,
Title: cp.Title,
Desc: cp.Desc,
OpenElec: cp.OpenElec,
// ------ diff values ----- //
Mid: a.Mid,
Author: a.Author,
TypeID: a.TypeID,
Cover: coverURL(a.Cover),
Copyright: a.Copyright,
NoReprint: a.NoReprint,
OrderID: a.OrderID,
Source: a.Source,
Attribute: a.Attribute,
UpFrom: archive.UpFromCreator,
DTime: a.DTime,
DescFormatID: a.DescFormatID,
Dynamic: a.Dynamic,
IPv6: net.ParseIP(ip),
MissionID: int(a.MissionID),
}
for _, vp := range vs {
ap.Videos = append(ap.Videos, &archive.VideoParam{
Title: vp.Title,
Desc: vp.Desc,
Filename: vp.Filename,
})
}
if only := onlyChangeTagArc(cp, a); only {
ap.Tag = s.removeDupTag(ap.Tag)
if !s.allowTag(ap.Tag) {
log.Error("s.allowTag mid(%d) ap.Tag(%s) tag name or number too large or Empty", mid, ap.Tag)
err = ecode.VideoupTagErr
return
}
if err = s.tagsCheck(c, mid, ap.Tag, ip); err != nil {
log.Error("s.tagsCheck mid(%d) ap(%+v) error(%v)", mid, ap.Tag, err)
return
}
if a.Tag != ap.Tag {
s.arc.TagUp(c, ap.Aid, ap.Tag, ip)
}
s.dealTag(c, mid, ap.Aid, a.Tag, ap.Tag, ip, ap.TypeID)
} else {
if err = s.preEdit(c, mid, a, vs, ap, ip, archive.UpFromCreator); err != nil {
log.Error("s.preCreatorEdit mid(%d) ap(%+v) error(%v)", mid, ap, err)
return
}
if err = s.arc.Edit(c, ap, ip); err != nil {
return
}
}
s.dealElec(c, ap.OpenElec, ap.Aid, mid, ip)
return
}
// 判断是否只在这种特殊的情况下,开放浏览/待审的稿件只修改了Tag信息
func onlyChangeTagArc(cp *archive.CreatorParam, a *archive.Archive) (only bool) {
st := a.State == archive.StateForbidSubmit ||
a.State == archive.StateForbidUserDelay ||
a.State == archive.StateOpen ||
a.State == archive.StateOrange ||
a.State == archive.StateForbidWait
ch := a.Title == cp.Title &&
a.Desc == cp.Desc &&
a.Tag != cp.Tag
if st && ch {
only = true
}
return
}
// CreatorAdd add archive by creator.
func (s *Service) CreatorAdd(c context.Context, mid int64, ap *archive.ArcParam) (aid int64, err error) {
ip := metadata.String(c, metadata.RemoteIP)
ap.IPv6 = net.ParseIP(ip)
defer func() {
if err != nil && err != ecode.VideoupCanotRepeat {
s.acc.DelSubmitCache(c, ap.Mid, ap.Title)
}
}()
if err = s.checkIdentify(c, mid, ip); err != nil {
log.Error("s.CheckIdentify mid(%d) ap(%+v) error(%v)", mid, ap, err)
return
}
// pre check
if err = s.preAdd(c, mid, ap, ip, archive.UpFromCreator); err != nil {
return
}
// add
if aid, err = s.arc.Add(c, ap, ip); err != nil || aid == 0 {
return
}
g := &errgroup.Group{}
ctx := context.TODO()
g.Go(func() error {
s.dealOrder(ctx, mid, aid, ap.OrderID, ip)
return nil
})
g.Go(func() error {
s.dealElec(ctx, ap.OpenElec, ap.Aid, mid, ip)
return nil
})
g.Wait()
return
}
// CreatorUpCover creator upload cover.
func (s *Service) CreatorUpCover(c context.Context, fileType string, body []byte, mid int64) (url string, err error) {
if len(body) == 0 {
err = ecode.FileNotExists
return
}
if len(body) > s.c.Bfs.MaxFileSize {
err = ecode.FileTooLarge
return
}
url, err = s.bfs.Upload(c, fileType, bytes.NewReader(body))
if err != nil {
log.Error("s.bfs.Upload error(%v)", err)
}
return
}
// coverURL convert cover url to full url.
func coverURL(uri string) (cover string) {
if uri == "" {
//cover = "http://static.hdslb.com/images/transparent.gif"
return
}
cover = uri
if strings.Index(uri, "http://") == 0 {
return
}
if len(uri) >= 10 && uri[:10] == "/templets/" {
return
}
if strings.HasPrefix(uri, "group1") {
cover = "http://i0.hdslb.com/" + uri
return
}
if pos := strings.Index(uri, "/uploads/"); pos != -1 && (pos == 0 || pos == 3) {
cover = uri[pos+8:]
}
cover = strings.Replace(cover, "{IMG}", "", -1)
cover = "http://i" + strconv.FormatInt(int64(crc32.ChecksumIEEE([]byte(cover)))%3, 10) + ".hdslb.com" + cover
return
}

Some files were not shown because too many files have changed in this diff Show More