100 lines
3.8 KiB
Go
100 lines
3.8 KiB
Go
// 功能描述:报修现场照片关联与本人受保护读取;不公开照片文件目录。
|
||
// 版本:1.0.0。
|
||
package user
|
||
|
||
import (
|
||
"crypto/sha256"
|
||
"fmt"
|
||
"git.apinb.com/bsm-sdk/core/errcode"
|
||
"git.apinb.com/heqiapp/platforms/backend/api/internal/impl"
|
||
common "git.apinb.com/heqiapp/platforms/backend/api/internal/logic/common"
|
||
"git.apinb.com/heqiapp/platforms/backend/api/internal/logic/upload"
|
||
"git.apinb.com/heqiapp/platforms/backend/api/internal/models"
|
||
"github.com/gin-gonic/gin"
|
||
"gorm.io/gorm"
|
||
"time"
|
||
)
|
||
|
||
// ticketPhotoRequest 记录添加时间,导入照片不冒充已验证的原始拍摄时间。
|
||
type ticketPhotoRequest struct {
|
||
URI string `json:"uri" binding:"required"`
|
||
AddedAt time.Time `json:"added_at" binding:"required"`
|
||
Source string `json:"source" binding:"required,oneof=camera gallery"`
|
||
}
|
||
|
||
func UploadTicketPhoto(ctx *gin.Context) {
|
||
account, ok := common.UserAccount(ctx)
|
||
if !ok {
|
||
return
|
||
}
|
||
upload.UploadTicketPhoto(ctx, account.Identity)
|
||
}
|
||
|
||
// UploadedTicketPhoto 恢复本人草稿照片,不接受其他账户或任意路径。
|
||
func UploadedTicketPhoto(ctx *gin.Context) {
|
||
account, ok := common.UserAccount(ctx)
|
||
if !ok {
|
||
return
|
||
}
|
||
upload.ServeOwnedTicketPhoto(ctx, account.Identity, ctx.Param("name"))
|
||
}
|
||
|
||
// saveTicketPhotos 与工单创建共用事务,任一图片不属于本人时全部回滚。
|
||
func saveTicketPhotos(tx *gorm.DB, ticket models.CsTicket, owner string, photos []ticketPhotoRequest) error {
|
||
seen := map[string]bool{}
|
||
for index, photo := range photos {
|
||
if seen[photo.URI] || !upload.OwnsTicketPhoto(owner, photo.URI) || photo.AddedAt.IsZero() || photo.AddedAt.After(time.Now().Add(5*time.Minute)) {
|
||
return errcode.ErrInvalidArgument
|
||
}
|
||
seen[photo.URI] = true
|
||
evidence := models.CsTicketEvidence{
|
||
Entity: common.NewEntity(common.StatusEnable), CsTicketID: ticket.ID, EvidenceType: "reported", MediaType: "image", FileURI: photo.URI,
|
||
CapturedAt: photo.AddedAt, ReceivedAt: time.Now(), Source: "user_" + photo.Source, IntegrityStatus: "capture_time_unknown", OperatorIdentity: owner,
|
||
RequestNo: fmt.Sprintf("%x", sha256.Sum256([]byte(fmt.Sprintf("user-photo:%s:%d", ticket.Identity, index)))),
|
||
}
|
||
if err := tx.Create(&evidence).Error; err != nil {
|
||
return err
|
||
}
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// ticketPhotosForList 一次查询本人列表涉及的证据,只发布元数据与公开证据UUID。
|
||
func ticketPhotosForList(tickets []models.CsTicket) (map[uint64][]gin.H, error) {
|
||
result := map[uint64][]gin.H{}
|
||
ids := make([]uint64, 0, len(tickets))
|
||
for _, ticket := range tickets {
|
||
ids = append(ids, ticket.ID)
|
||
}
|
||
if len(ids) == 0 {
|
||
return result, nil
|
||
}
|
||
var photos []models.CsTicketEvidence
|
||
if err := impl.DBService.Where("cs_ticket_id IN ? AND evidence_type = ? AND status <> ?", ids, "reported", common.StatusArchived).Order("created_at asc").Find(&photos).Error; err != nil {
|
||
return nil, err
|
||
}
|
||
for _, photo := range photos {
|
||
result[photo.CsTicketID] = append(result[photo.CsTicketID], gin.H{"identity": photo.Identity, "added_at": photo.CapturedAt, "source": photo.Source, "integrity_status": photo.IntegrityStatus})
|
||
}
|
||
return result, nil
|
||
}
|
||
|
||
// TicketPhoto 不允许借工单UUID读取其他工单照片,也不允许读取他人报修。
|
||
func TicketPhoto(ctx *gin.Context) {
|
||
account, ok := common.UserAccount(ctx)
|
||
if !ok {
|
||
return
|
||
}
|
||
var ticket models.CsTicket
|
||
if impl.DBService.Where("identity = ? AND user_account_id = ? AND status <> ?", ctx.Param("identity"), account.ID, common.StatusArchived).First(&ticket).Error != nil {
|
||
ctx.Status(404)
|
||
return
|
||
}
|
||
var photo models.CsTicketEvidence
|
||
if impl.DBService.Where("identity = ? AND cs_ticket_id = ? AND evidence_type = ? AND status <> ?", ctx.Param("photoIdentity"), ticket.ID, "reported", common.StatusArchived).First(&photo).Error != nil {
|
||
ctx.Status(404)
|
||
return
|
||
}
|
||
upload.ServeTicketPhoto(ctx, account.Identity, photo.FileURI)
|
||
}
|