|
@@ -2,6 +2,7 @@ package services
|
|
|
|
|
|
import (
|
|
|
"archive/zip"
|
|
|
+ "encoding/json"
|
|
|
"errors"
|
|
|
"eta/eta_mobile/models"
|
|
|
"eta/eta_mobile/models/report"
|
|
@@ -11,10 +12,17 @@ import (
|
|
|
"fmt"
|
|
|
"github.com/rdlucklib/rdluck_tools/file"
|
|
|
"github.com/rdlucklib/rdluck_tools/http"
|
|
|
+ html2 "golang.org/x/net/html"
|
|
|
+ "net/url"
|
|
|
"os"
|
|
|
"path"
|
|
|
"strconv"
|
|
|
+ "strings"
|
|
|
"time"
|
|
|
+
|
|
|
+ "github.com/beego/beego/v2/server/web"
|
|
|
+ "github.com/beego/beego/v2/server/web/context"
|
|
|
+ "github.com/go-redis/redis/v8"
|
|
|
)
|
|
|
|
|
|
|
|
@@ -1207,7 +1215,7 @@ func PublishReport(reportId int, reportUrl string, sysUser *system.Admin) (tips
|
|
|
|
|
|
|
|
|
{
|
|
|
- reportPdfUrl := GetGeneralPdfUrl(reportInfo.ReportCode, reportInfo.ReportLayout)
|
|
|
+ reportPdfUrl := GetGeneralPdfUrl(reportInfo.Id, reportInfo.ReportCode, reportInfo.ReportLayout)
|
|
|
go Report2pdfAndJpeg(reportPdfUrl, reportId, 1)
|
|
|
}
|
|
|
|
|
@@ -1334,7 +1342,7 @@ func PublishChapterReport(reportInfo *models.Report, reportUrl string, sysUser *
|
|
|
|
|
|
|
|
|
{
|
|
|
- reportPdfUrl := GetGeneralPdfUrl(reportInfo.ReportCode, reportInfo.ReportLayout)
|
|
|
+ reportPdfUrl := GetGeneralPdfUrl(reportInfo.Id, reportInfo.ReportCode, reportInfo.ReportLayout)
|
|
|
go Report2pdfAndJpeg(reportPdfUrl, reportId, 1)
|
|
|
}
|
|
|
|
|
@@ -1495,7 +1503,7 @@ func UpdateReportVideo(reportInfo *models.Report) {
|
|
|
|
|
|
|
|
|
|
|
|
-func GetGeneralPdfUrl(reportCode string, reportLayout int8) (pdfUrl string) {
|
|
|
+func GetGeneralPdfUrl(reportId int, reportCode string, reportLayout int8) (pdfUrl string) {
|
|
|
conf, e := models.GetBusinessConfByKey("ReportViewUrl")
|
|
|
if e != nil {
|
|
|
return
|
|
@@ -1510,5 +1518,409 @@ func GetGeneralPdfUrl(reportCode string, reportLayout int8) (pdfUrl string) {
|
|
|
pdfUrl = fmt.Sprintf("%s/reportshare_smart_pdf?code=%s", conf.ConfVal, reportCode)
|
|
|
}
|
|
|
|
|
|
+ if pdfUrl != "" {
|
|
|
+ token := utils.MD5(fmt.Sprint(pdfUrl, time.Now().UnixNano()/1e6))
|
|
|
+ e := generalReportAuthToken(token, ``, reportId)
|
|
|
+ if e == nil {
|
|
|
+ pdfUrl = fmt.Sprintf("%s&authToken=%s", pdfUrl, token)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+func HandleReportContent(body string, opType string, tokenMap map[string]string) (newBody string) {
|
|
|
+ if body == `` {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ newBody = body
|
|
|
+
|
|
|
+
|
|
|
+ doc, err := html2.Parse(strings.NewReader(body))
|
|
|
+ if err != nil {
|
|
|
+ fmt.Println("Error parsing HTML:", err)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ replaceIframeSrc(doc, opType, tokenMap)
|
|
|
+
|
|
|
+
|
|
|
+ var modifiedHtml strings.Builder
|
|
|
+ err = html2.Render(&modifiedHtml, doc)
|
|
|
+ if err != nil {
|
|
|
+ fmt.Println("Error rendering HTML:", err)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ newBody = modifiedHtml.String()
|
|
|
+ fmt.Println(newBody)
|
|
|
+
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+func replaceIframeSrc(n *html2.Node, opType string, tokenMap map[string]string) {
|
|
|
+ if n.Type == html2.ElementNode && n.Data == "iframe" {
|
|
|
+ for i, attr := range n.Attr {
|
|
|
+ if attr.Key == "src" {
|
|
|
+ newLink := attr.Val
|
|
|
+
|
|
|
+ switch opType {
|
|
|
+ case `add`:
|
|
|
+ newLink = linkAddToken(attr.Val, tokenMap)
|
|
|
+ case `del`:
|
|
|
+ newLink = linkDelToken(attr.Val)
|
|
|
+ }
|
|
|
+
|
|
|
+ n.Attr[i].Val = newLink
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ for c := n.FirstChild; c != nil; c = c.NextSibling {
|
|
|
+ replaceIframeSrc(c, opType, tokenMap)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+func linkAddToken(link string, tokenMap map[string]string) string {
|
|
|
+ var err error
|
|
|
+ defer func() {
|
|
|
+ if err != nil {
|
|
|
+ utils.FileLog.Info("处理链接失败,ERR:" + err.Error())
|
|
|
+ }
|
|
|
+ }()
|
|
|
+ parsedURL, err := url.Parse(link)
|
|
|
+ if err != nil {
|
|
|
+ return link
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ queryParams := parsedURL.Query()
|
|
|
+
|
|
|
+
|
|
|
+ queryParams.Del("authToken")
|
|
|
+
|
|
|
+
|
|
|
+ code := queryParams.Get("code")
|
|
|
+ if code == "" {
|
|
|
+ return link
|
|
|
+ }
|
|
|
+
|
|
|
+ showType := `chart`
|
|
|
+ if strings.Contains(parsedURL.Path, "sheetshow") {
|
|
|
+ showType = `excel`
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ var token string
|
|
|
+ key := fmt.Sprint(showType, `:`, code)
|
|
|
+ if tokenMap != nil {
|
|
|
+ token = tokenMap[key]
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ if token == `` {
|
|
|
+ token, err = GeneralChartToken(showType, code, 30*time.Minute)
|
|
|
+ if err != nil {
|
|
|
+ return link
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if tokenMap != nil {
|
|
|
+ tokenMap[key] = token
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ queryParams.Add("authToken", token)
|
|
|
+
|
|
|
+
|
|
|
+ parsedURL.RawQuery = queryParams.Encode()
|
|
|
+
|
|
|
+ return parsedURL.String()
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+func linkDelToken(link string) string {
|
|
|
+ var err error
|
|
|
+ defer func() {
|
|
|
+ if err != nil {
|
|
|
+ utils.FileLog.Info("处理链接失败,ERR:" + err.Error())
|
|
|
+ }
|
|
|
+ }()
|
|
|
+ parsedURL, err := url.Parse(link)
|
|
|
+ if err != nil {
|
|
|
+ return link
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ queryParams := parsedURL.Query()
|
|
|
+
|
|
|
+
|
|
|
+ queryParams.Del("authToken")
|
|
|
+
|
|
|
+
|
|
|
+ parsedURL.RawQuery = queryParams.Encode()
|
|
|
+
|
|
|
+ return parsedURL.String()
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+func GeneralChartToken(showType, uniqueCode string, expireTime time.Duration) (token string, err error) {
|
|
|
+
|
|
|
+ token = utils.MD5(fmt.Sprint(showType+`:`, uniqueCode, time.Now().UnixNano()/1e6))
|
|
|
+ key := fmt.Sprint(utils.CACHE_CHART_AUTH, token)
|
|
|
+ err = utils.Rc.Put(key, uniqueCode, expireTime)
|
|
|
+
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+func GeneralReportToken(linkToken string, reportId int) (token string, err error) {
|
|
|
+
|
|
|
+ token = utils.MD5(fmt.Sprint(linkToken, time.Now().UnixNano()/1e6))
|
|
|
+
|
|
|
+
|
|
|
+ reportKey := getReportShareTokenKey(linkToken)
|
|
|
+ err = utils.Rc.Put(reportKey, token, utils.BusinessConfReportChartExpiredTime)
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ err = generalReportAuthToken(token, ``, reportId)
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
return
|
|
|
}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+func generalReportAuthToken(token, source string, reportId int) (err error) {
|
|
|
+
|
|
|
+ reportTokenKey := getReportTokenKey(token, source)
|
|
|
+ err = utils.Rc.Put(reportTokenKey, reportId, utils.BusinessConfReportChartExpiredTime)
|
|
|
+
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+func getReportShareTokenKey(linkToken string) string {
|
|
|
+ return fmt.Sprint(utils.CACHE_REPORT_SHARE_AUTH, utils.MD5(linkToken))
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+func GetReportAuthToken(linkToken string) string {
|
|
|
+ key := getReportShareTokenKey(linkToken)
|
|
|
+ return utils.Rc.GetStr(key)
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+func getReportTokenKey(token, source string) string {
|
|
|
+ return fmt.Sprint(utils.CACHE_REPORT_AUTH, source, token)
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+func HandleReportContentStruct(body string, opType string, tokenMap map[string]string) (newBody string) {
|
|
|
+ if body == `` {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ newBody = body
|
|
|
+
|
|
|
+
|
|
|
+ var jsonData []map[string]interface{}
|
|
|
+ if err := json.Unmarshal([]byte(body), &jsonData); err != nil {
|
|
|
+ fmt.Println("Error parsing JSON:", err)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ for i := range jsonData {
|
|
|
+ if err := processMap(jsonData[i], opType, tokenMap); err != nil {
|
|
|
+ fmt.Println("Error processing component:", err)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ modifiedJSON, err := json.MarshalIndent(jsonData, "", " ")
|
|
|
+ if err != nil {
|
|
|
+ fmt.Println("Error marshaling JSON:", err)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ newBody = string(modifiedJSON)
|
|
|
+
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+func processMap(data map[string]interface{}, opType string, tokenMap map[string]string) error {
|
|
|
+ for key, value := range data {
|
|
|
+ switch v := value.(type) {
|
|
|
+ case string:
|
|
|
+ if key == "content" {
|
|
|
+ newContent := v
|
|
|
+
|
|
|
+ switch opType {
|
|
|
+ case `add`:
|
|
|
+ newContent = linkAddToken(v, tokenMap)
|
|
|
+ case `del`:
|
|
|
+ newContent = linkDelToken(v)
|
|
|
+ }
|
|
|
+ data[key] = newContent
|
|
|
+ }
|
|
|
+ case map[string]interface{}:
|
|
|
+ if err := processMap(v, opType, tokenMap); err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ case []interface{}:
|
|
|
+ for i := range v {
|
|
|
+ if m, ok := v[i].(map[string]interface{}); ok {
|
|
|
+ if err := processMap(m, opType, tokenMap); err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+func GetReportShareUrlToken(req models.ReportShartUrlReq, adminId int) (linkToken string, err error) {
|
|
|
+ defer func() {
|
|
|
+ if err == nil && linkToken != `` {
|
|
|
+ GeneralReportToken(linkToken, req.ReportId)
|
|
|
+ }
|
|
|
+ }()
|
|
|
+ cacheLinkKey := utils.CACHE_REPORT_SHARE_SHORT_Url + strconv.Itoa(req.ReportId) + "userId:" + strconv.Itoa(adminId)
|
|
|
+ linkToken, _ = utils.Rc.RedisString(cacheLinkKey)
|
|
|
+ if linkToken != "" && utils.Rc.IsExist(fmt.Sprint(utils.CACHE_REPORT_SHARE_ORIGIN_Url, utils.MD5(linkToken))) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ var tokenKey string
|
|
|
+
|
|
|
+ var ok bool
|
|
|
+
|
|
|
+ for i := 0; i < 3; i++ {
|
|
|
+ linkToken = req.Url
|
|
|
+ if i > 0 {
|
|
|
+ linkToken += "_" + utils.GetRandDigit(3)
|
|
|
+ }
|
|
|
+ hashUrl := utils.MurmurHash64([]byte(linkToken))
|
|
|
+ linkToken = utils.ConvertNumToBase62(hashUrl)
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ tokenKey = fmt.Sprint(utils.CACHE_REPORT_SHARE_ORIGIN_Url, utils.MD5(linkToken))
|
|
|
+ ok = utils.Rc.IsExist(tokenKey)
|
|
|
+ if !ok {
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if !ok {
|
|
|
+ after := time.Now().AddDate(0, 0, 7)
|
|
|
+ err = utils.Rc.Put(cacheLinkKey, linkToken, time.Until(after))
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ err = utils.Rc.Put(tokenKey, req.Url, time.Until(after))
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ linkToken = ""
|
|
|
+ err = errors.New("生成链接失败")
|
|
|
+ }
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+func TransfromToOriginUrl(linkToken string) (originLink string, msg string, err error) {
|
|
|
+ cacheLinkKey := fmt.Sprint(utils.CACHE_REPORT_SHARE_ORIGIN_Url, utils.MD5(linkToken))
|
|
|
+ originLink, err = utils.Rc.RedisString(cacheLinkKey)
|
|
|
+ if err != nil {
|
|
|
+ if err == redis.Nil {
|
|
|
+ msg = "链接已失效, 请重新获取"
|
|
|
+ return
|
|
|
+ }
|
|
|
+ msg = "获取链接失败"
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if originLink == "" {
|
|
|
+ msg = "链接已失效, 请重新获取"
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ reportToken := GetReportAuthToken(linkToken)
|
|
|
+ if reportToken != "" {
|
|
|
+ originLink += `&authToken=` + reportToken
|
|
|
+ }
|
|
|
+
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+func FilterShareUrl() web.FilterFunc {
|
|
|
+ return func(c *context.Context) {
|
|
|
+ path := c.Input.Context.Request.URL.Path
|
|
|
+ tokenArr := strings.Split(path, "/")
|
|
|
+ token := tokenArr[len(tokenArr)-1]
|
|
|
+
|
|
|
+ newPath := "/v1/report/share/link"
|
|
|
+ q := c.Input.Context.Request.URL.Query()
|
|
|
+ q.Add("Token", token)
|
|
|
+ c.Input.Context.Request.URL.Path = newPath
|
|
|
+ c.Input.Context.Request.URL.RawQuery = q.Encode()
|
|
|
+
|
|
|
+ utils.ApiLog.Info(fmt.Sprintf("原始请求为:%s, 已修改请求路径为:%s?%s", path, newPath, q.Encode()))
|
|
|
+ }
|
|
|
+}
|