ncDocConverter/internal/ncworker/office.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()
}