2022-07-16 22:20:56 +01:00
|
|
|
package index
|
|
|
|
|
|
|
|
import (
|
2023-09-19 23:27:32 +01:00
|
|
|
"errors"
|
2022-07-17 13:37:50 +01:00
|
|
|
"golang.captainalm.com/cityuni-webserver/utils/io"
|
|
|
|
"gopkg.in/yaml.v3"
|
2022-07-16 22:20:56 +01:00
|
|
|
"html/template"
|
|
|
|
"net/url"
|
|
|
|
"os"
|
|
|
|
"path"
|
|
|
|
"strings"
|
|
|
|
"sync"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
2023-09-19 23:27:32 +01:00
|
|
|
const PageName = "index"
|
2022-07-16 22:20:56 +01:00
|
|
|
const templateName = "index.go.html"
|
|
|
|
|
2023-09-19 23:27:32 +01:00
|
|
|
func NewPage(dataStore string, cacheTemplates bool, templateStore string, pagePath string, ymlDataFallback bool) *Page {
|
2022-07-16 22:20:56 +01:00
|
|
|
var ptm *sync.Mutex
|
2022-07-28 01:56:00 +01:00
|
|
|
var sdm *sync.Mutex
|
2022-07-16 22:20:56 +01:00
|
|
|
if cacheTemplates {
|
|
|
|
ptm = &sync.Mutex{}
|
2022-07-28 01:56:00 +01:00
|
|
|
sdm = &sync.Mutex{}
|
2022-07-16 22:20:56 +01:00
|
|
|
}
|
|
|
|
pageToReturn := &Page{
|
2023-09-19 23:27:32 +01:00
|
|
|
YMLDataFallback: ymlDataFallback,
|
|
|
|
PagePath: pagePath,
|
|
|
|
DataPath: path.Join(dataStore, pagePath),
|
|
|
|
TemplatePath: path.Join(templateStore, templateName),
|
2022-07-28 01:56:00 +01:00
|
|
|
StoredDataMutex: sdm,
|
2022-07-16 22:20:56 +01:00
|
|
|
PageTemplateMutex: ptm,
|
|
|
|
}
|
|
|
|
return pageToReturn
|
|
|
|
}
|
|
|
|
|
|
|
|
type Page struct {
|
2023-09-19 23:27:32 +01:00
|
|
|
YMLDataFallback bool
|
|
|
|
PagePath string
|
|
|
|
DataPath string
|
|
|
|
TemplatePath string
|
2022-07-17 13:37:50 +01:00
|
|
|
StoredDataMutex *sync.Mutex
|
|
|
|
StoredData *DataYaml
|
|
|
|
LastModifiedData time.Time
|
|
|
|
PageTemplateMutex *sync.Mutex
|
|
|
|
PageTemplate *template.Template
|
|
|
|
LastModifiedTemplate time.Time
|
2022-07-16 22:20:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func (p *Page) GetPath() string {
|
2023-09-19 23:27:32 +01:00
|
|
|
return p.PagePath
|
2022-07-16 22:20:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func (p *Page) GetLastModified() time.Time {
|
2022-07-17 13:37:50 +01:00
|
|
|
if p.LastModifiedData.After(p.LastModifiedTemplate) {
|
|
|
|
return p.LastModifiedData
|
|
|
|
} else {
|
|
|
|
return p.LastModifiedTemplate
|
|
|
|
}
|
2022-07-16 22:20:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func (p *Page) GetCacheIDExtension(urlParameters url.Values) string {
|
2022-07-28 01:56:00 +01:00
|
|
|
toReturn := p.getNonThemedCleanQuery(urlParameters)
|
|
|
|
if toReturn != "" {
|
|
|
|
toReturn += "&"
|
|
|
|
}
|
|
|
|
if urlParameters.Has("light") {
|
|
|
|
toReturn += "light"
|
|
|
|
}
|
|
|
|
return strings.TrimRight(toReturn, "&")
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *Page) getNonThemedCleanQuery(urlParameters url.Values) string {
|
2022-07-16 22:20:56 +01:00
|
|
|
toReturn := ""
|
|
|
|
if urlParameters.Has("order") {
|
2022-07-17 13:37:50 +01:00
|
|
|
if theParameter := strings.ToLower(urlParameters.Get("order")); theParameter == "start" || theParameter == "end" || theParameter == "name" || theParameter == "duration" {
|
2022-07-16 22:20:56 +01:00
|
|
|
toReturn += "order=" + theParameter + "&"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if urlParameters.Has("sort") {
|
2022-07-17 13:37:50 +01:00
|
|
|
if theParameter := strings.ToLower(urlParameters.Get("sort")); theParameter == "asc" || theParameter == "ascending" || theParameter == "desc" || theParameter == "descending" {
|
2022-07-28 01:56:00 +01:00
|
|
|
toReturn += "sort=" + theParameter
|
2022-07-16 22:20:56 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return strings.TrimRight(toReturn, "&")
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *Page) GetContents(urlParameters url.Values) (contentType string, contents []byte, canCache bool) {
|
2022-07-17 13:37:50 +01:00
|
|
|
theTemplate, err := p.getPageTemplate()
|
|
|
|
if err != nil {
|
|
|
|
return "text/plain", []byte("Cannot Get Index.\r\n" + err.Error()), false
|
|
|
|
}
|
|
|
|
theData, err := p.getPageData()
|
|
|
|
if err != nil {
|
|
|
|
return "text/plain", []byte("Cannot Get Data.\r\n" + err.Error()), false
|
|
|
|
}
|
|
|
|
theMarshal := &Marshal{
|
2022-07-28 01:56:00 +01:00
|
|
|
Data: *theData,
|
|
|
|
Light: urlParameters.Has("light"),
|
|
|
|
Parameters: template.URL(p.getNonThemedCleanQuery(urlParameters)),
|
2022-07-17 13:37:50 +01:00
|
|
|
}
|
2022-07-17 14:02:40 +01:00
|
|
|
switch strings.ToLower(urlParameters.Get("order")) {
|
|
|
|
case "end":
|
|
|
|
theMarshal.OrderEndDate = getSortValue(strings.ToLower(urlParameters.Get("sort")))
|
|
|
|
case "name":
|
|
|
|
theMarshal.OrderName = getSortValue(strings.ToLower(urlParameters.Get("sort")))
|
|
|
|
case "duration":
|
|
|
|
theMarshal.OrderDuration = getSortValue(strings.ToLower(urlParameters.Get("sort")))
|
|
|
|
default:
|
|
|
|
theMarshal.OrderStartDate = getSortValue(strings.ToLower(urlParameters.Get("sort")))
|
|
|
|
}
|
2022-07-17 13:37:50 +01:00
|
|
|
theBuffer := &io.BufferedWriter{}
|
|
|
|
err = theTemplate.ExecuteTemplate(theBuffer, templateName, theMarshal)
|
|
|
|
if err != nil {
|
|
|
|
return "text/plain", []byte("Cannot Get Page.\r\n" + err.Error()), false
|
|
|
|
}
|
|
|
|
return "text/html", theBuffer.Data, true
|
2022-07-16 22:20:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func (p *Page) PurgeTemplate() {
|
|
|
|
if p.PageTemplateMutex != nil {
|
|
|
|
p.PageTemplateMutex.Lock()
|
|
|
|
p.PageTemplate = nil
|
|
|
|
p.PageTemplateMutex.Unlock()
|
|
|
|
}
|
2022-07-17 13:37:50 +01:00
|
|
|
if p.StoredDataMutex != nil {
|
|
|
|
p.StoredDataMutex.Lock()
|
|
|
|
p.StoredData = nil
|
|
|
|
p.StoredDataMutex.Unlock()
|
|
|
|
}
|
2022-07-16 22:20:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func (p *Page) getPageTemplate() (*template.Template, error) {
|
|
|
|
if p.PageTemplateMutex != nil {
|
|
|
|
p.PageTemplateMutex.Lock()
|
|
|
|
defer p.PageTemplateMutex.Unlock()
|
|
|
|
}
|
|
|
|
if p.PageTemplate == nil {
|
2023-09-19 23:27:32 +01:00
|
|
|
stat, err := os.Stat(p.TemplatePath)
|
2022-07-17 13:37:50 +01:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
p.LastModifiedTemplate = stat.ModTime()
|
2023-09-19 23:27:32 +01:00
|
|
|
loadedData, err := os.ReadFile(p.TemplatePath)
|
2022-07-16 22:20:56 +01:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
tmpl, err := template.New(templateName).Parse(string(loadedData))
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if p.PageTemplateMutex != nil {
|
|
|
|
p.PageTemplate = tmpl
|
|
|
|
}
|
|
|
|
return tmpl, nil
|
|
|
|
} else {
|
|
|
|
return p.PageTemplate, nil
|
|
|
|
}
|
|
|
|
}
|
2022-07-17 13:37:50 +01:00
|
|
|
|
|
|
|
func (p *Page) getPageData() (*DataYaml, error) {
|
|
|
|
if p.StoredDataMutex != nil {
|
|
|
|
p.StoredDataMutex.Lock()
|
|
|
|
defer p.StoredDataMutex.Unlock()
|
|
|
|
}
|
|
|
|
if p.StoredData == nil {
|
2023-09-19 23:27:32 +01:00
|
|
|
thePath := p.DataPath
|
2022-07-17 13:37:50 +01:00
|
|
|
stat, err := os.Stat(thePath)
|
|
|
|
if err != nil {
|
2023-09-19 23:27:32 +01:00
|
|
|
if p.YMLDataFallback && errors.Is(err, os.ErrNotExist) {
|
|
|
|
thePath += ".yml"
|
|
|
|
stat, err = os.Stat(thePath)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return nil, err
|
|
|
|
}
|
2022-07-17 13:37:50 +01:00
|
|
|
}
|
|
|
|
p.LastModifiedData = stat.ModTime()
|
|
|
|
fileHandle, err := os.Open(thePath)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
dataYaml := &DataYaml{}
|
|
|
|
decoder := yaml.NewDecoder(fileHandle)
|
|
|
|
err = decoder.Decode(dataYaml)
|
|
|
|
if err != nil {
|
|
|
|
_ = fileHandle.Close()
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
err = fileHandle.Close()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if p.StoredDataMutex != nil {
|
|
|
|
p.StoredData = dataYaml
|
|
|
|
}
|
|
|
|
return dataYaml, nil
|
2023-09-19 23:27:32 +01:00
|
|
|
|
2022-07-17 13:37:50 +01:00
|
|
|
} else {
|
|
|
|
return p.StoredData, nil
|
|
|
|
}
|
|
|
|
}
|
2022-07-17 14:02:40 +01:00
|
|
|
|
|
|
|
func getSortValue(toCheckIn string) int8 {
|
2022-12-28 20:36:13 +00:00
|
|
|
if toCheckIn == "asc" || toCheckIn == "ascending" {
|
2022-07-17 14:02:40 +01:00
|
|
|
return 1
|
2022-12-28 20:36:13 +00:00
|
|
|
} else {
|
|
|
|
return -1
|
2022-07-17 14:02:40 +01:00
|
|
|
}
|
|
|
|
}
|