200 lines
5.3 KiB
Go
200 lines
5.3 KiB
Go
package ncworker
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"net/url"
|
|
"path/filepath"
|
|
"strconv"
|
|
"time"
|
|
|
|
"rpjosh.de/ncDocConverter/internal/models"
|
|
"rpjosh.de/ncDocConverter/internal/nextcloud"
|
|
"rpjosh.de/ncDocConverter/pkg/logger"
|
|
"rpjosh.de/ncDocConverter/pkg/utils"
|
|
)
|
|
|
|
type convertJob struct {
|
|
job *models.NcConvertJob
|
|
ncUser *models.NextcloudUser
|
|
}
|
|
|
|
type ncFiles struct {
|
|
extension string
|
|
path string
|
|
lastModified time.Time
|
|
contentType string
|
|
size int
|
|
fileid int
|
|
}
|
|
|
|
func NewNcJob(job *models.NcConvertJob, ncUser *models.NextcloudUser) *convertJob {
|
|
convJob := &convertJob{
|
|
job: job,
|
|
ncUser: ncUser,
|
|
}
|
|
|
|
return convJob
|
|
}
|
|
|
|
func (job *convertJob) ExecuteJob() {
|
|
|
|
// Get existing directory contents
|
|
source, err := nextcloud.SearchInDirectory(
|
|
job.ncUser,
|
|
job.job.SourceDir,
|
|
[]string{
|
|
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
"application/msword",
|
|
},
|
|
)
|
|
if err != nil {
|
|
logger.Error("Failed to get files in source directory '%s': %s", job.job.SourceDir, err)
|
|
return
|
|
}
|
|
|
|
destination, err := nextcloud.SearchInDirectory(
|
|
job.ncUser,
|
|
job.job.DestinationDir,
|
|
[]string{
|
|
"application/pdf",
|
|
},
|
|
)
|
|
if err != nil {
|
|
logger.Error("Failed to get files in destination directory '%s': %s", job.job.DestinationDir, err)
|
|
return
|
|
}
|
|
|
|
preCount := len("/remote.php/dav/files/" + job.ncUser.Username + "/")
|
|
// Store the files in a map
|
|
sourceMap := make(map[string]ncFiles)
|
|
destinationMap := make(map[string]ncFiles)
|
|
|
|
for _, file := range source.Response {
|
|
href, _ := url.QueryUnescape(file.Href)
|
|
path := href[preCount:]
|
|
var extension = filepath.Ext(path)
|
|
var name = path[0 : len(path)-len(extension)][len(job.job.SourceDir):]
|
|
time := file.GetLastModified()
|
|
size, err := strconv.Atoi(file.Propstat.Prop.Size)
|
|
if err != nil {
|
|
logger.Error("%s", err)
|
|
}
|
|
sourceMap[name] = ncFiles{
|
|
extension: extension,
|
|
path: path,
|
|
lastModified: time,
|
|
size: size,
|
|
contentType: file.Propstat.Prop.Getcontenttype,
|
|
fileid: file.Propstat.Prop.Fileid,
|
|
}
|
|
}
|
|
|
|
for _, file := range destination.Response {
|
|
href, _ := url.QueryUnescape(file.Href)
|
|
path := href[preCount:]
|
|
var extension = filepath.Ext(path)
|
|
var name = path[0 : len(path)-len(extension)][len(job.job.DestinationDir):]
|
|
|
|
time, err := time.Parse("Mon, 02 Jan 2006 15:04:05 GMT", file.Propstat.Prop.Getlastmodified)
|
|
if err != nil {
|
|
logger.Error("%s", err)
|
|
}
|
|
size, err := strconv.Atoi(file.Propstat.Prop.Size)
|
|
if err != nil {
|
|
logger.Error("%s", err)
|
|
}
|
|
destinationMap[name] = ncFiles{
|
|
extension: extension,
|
|
path: path,
|
|
lastModified: time,
|
|
size: size,
|
|
contentType: file.Propstat.Prop.Getcontenttype,
|
|
fileid: file.Propstat.Prop.Fileid,
|
|
}
|
|
}
|
|
|
|
convertCount := 0
|
|
for index, source := range sourceMap {
|
|
// check if the file exists in the destination map
|
|
if dest, exists := destinationMap[index]; exists {
|
|
// compare timestamp and size
|
|
if dest.lastModified.Before(source.lastModified) {
|
|
job.convertFile(source.path, source.fileid, dest.path)
|
|
convertCount++
|
|
}
|
|
delete(destinationMap, index)
|
|
} else {
|
|
job.convertFile(
|
|
source.path, source.fileid, job.getDestinationDir(source.path),
|
|
)
|
|
convertCount++
|
|
delete(destinationMap, index)
|
|
}
|
|
}
|
|
|
|
// Delete the files which are not available anymore
|
|
for _, dest := range destinationMap {
|
|
err := nextcloud.DeleteFile(job.ncUser, dest.path)
|
|
if err != nil {
|
|
logger.Error(utils.FirstCharToUppercase(err.Error()))
|
|
}
|
|
}
|
|
|
|
logger.Info("Finished Nextcloud job \"%s\": %d documents converted", job.job.JobName, convertCount)
|
|
}
|
|
|
|
func (job *convertJob) getDestinationDir(sourceFile string) string {
|
|
sourceFile = sourceFile[len(job.job.SourceDir):]
|
|
var extension = filepath.Ext(sourceFile)
|
|
var name = sourceFile[0 : len(sourceFile)-len(extension)]
|
|
|
|
return job.job.DestinationDir + name + ".pdf"
|
|
}
|
|
|
|
// Converts the source file to the destination file utilizing the onlyoffice convert api
|
|
func (job *convertJob) convertFile(sourceFile string, sourceid int, destinationFile string) {
|
|
logger.Debug("Trying to convert %s (%d) to %s", sourceFile, sourceid, destinationFile)
|
|
|
|
nextcloud.CreateFoldersRecursively(job.ncUser, destinationFile)
|
|
|
|
client := http.Client{Timeout: 10 * time.Second}
|
|
req, err := http.NewRequest(http.MethodGet, job.ncUser.NextcloudBaseUrl+"/apps/onlyoffice/downloadas", nil)
|
|
if err != nil {
|
|
logger.Error("%s", err)
|
|
}
|
|
req.SetBasicAuth(job.ncUser.Username, job.ncUser.Password)
|
|
|
|
q := req.URL.Query()
|
|
q.Add("fileId", fmt.Sprint(sourceid))
|
|
q.Add("toExtension", "pdf")
|
|
req.URL.RawQuery = q.Encode()
|
|
|
|
res, err := client.Do(req)
|
|
if err != nil {
|
|
logger.Error("%s", err)
|
|
}
|
|
// Status Code 200
|
|
defer res.Body.Close()
|
|
|
|
uploadClient := http.Client{Timeout: 10 * time.Second}
|
|
uploadReq, err := http.NewRequest(http.MethodPut, job.ncUser.NextcloudBaseUrl+"/remote.php/dav/files/"+job.ncUser.Username+"/"+destinationFile, res.Body)
|
|
|
|
if err != nil {
|
|
logger.Error("%s", err)
|
|
}
|
|
uploadReq.SetBasicAuth(job.ncUser.Username, job.ncUser.Password)
|
|
uploadReq.Header.Set("Content-Type", "application/binary")
|
|
|
|
res, err = uploadClient.Do(uploadReq)
|
|
if err != nil {
|
|
logger.Error("%s", err)
|
|
}
|
|
|
|
if res.StatusCode != 204 && res.StatusCode != 201 {
|
|
logger.Error("Failed to create file %s (#%d)", destinationFile, res.StatusCode)
|
|
}
|
|
// Status Code 201
|
|
res.Body.Close()
|
|
}
|