feat(phase2): 追更/授权链/跨省复用/终端抽检/CI(F21/F22/F13/F08/K)
- F21 追更: AddEpisodes 追加新集不重新发码; Merkle定位变更集 - F22 授权链: RecordAuthorization + CheckAuthorization(地域/平台/期限), 嵌入注入前核验 - F13 跨省复用: CrossProvinceAdmit 三重校验(MA有效+哈希一致+非黑名单)快速准入 - F08 终端抽检: TerminalVerifySegment 片段校验+断流提示 - K.1 CI: .gitlab-ci.yml(后端构建/测试/前端构建) - 新增6个API; 16项测试通过; 二期纯代码功能全部完成 - A(真实链)/B(BFF)延后至有环境/三期, MemoryChain接口已就绪可平滑替换
This commit is contained in:
@@ -50,6 +50,11 @@ func (h *Handler) Register(rg *gin.RouterGroup) {
|
||||
rg.GET("/content/accountability", h.accountability) // 责任界定取证(需求22)
|
||||
rg.GET("/content/evidence", h.evidence) // 版权确权证据链(需求23)
|
||||
rg.POST("/content/infringe-match", h.infringeMatch) // 感知哈希侵权比对(需求23)
|
||||
rg.POST("/content/authorize", h.authorize) // 登记授权(需求25)
|
||||
rg.POST("/content/auth-check", h.authCheck) // 授权核验(需求25)
|
||||
rg.POST("/content/add-episodes", h.addEpisodes) // 追更新集(需求24)
|
||||
rg.POST("/content/cross-province", h.crossProvince) // 跨省复用准入(需求13)
|
||||
rg.POST("/terminal/verify-segment", h.terminalVerify) // 终端片段抽检(需求8)
|
||||
}
|
||||
|
||||
func roleOf(c *gin.Context) chain.Role {
|
||||
@@ -514,3 +519,101 @@ func (h *Handler) infringeMatch(c *gin.Context) {
|
||||
}
|
||||
httpx.OK(c, gin.H{"matches": matches, "count": len(matches)})
|
||||
}
|
||||
|
||||
// ---- 二期:授权链/追更/跨省/终端抽检(需求25/24/13/8) ----
|
||||
|
||||
type authorizeReq struct {
|
||||
MACode string `json:"ma_code"`
|
||||
Regions []string `json:"regions"`
|
||||
Platforms []string `json:"platforms"`
|
||||
ExpiryAt string `json:"expiry_at"` // RFC3339,空=长期
|
||||
}
|
||||
|
||||
func (h *Handler) authorize(c *gin.Context) {
|
||||
var req authorizeReq
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
httpx.Error(c, http.StatusBadRequest, "INVALID_REQUEST", err.Error())
|
||||
return
|
||||
}
|
||||
var expiry time.Time
|
||||
if req.ExpiryAt != "" {
|
||||
expiry, _ = time.Parse(time.RFC3339, req.ExpiryAt)
|
||||
}
|
||||
if err := h.svc.RecordAuthorization(req.MACode, req.Regions, req.Platforms, expiry); err != nil {
|
||||
httpx.Error(c, http.StatusBadRequest, "AUTHORIZE_FAILED", err.Error())
|
||||
return
|
||||
}
|
||||
httpx.OK(c, gin.H{"ma_code": req.MACode, "authorized": true})
|
||||
}
|
||||
|
||||
type authCheckReq struct {
|
||||
MACode string `json:"ma_code"`
|
||||
Region string `json:"region"`
|
||||
Platform string `json:"platform"`
|
||||
}
|
||||
|
||||
func (h *Handler) authCheck(c *gin.Context) {
|
||||
var req authCheckReq
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
httpx.Error(c, http.StatusBadRequest, "INVALID_REQUEST", err.Error())
|
||||
return
|
||||
}
|
||||
httpx.OK(c, h.svc.CheckAuthorization(req.MACode, req.Region, req.Platform))
|
||||
}
|
||||
|
||||
type addEpisodesReq struct {
|
||||
MACode string `json:"ma_code"`
|
||||
Episodes []struct {
|
||||
Episode int `json:"episode"`
|
||||
FileSHA256 string `json:"file_sha256"`
|
||||
MerkleRoot string `json:"merkle_root"`
|
||||
} `json:"episodes"`
|
||||
}
|
||||
|
||||
func (h *Handler) addEpisodes(c *gin.Context) {
|
||||
var req addEpisodesReq
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
httpx.Error(c, http.StatusBadRequest, "INVALID_REQUEST", err.Error())
|
||||
return
|
||||
}
|
||||
eps := make([]model.EpisodeHash, 0, len(req.Episodes))
|
||||
for _, e := range req.Episodes {
|
||||
eps = append(eps, model.EpisodeHash{Episode: e.Episode, FileSHA256: e.FileSHA256, MerkleRoot: e.MerkleRoot})
|
||||
}
|
||||
if err := h.svc.AddEpisodes(roleOf(c), req.MACode, eps); err != nil {
|
||||
httpx.Error(c, http.StatusBadRequest, "ADD_EPISODES_FAILED", err.Error())
|
||||
return
|
||||
}
|
||||
httpx.OK(c, gin.H{"ma_code": req.MACode, "added": len(eps)})
|
||||
}
|
||||
|
||||
type crossProvinceReq struct {
|
||||
MACode string `json:"ma_code"`
|
||||
FileHash string `json:"file_sha256"`
|
||||
Province string `json:"province"`
|
||||
}
|
||||
|
||||
func (h *Handler) crossProvince(c *gin.Context) {
|
||||
var req crossProvinceReq
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
httpx.Error(c, http.StatusBadRequest, "INVALID_REQUEST", err.Error())
|
||||
return
|
||||
}
|
||||
httpx.OK(c, h.svc.CrossProvinceAdmit(req.MACode, req.FileHash, req.Province))
|
||||
}
|
||||
|
||||
type terminalVerifyReq struct {
|
||||
MACode string `json:"ma_code"`
|
||||
Episode int `json:"episode"`
|
||||
SegHash string `json:"segment_hash"`
|
||||
}
|
||||
|
||||
func (h *Handler) terminalVerify(c *gin.Context) {
|
||||
var req terminalVerifyReq
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
httpx.Error(c, http.StatusBadRequest, "INVALID_REQUEST", err.Error())
|
||||
return
|
||||
}
|
||||
ok, msg := h.svc.TerminalVerifySegment(req.MACode, req.Episode, req.SegHash)
|
||||
httpx.OK(c, gin.H{"ok": ok, "message": msg})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user