package router
import (
"github.com/gin-gonic/gin" "your_project/adapter/handler"
)
func AddServiceReportRoutes(r *gin.Engine) {
serviceReportGroup := r.Group("/service-reports")
{
serviceReportGroup.GET("/:serviceReportId/shared-tokens",
handler.GetServiceReportSharedTokensHandler)
}
}
srst.uuid,
srst.email,
srst.started_at AS "startedAt",
srst.starter_id AS "starterId",
start_u.name AS "starterName",
CASE
WHEN srst.started_at IS NOT NULL THEN (srst.started_at + INTERVAL '90 days')
ELSE NULL
END AS "expiredAt",
srst.stopper_id AS "stopperId",
stop_u.name AS "stopperName",
srst.stopped_at AS "stoppedAt"
FROM
service_report_shared_tokens srst LEFT JOIN users start_u ON srst.starter_id = start_u.id LEFT JOIN users stop_u ON srst.stopper_id = stop_u.idWHERE
srst.service_report_id = $1ORDER BY
srst.created_at DESC;
package adaptersqlfile
import (
"embed" "io/fs" "log"
)
var sqlFS embed.FS
func GetServiceReportSharedTokensSQL() string {
content, err := fs.ReadFile(sqlFS, "adapterquery.sql")
if err != nil {
log.Printf("SQL文件读取失败: %v", err)
return ""
}
return string(content)
}
package usecase
import (
"database/sql" "errors" "log" "strings" "your_project/adapter/adaptersqlfile"
)
type SharedToken struct {
UUID string `json:"uuid"` Email *string `json:"email,omitempty"` StartedAt string `json:"startedAt"` StarterID int `json:"starterId"` StarterName string `json:"starterName"` ExpiredAt string `json:"expiredAt"` StopperID *int `json:"stopperId,omitempty"` StopperName *string `json:"stopperName,omitempty"` StoppedAt *string `json:"stoppedAt,omitempty"`
}
type ErrorResponse struct {
Type string `json:"type"`
Title string `json:"title"`
Errors []struct {
ErrorCode string `json:"errorCode"`
Message string `json:"message"`
Name *string `json:"name,omitempty"`
Validator *string `json:"validator,omitempty"`
Param *string `json:"param,omitempty"`
} `json:"errors"`
}
func ValidateFurunoEmail(email string) bool {
parts := strings.Split(email, "@")
if len(parts) < 2 {
return false
}
return parts[1] == "furuno.co.jp"
}
func GetServiceReportSharedTokens(db *sql.DB, serviceReportID int, userEmail string) ([]SharedToken, error) {
// 权限验证
if !ValidateFurunoEmail(userEmail) {
return nil, errors.New("E403-4: Require Furuno Permission")
}
// 获取SQL查询
sqlQuery := adaptersqlfile.GetServiceReportSharedTokensSQL()
if sqlQuery == "" {
return nil, errors.New("E500-1: SQL query not found")
}
// 执行查询
rows, err := db.Query(sqlQuery, serviceReportID)
if err != nil {
log.Printf("数据库查询错误: %v", err)
return nil, errors.New("E500-1: Database query failed")
}
defer rows.Close()
// 处理结果
var tokens []SharedToken
for rows.Next() {
var token SharedToken
err := rows.Scan(
&token.UUID,
&token.Email,
&token.StartedAt,
&token.StarterID,
&token.StarterName,
&token.ExpiredAt,
&token.StopperID,
&token.StopperName,
&token.StoppedAt,
)
if err != nil {
log.Printf("行扫描错误: %v", err)
continue
}
tokens = append(tokens, token)
}
if err := rows.Err(); err != nil {
log.Printf("行迭代错误: %v", err)
return nil, errors.New("E500-1: Row iteration error")
}
return tokens, nil
}
func CreateErrorResponse(errorType, title, errorCode, message string) ErrorResponse {
resp := ErrorResponse{
Type: errorType,
Title: title,
Errors: []struct {
ErrorCode string `json:"errorCode"`
Message string `json:"message"`
package handler
import (
"database/sql" "log" "net/http" "strconv" "your_project/usecase"
"github.com/gin-gonic/gin"
)
func GetServiceReportSharedTokensHandler(c *gin.Context) {
// 获取路径参数
serviceReportID, err := strconv.Atoi(c.Param("serviceReportId"))
if err != nil {
log.Printf("无效的服务报告ID: %s", c.Param("serviceReportId"))
c.JSON(http.StatusBadRequest, createErrorResponse(
"https://webapi.sapli.fdev2.net/#/components/responses/InvalidParameter",
"Invalid Parameter",
"E400-1",
"Invalid serviceReportId format",
))
return
}
// 获取用户信息
userInfo, exists := c.Get("UserKey")
if !exists {
log.Println("用户信息未找到")
c.JSON(http.StatusUnauthorized, createErrorResponse(
"https://webapi.sapli.fdev2.net/#/components/responses/Unauthorized",
"Unauthorized",
"E401-1",
"User information not found",
))
return
}
// 提取用户邮箱
user, ok := userInfo.(map[string]interface{})
if !ok {
log.Println("用户信息格式错误")
c.JSON(http.StatusInternalServerError, createErrorResponse(
"https://webapi.sapli.fdev2.net/#/components/responses/InternalServerError",
"Internal Server Error",
"E500-1",
"Invalid user data format",
))
return
}
userEmail, ok := user["email"].(string)
if !ok || userEmail == "" {
log.Println("用户邮箱缺失")
c.JSON(http.StatusUnauthorized, createErrorResponse(
"https://webapi.sapli.fdev2.net/#/components/responses/Unauthorized",
"Unauthorized",
"E401-2",
"User email not found",
))
return
}
log.Printf("请求开始 - 服务报告ID: %d, 用户: %s", serviceReportID, userEmail)
// 获取数据库连接
db, exists := c.Get("db")
if !exists {
log.Println("数据库连接未找到")
c.JSON(http.StatusInternalServerError, createErrorResponse(
"https://webapi.sapli.fdev2.net/#/components/responses/InternalServerError",
"Internal Server Error",
"E500-1",
"Database connection not found",
))
return
}
sqlDB, ok := db.(*sql.DB)
if !ok {
log.Println("无效的数据库连接类型")
c.JSON(http.StatusInternalServerError, createErrorResponse(
"https://webapi.sapli.fdev2.net/#/components/responses/InternalServerError",
"Internal Server Error",
"E500-1",
"Invalid database connection type",
))
return
}
// 获取共享历史数据
tokens, err := usecase.GetServiceReportSharedTokens(sqlDB, serviceReportID, userEmail)
if err != nil {
handleServiceError(c, err)
return
}
log.Printf("请求成功 - 服务报告ID: %d, 返回记录数: %d", serviceReportID, len(tokens))
// 返回成功响应
c.JSON(http.StatusOK, gin.H{
"sharedTokens": tokens,
})
}
func handleServiceError(c *gin.Context, err error) {
errorMsg := err.Error()
switch {
case strings.Contains(errorMsg, "E403-4"):
log.Printf("权限错误: %s", errorMsg)
c.JSON(http.StatusForbidden, createErrorResponse(
"https://webapi.sapli.fdev2.net/#/components/responses/Forbidden",
"Forbidden",
"E403-4",
"Require Furuno Permission",
))
case strings.Contains(errorMsg, "E400"):
log.Printf("客户端错误: %s", errorMsg)
parts := strings.SplitN(errorMsg, ":", 2)
message := "Invalid request"
if len(parts) > 1 {
message = strings.TrimSpace(parts[1])
}
c.JSON(http.StatusBadRequest, createErrorResponse(
"https://webapi.sapli.fdev2.net/#/components/responses/InvalidParameter",
"Invalid Parameter",
"E400-1",
message,
))
default:
log.Printf("服务器错误: %v", err)
c.JSON(http.StatusInternalServerError, createErrorResponse(
"https://webapi.sapli.fdev2.net/#/components/responses/InternalServerError",
"Internal Server Error",
"E500-1",
"Internal server error",
))
}
}
func createErrorResponse(errorType, title, errorCode, message string) gin.H {
return gin.H{
"type": errorType,
"title": title,
"errors": []gin.H{
{
"errorCode": errorCode,
"message": message,
},
},
}
}