|
|
package model
|
|
|
|
|
|
import (
|
|
|
"bytes"
|
|
|
"compress/gzip"
|
|
|
"errors"
|
|
|
"fmt"
|
|
|
"io"
|
|
|
"moredoc/util"
|
|
|
"moredoc/util/converter"
|
|
|
"moredoc/util/sitemap"
|
|
|
"os"
|
|
|
"path/filepath"
|
|
|
"strconv"
|
|
|
"strings"
|
|
|
"time"
|
|
|
|
|
|
"github.com/PuerkitoBio/goquery"
|
|
|
"go.uber.org/zap"
|
|
|
"gorm.io/gorm"
|
|
|
)
|
|
|
|
|
|
type reconvertDocument struct {
|
|
|
Id int64 `json:"id"`
|
|
|
}
|
|
|
|
|
|
var (
|
|
|
isCreatingSitemap bool
|
|
|
cacheReconvert = "cache/reconvert"
|
|
|
)
|
|
|
|
|
|
// UpdateSitemap 更新站点地图
|
|
|
func (m *DBModel) UpdateSitemap() (err error) {
|
|
|
if isCreatingSitemap {
|
|
|
return
|
|
|
}
|
|
|
isCreatingSitemap = true
|
|
|
defer func() {
|
|
|
isCreatingSitemap = false
|
|
|
}()
|
|
|
os.MkdirAll("sitemap", os.ModePerm)
|
|
|
|
|
|
var (
|
|
|
limit = 10000
|
|
|
page = 1
|
|
|
documents []Document
|
|
|
articles []Article
|
|
|
modelDocument = &Document{}
|
|
|
modelArticle = &Article{}
|
|
|
sitemapIndexes []sitemap.SitemapIndex
|
|
|
sm = sitemap.NewSitemap()
|
|
|
domain = strings.TrimRight(m.GetConfigOfSystem(ConfigSystemDomain).Domain, "/")
|
|
|
)
|
|
|
for {
|
|
|
if err = m.db.Model(modelDocument).Select("id", "updated_at").Limit(limit).Offset((page - 1) * limit).Order("id asc").Find(&documents).Error; err != nil && err != gorm.ErrRecordNotFound {
|
|
|
m.logger.Error("execUpdateSitemap", zap.Error(err))
|
|
|
return
|
|
|
}
|
|
|
if len(documents) == 0 {
|
|
|
break
|
|
|
}
|
|
|
file := fmt.Sprintf("sitemap/documents-%d.xml", page)
|
|
|
var su []sitemap.SitemapUrl
|
|
|
for _, doc := range documents {
|
|
|
su = append(su, sitemap.SitemapUrl{
|
|
|
Loc: fmt.Sprintf("%s/document/%d", domain, doc.Id),
|
|
|
Lastmod: doc.UpdatedAt.Format(time.RFC3339),
|
|
|
ChangeFreq: sitemap.DAILY,
|
|
|
Priority: 1.0,
|
|
|
})
|
|
|
}
|
|
|
if err = sm.CreateSitemapContent(su, file); err != nil {
|
|
|
m.logger.Error("execUpdateSitemap", zap.Error(err))
|
|
|
return
|
|
|
}
|
|
|
sitemapIndexes = append(sitemapIndexes, sitemap.SitemapIndex{
|
|
|
Loc: domain + "/" + file,
|
|
|
Lastmod: time.Now().Format(time.RFC3339),
|
|
|
})
|
|
|
page++
|
|
|
}
|
|
|
|
|
|
page = 1
|
|
|
for {
|
|
|
if err = m.db.Model(modelArticle).Select("id", "updated_at", "identifier").Limit(limit).Offset((page - 1) * limit).Order("id asc").Find(&articles).Error; err != nil && err != gorm.ErrRecordNotFound {
|
|
|
m.logger.Error("execUpdateSitemap", zap.Error(err))
|
|
|
return
|
|
|
}
|
|
|
if len(articles) == 0 {
|
|
|
break
|
|
|
}
|
|
|
file := fmt.Sprintf("sitemap/articles-%d.xml", page)
|
|
|
var su []sitemap.SitemapUrl
|
|
|
for _, article := range articles {
|
|
|
su = append(su, sitemap.SitemapUrl{
|
|
|
Loc: fmt.Sprintf("%s/article/%s", domain, article.Identifier),
|
|
|
Lastmod: article.UpdatedAt.Format(time.RFC3339),
|
|
|
ChangeFreq: sitemap.DAILY,
|
|
|
Priority: 1.0,
|
|
|
})
|
|
|
}
|
|
|
if err = sm.CreateSitemapContent(su, file); err != nil {
|
|
|
m.logger.Error("execUpdateSitemap", zap.Error(err))
|
|
|
return
|
|
|
}
|
|
|
sitemapIndexes = append(sitemapIndexes, sitemap.SitemapIndex{
|
|
|
Loc: domain + "/" + file,
|
|
|
Lastmod: time.Now().Format(time.RFC3339),
|
|
|
})
|
|
|
page++
|
|
|
}
|
|
|
|
|
|
if len(sitemapIndexes) > 0 {
|
|
|
if err = sm.CreateSitemapIndex(sitemapIndexes, "sitemap/sitemap.xml"); err != nil {
|
|
|
m.logger.Error("execUpdateSitemap", zap.Error(err))
|
|
|
return
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return
|
|
|
}
|
|
|
|
|
|
// SEO
|
|
|
func (m *DBModel) InitSEO() {
|
|
|
// 扫描dist目录下的所有HTML文件,将文件名作为SEO的关键字
|
|
|
cfg := m.GetConfigOfSystem()
|
|
|
dist := "dist"
|
|
|
pages := map[string]string{
|
|
|
"200.html": "",
|
|
|
"404.html": "404 - 页面未找到 - ",
|
|
|
"findpassword/index.html": "找回密码 - ",
|
|
|
"index.html": "",
|
|
|
"login/index.html": "用户登录 - ",
|
|
|
"register/index.html": "用户注册 - ",
|
|
|
"search/index.html": "文档搜索 - ",
|
|
|
"upload/index.html": "文档上传 - ",
|
|
|
}
|
|
|
filepath.Walk(dist, func(path string, info os.FileInfo, err error) error {
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
if info.IsDir() {
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
path = filepath.ToSlash(path)
|
|
|
if filepath.Ext(path) == ".html" {
|
|
|
name := strings.TrimPrefix(path, dist+"/")
|
|
|
defaultTitle, ok := pages[name]
|
|
|
if !ok && strings.HasPrefix(path, dist+"/admin") {
|
|
|
defaultTitle = "管理后台 - "
|
|
|
}
|
|
|
|
|
|
bs, _ := os.ReadFile(path)
|
|
|
if doc, errDoc := goquery.NewDocumentFromReader(bytes.NewReader(bs)); errDoc != nil {
|
|
|
m.logger.Error("initSEO", zap.Error(errDoc), zap.String("file", path))
|
|
|
} else {
|
|
|
m.logger.Debug("initSEO", zap.String("file", path), zap.String("title", defaultTitle+cfg.Sitename))
|
|
|
doc.Find("title").SetText(defaultTitle + cfg.Sitename)
|
|
|
doc.Find("meta[name='keywords']").SetAttr("content", cfg.Keywords)
|
|
|
doc.Find("meta[name='description']").SetAttr("content", cfg.Description)
|
|
|
doc.Find("meta[content='moredoc']").Remove()
|
|
|
doc.Find("meta[name='og:type']").Remove()
|
|
|
if htmlStr, errHtml := doc.Html(); errHtml == nil {
|
|
|
os.WriteFile(path, []byte(htmlStr), os.ModePerm)
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
return nil
|
|
|
})
|
|
|
}
|
|
|
|
|
|
func (m *DBModel) cronUpdateSitemap() {
|
|
|
layout := "2006-01-02"
|
|
|
lastUpdated := time.Now().Format(layout)
|
|
|
for {
|
|
|
hour, _ := strconv.Atoi(os.Getenv("MOREDOC_UPDATE_SITEMAP_HOUR")) // 默认为每天凌晨0点更新站点地图
|
|
|
hour = hour % 24
|
|
|
m.logger.Debug("cronUpdateSitemap", zap.Int("hour", hour), zap.String("lastUpdated", lastUpdated))
|
|
|
now := time.Now()
|
|
|
if now.Hour() == hour && now.Format(layout) != lastUpdated {
|
|
|
m.logger.Debug("cronUpdateSitemap,start...")
|
|
|
err := m.UpdateSitemap()
|
|
|
if err != nil {
|
|
|
m.logger.Debug("cronUpdateSitemap,end...", zap.Error(err))
|
|
|
}
|
|
|
m.logger.Debug("cronUpdateSitemap,end...")
|
|
|
lastUpdated = now.Format(layout)
|
|
|
}
|
|
|
time.Sleep(1 * time.Minute)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 清理无效附件
|
|
|
// 1. 找出已被标记删除的附件
|
|
|
// 2. 查询是否存在相同hash的未被标记删除的附件,对于此类附件,则只删除附件记录而不删除附件文件。
|
|
|
// 3. 删除已被标记删除的附件
|
|
|
// 4. 对于文档类附件,要注意衍生的附件,如缩略图、PDF等,也要一并删除。
|
|
|
func (m *DBModel) cronCleanInvalidAttachment() {
|
|
|
sleepDuration := 1 * time.Minute
|
|
|
for {
|
|
|
time.Sleep(1 * time.Second)
|
|
|
m.logger.Debug("cronCleanInvalidAttachment,start...")
|
|
|
var (
|
|
|
deletedAttachemnts, attachemnts []Attachment
|
|
|
hashes []string
|
|
|
hashMap = make(map[string]struct{})
|
|
|
ids []int64
|
|
|
retentionMinute = m.GetConfigOfSecurity(ConfigSecurityAttachmentRetentionMinute).AttachmentRetentionMinute
|
|
|
)
|
|
|
|
|
|
if retentionMinute < 0 {
|
|
|
retentionMinute = 0
|
|
|
}
|
|
|
|
|
|
// 1. 找出已被标记删除的附件
|
|
|
m.db.Unscoped().Where("deleted_at IS NOT NULL").Where("deleted_at < ?", time.Now().Add(-time.Duration(retentionMinute)*time.Minute)).Limit(100).Find(&deletedAttachemnts)
|
|
|
if len(deletedAttachemnts) == 0 {
|
|
|
m.logger.Debug("cronCleanInvalidAttachment,end...")
|
|
|
time.Sleep(sleepDuration)
|
|
|
continue
|
|
|
}
|
|
|
|
|
|
for _, attachemnt := range deletedAttachemnts {
|
|
|
hashes = append(hashes, attachemnt.Hash)
|
|
|
ids = append(ids, attachemnt.Id)
|
|
|
}
|
|
|
|
|
|
// 2. 查询是否存在相同hash的未被标记删除的附件
|
|
|
m.db.Select("hash").Where("hash IN (?)", hashes).Group("hash").Limit(len(hashes)).Find(&attachemnts)
|
|
|
for _, attachemnt := range attachemnts {
|
|
|
hashMap[attachemnt.Hash] = struct{}{}
|
|
|
}
|
|
|
|
|
|
// 3. 删除已被标记删除的附件
|
|
|
err := m.db.Unscoped().Where("id IN (?)", ids).Delete(&Attachment{}).Error
|
|
|
if err != nil {
|
|
|
m.logger.Error("cronCleanInvalidAttachment", zap.Error(err))
|
|
|
m.logger.Debug("cronCleanInvalidAttachment,end...")
|
|
|
continue
|
|
|
}
|
|
|
m.logger.Debug("cronCleanInvalidAttachment", zap.Any("ids", ids), zap.Any("Attachemnts", deletedAttachemnts))
|
|
|
for _, attachemnt := range deletedAttachemnts {
|
|
|
if _, ok := hashMap[attachemnt.Hash]; !ok { // 删除附件文件
|
|
|
m.logger.Debug("cronCleanInvalidAttachment", zap.String("path", attachemnt.Path), zap.Any("attachemnt", attachemnt))
|
|
|
file := strings.TrimLeft(attachemnt.Path, "./")
|
|
|
m.logger.Debug("cronCleanInvalidAttachment", zap.String("file", file))
|
|
|
if err := os.Remove(file); err != nil {
|
|
|
m.logger.Error("cronCleanInvalidAttachment", zap.Error(err), zap.String("file", file))
|
|
|
}
|
|
|
if attachemnt.Type == AttachmentTypeDocument { // 删除文档的衍生文件
|
|
|
folder := strings.TrimSuffix(file, filepath.Ext(file))
|
|
|
m.logger.Debug("cronCleanInvalidAttachment", zap.String("folder", folder))
|
|
|
if err := os.RemoveAll(folder); err != nil {
|
|
|
m.logger.Error("cronCleanInvalidAttachment", zap.Error(err), zap.String("folder", folder))
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
m.logger.Debug("cronCleanInvalidAttachment,end...")
|
|
|
}
|
|
|
}
|
|
|
|
|
|
func (m *DBModel) cronMarkAttachmentDeleted() {
|
|
|
// 定时标记删除24小时前上传的但是未被使用的附件
|
|
|
for {
|
|
|
time.Sleep(1 * time.Hour)
|
|
|
var (
|
|
|
configs []Config
|
|
|
banners []Banner
|
|
|
hashes []string
|
|
|
)
|
|
|
|
|
|
// 1. 查找图片类配置
|
|
|
m.db.Select("value").Where("input_type = ?", "image").Find(&configs)
|
|
|
if len(configs) > 0 {
|
|
|
for _, config := range configs {
|
|
|
// 文件hash
|
|
|
hash := strings.TrimSpace(strings.TrimSuffix(filepath.Base(config.Value), filepath.Ext(config.Value)))
|
|
|
if hash != "" {
|
|
|
hashes = append(hashes, hash)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
// 2. 查找横幅类配置
|
|
|
m.db.Select("path").Find(&banners)
|
|
|
if len(banners) > 0 {
|
|
|
for _, banner := range banners {
|
|
|
// 文件hash
|
|
|
hash := strings.TrimSpace(strings.TrimSuffix(filepath.Base(banner.Path), filepath.Ext(banner.Path)))
|
|
|
if hash != "" {
|
|
|
hashes = append(hashes, hash)
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if len(hashes) > 0 {
|
|
|
err := m.db.Where("`hash` NOT IN (?) and `type` in (?)", hashes, []int{AttachmentTypeConfig, AttachmentTypeBanner}).Delete(&Attachment{}).Error
|
|
|
if err != nil {
|
|
|
m.logger.Error("cronMarkAttachmentDeleted", zap.Error(err))
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 非配置类和横幅类附件,如果type_id为0,则表示未被使用,超过24小时则标记删除
|
|
|
m.logger.Debug("cronMarkAttachmentDeleted start...")
|
|
|
err := m.db.Where("`type` not in (?) and type_id = ?", []int{AttachmentTypeConfig, AttachmentTypeBanner}, 0).Where("created_at < ?", time.Now().Add(-time.Duration(24)*time.Hour)).Delete(&Attachment{}).Error
|
|
|
if err != nil {
|
|
|
m.logger.Error("cronMarkAttachmentDeleted", zap.Error(err))
|
|
|
}
|
|
|
m.logger.Debug("cronMarkAttachmentDeleted end...")
|
|
|
}
|
|
|
}
|
|
|
|
|
|
func (m *DBModel) loopCovertDocument() {
|
|
|
if convertDocumentRunning {
|
|
|
return
|
|
|
}
|
|
|
// 清空缓存目录
|
|
|
os.RemoveAll("cache/convert")
|
|
|
convertDocumentRunning = true
|
|
|
sleep := 10 * time.Second
|
|
|
m.db.Model(&Document{}).Where("status = ?", DocumentStatusConverting).Update("status", DocumentStatusPending)
|
|
|
for {
|
|
|
now := time.Now()
|
|
|
m.logger.Debug("loopCovertDocument,start...")
|
|
|
err := m.ConvertDocument()
|
|
|
if err != nil && err != gorm.ErrRecordNotFound {
|
|
|
m.logger.Error("loopCovertDocument", zap.Error(err))
|
|
|
}
|
|
|
m.logger.Debug("loopCovertDocument,end...", zap.String("cost", time.Since(now).String()))
|
|
|
if err == gorm.ErrRecordNotFound {
|
|
|
time.Sleep(sleep)
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
func (m *DBModel) ReconvertDocoument(documentId int64, ext string) {
|
|
|
ext = "." + strings.TrimLeft(ext, ".")
|
|
|
os.RemoveAll(cacheReconvert)
|
|
|
os.MkdirAll(cacheReconvert, os.ModePerm)
|
|
|
if documentId <= 0 {
|
|
|
m.reconvertAllDocument(ext)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
doc, err := m.GetDocument(documentId)
|
|
|
if err != nil {
|
|
|
m.logger.Error("ReconvertDocoument", zap.Error(err))
|
|
|
return
|
|
|
}
|
|
|
if doc.Status != DocumentStatusConverted {
|
|
|
m.logger.Error("ReconvertDocoument", zap.Error(errors.New("文档不是已转换的文档,不能重转")))
|
|
|
return
|
|
|
}
|
|
|
m.reconvertDocument(&doc, ext)
|
|
|
}
|
|
|
|
|
|
func (m *DBModel) reconvertDocument(doc *Document, ext string) {
|
|
|
m.logger.Debug("reconvertDocument", zap.Any("doc", doc), zap.String("ext", ext))
|
|
|
if doc.PreviewExt == ext {
|
|
|
m.logger.Info("reconvertDocument", zap.String("msg", "文档预览文件格式与指定格式一致,无需重转"), zap.String("document", doc.Title+doc.Ext))
|
|
|
return
|
|
|
}
|
|
|
|
|
|
// 1. 下载文档预览文件
|
|
|
attachment := m.GetAttachmentByTypeAndTypeId(AttachmentTypeDocument, doc.Id, "id", "hash")
|
|
|
if attachment.Id == 0 {
|
|
|
m.logger.Error("reconvertDocument", zap.String("msg", "文档预览文件不存在"), zap.String("document", doc.Title+doc.Ext))
|
|
|
return
|
|
|
}
|
|
|
cacheDir := filepath.Join(cacheReconvert, strconv.FormatInt(doc.Id, 10))
|
|
|
os.MkdirAll(cacheDir, os.ModePerm)
|
|
|
defer os.RemoveAll(cacheDir)
|
|
|
|
|
|
totalPreview := doc.Preview
|
|
|
if totalPreview == 0 {
|
|
|
totalPreview = doc.Pages
|
|
|
}
|
|
|
|
|
|
var (
|
|
|
convertedTargets []string
|
|
|
oldSrcFiles []string
|
|
|
)
|
|
|
|
|
|
for i := 1; i <= totalPreview; i++ {
|
|
|
// 已存在的预览文件
|
|
|
isGZIP := false
|
|
|
oldExt := doc.PreviewExt
|
|
|
if doc.EnableGZIP && strings.HasSuffix(oldExt, ".svg") {
|
|
|
oldExt = ".gzip.svg"
|
|
|
isGZIP = true
|
|
|
}
|
|
|
|
|
|
// 目标文件
|
|
|
dstFile := filepath.Join(cacheDir, fmt.Sprintf("%d%s", i, oldExt))
|
|
|
// 源文件
|
|
|
srcFile := fmt.Sprintf("documents/%s/%s/%d%s", strings.Join(strings.Split(attachment.Hash, "")[:5], "/"), attachment.Hash, i, oldExt)
|
|
|
oldSrcFiles = append(oldSrcFiles, srcFile)
|
|
|
err := util.CopyFile(srcFile, dstFile)
|
|
|
if err != nil {
|
|
|
m.logger.Error("reconvertDocument", zap.String("msg", "下载文档预览文件失败"), zap.String("document", doc.Title+doc.Ext), zap.Error(err))
|
|
|
return
|
|
|
}
|
|
|
m.logger.Debug("reconvertDocument", zap.Bool("isGZIP", isGZIP), zap.String("msg", "下载文档预览文件成功"), zap.String("document", doc.Title+doc.Ext), zap.String("srcFile", srcFile), zap.String("dstFile", dstFile))
|
|
|
if isGZIP { // 解压缩
|
|
|
m.ungzipSVG(dstFile)
|
|
|
}
|
|
|
|
|
|
// 2. 转换文档预览文件
|
|
|
convertedTargetFile := filepath.Join(cacheDir, fmt.Sprintf("%d%s", i, ext))
|
|
|
if strings.HasSuffix(oldExt, ".svg") {
|
|
|
// 如果是svg文件,则需要使用inkscape预先转为png
|
|
|
tmpFile := filepath.Join(cacheDir, fmt.Sprintf("tmp-%d.png", i))
|
|
|
err = converter.ConvertByInkscape(dstFile, tmpFile)
|
|
|
if err == nil {
|
|
|
if strings.HasSuffix(convertedTargetFile, ".png") {
|
|
|
// 如果目标文件是png,则直接使用inkscape转换后的文件
|
|
|
convertedTargetFile = tmpFile
|
|
|
} else {
|
|
|
// 如果目标文件不是png,则需要使用ImageMagick转换
|
|
|
err = converter.ConvertByImageMagick(tmpFile, convertedTargetFile)
|
|
|
os.RemoveAll(tmpFile)
|
|
|
}
|
|
|
}
|
|
|
} else {
|
|
|
err = converter.ConvertByImageMagick(dstFile, convertedTargetFile)
|
|
|
}
|
|
|
if err != nil {
|
|
|
m.logger.Error("reconvertDocument", zap.String("msg", "转换文档预览文件失败"), zap.String("document", doc.Title+doc.Ext), zap.Error(err))
|
|
|
return
|
|
|
}
|
|
|
convertedTargets = append(convertedTargets, convertedTargetFile)
|
|
|
}
|
|
|
|
|
|
// 3. 上传文档预览文件
|
|
|
for i, srcFile := range convertedTargets {
|
|
|
dstFile := fmt.Sprintf("documents/%s/%s/%d%s", strings.Join(strings.Split(attachment.Hash, "")[:5], "/"), attachment.Hash, i+1, ext)
|
|
|
err := util.CopyFile(srcFile, dstFile)
|
|
|
if err != nil {
|
|
|
m.logger.Error("reconvertDocument", zap.String("msg", "上传文档预览文件失败"), zap.String("document", doc.Title+doc.Ext), zap.Error(err))
|
|
|
return
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 4. 更新数据库表的预览后缀
|
|
|
// 查询同一hash的文档
|
|
|
var (
|
|
|
attachemnts []Attachment
|
|
|
err error
|
|
|
data = map[string]interface{}{
|
|
|
"preview_ext": ext,
|
|
|
"enable_gzip": false,
|
|
|
}
|
|
|
)
|
|
|
|
|
|
m.db.Select("id", "type_id").Where("hash = ? and `type` = ?", attachment.Hash, AttachmentTypeDocument).Find(&attachemnts)
|
|
|
if len(attachemnts) > 0 {
|
|
|
var ids []int64
|
|
|
for _, attachemnt := range attachemnts {
|
|
|
ids = append(ids, attachemnt.TypeId)
|
|
|
}
|
|
|
err = m.db.Model(&Document{}).Where("id IN (?)", ids).Updates(data).Error
|
|
|
} else {
|
|
|
err = m.db.Model(doc).Updates(data).Error
|
|
|
}
|
|
|
if err != nil {
|
|
|
m.logger.Error("reconvertDocument", zap.String("msg", "更新文档预览文件后缀失败"), zap.String("document", doc.Title+doc.Ext), zap.Error(err))
|
|
|
return
|
|
|
}
|
|
|
|
|
|
// 5. 删除缓存文件,删除原预览文件
|
|
|
for _, file := range oldSrcFiles {
|
|
|
os.Remove(file)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
func (m *DBModel) reconvertAllDocument(ext string) {
|
|
|
var cfg reconvertDocument
|
|
|
bytes, _ := os.ReadFile("cache/reconvert.json")
|
|
|
json.Unmarshal(bytes, &cfg)
|
|
|
for {
|
|
|
var doc Document
|
|
|
m.db.Where("id > ?", cfg.Id).Where("status = ?", DocumentStatusConverted).Order("id asc").Find(&doc)
|
|
|
if doc.Id == 0 {
|
|
|
break
|
|
|
}
|
|
|
m.reconvertDocument(&doc, ext)
|
|
|
cfg.Id = doc.Id
|
|
|
bytes, _ = json.Marshal(cfg)
|
|
|
os.WriteFile("cache/reconvert.json", bytes, os.ModePerm)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
func (m *DBModel) ungzipSVG(svg string) {
|
|
|
m.logger.Info("ungzipSVG", zap.String("svg", svg))
|
|
|
bs, err := os.ReadFile(svg)
|
|
|
if err != nil {
|
|
|
m.logger.Error("ungzipSVG", zap.Error(err))
|
|
|
return
|
|
|
}
|
|
|
gz, err := gzip.NewReader(bytes.NewReader(bs))
|
|
|
if err != nil {
|
|
|
m.logger.Error("ungzipSVG", zap.Error(err))
|
|
|
return
|
|
|
}
|
|
|
defer gz.Close()
|
|
|
fp, err := os.Create(svg)
|
|
|
if err != nil {
|
|
|
m.logger.Error("ungzipSVG", zap.Error(err))
|
|
|
return
|
|
|
}
|
|
|
defer fp.Close()
|
|
|
io.Copy(fp, gz)
|
|
|
}
|