1
0
Fork 0
mirror of https://github.com/Eggbertx/gochan.git synced 2025-08-02 15:06:23 -07:00

Finish browser-based template editor, resolves issue #90

This commit is contained in:
Eggbertx 2023-12-26 17:02:09 -08:00
parent 6fbfb731bd
commit e968dc875a
9 changed files with 134 additions and 20 deletions

View file

@ -38,7 +38,7 @@ release_files = (
"README.md",
)
GOCHAN_VERSION = "3.8.0"
GOCHAN_VERSION = "3.9.0"
DATABASE_VERSION = "2" # stored in DBNAME.DBPREFIXdatabase_version
PATH_NOTHING = -1

View file

@ -7,7 +7,7 @@ local url = require("url")
local check_key_url = "https://rest.akismet.com/1.1/verify-key"
local base_headers = {}
base_headers["User-Agent"] = "gochan/3.8 | Akismet/0.1"
base_headers["User-Agent"] = "gochan/3.9 | Akismet/0.1"
base_headers["Content-Type"] = "application/x-www-form-urlencoded"
local key = "" -- read from akismet_key.txt

View file

@ -1,6 +1,6 @@
{
"name": "gochan.js",
"version": "3.8.0",
"version": "3.9.0",
"description": "",
"main": "./ts/main.ts",
"private": true,

View file

@ -7,6 +7,6 @@
<h1>404: File not found</h1>
<img src="/error/lol 404.gif" border="0" alt="">
<p>The requested file could not be found on this server.</p>
<hr/>Site powered by <a href="https://github.com/gochan-org/gochan" target="_blank">Gochan</a> v3.8.0
<hr/>Site powered by <a href="https://github.com/gochan-org/gochan" target="_blank">Gochan</a> v3.9.0
</body>
</html>

View file

@ -7,6 +7,6 @@
<h1>Error 500: Internal Server error</h1>
<img src="/error/server500.gif" border="0" alt="">
<p>The server encountered an error while trying to serve the page, and we apologize for the inconvenience. The <a href="https://en.wikipedia.org/wiki/Idiot">system administrator</a> will try to fix things as soon they get around to it, whenever that is. Hopefully soon.</p>
<hr/>Site powered by <a href="https://github.com/gochan-org/gochan" target="_blank">Gochan</a> v3.8.0
<hr/>Site powered by <a href="https://github.com/gochan-org/gochan" target="_blank">Gochan</a> v3.9.0
</body>
</html>

View file

@ -7,6 +7,6 @@
<h1>Error 502: Bad gateway</h1>
<img src="/error/server500.gif" border="0" alt="">
<p>The server encountered an error while trying to serve the page, and we apologize for the inconvenience. The <a href="https://en.wikipedia.org/wiki/Idiot">system administrator</a> will try to fix things as soon they get around to it, whenever that is. Hopefully soon.</p>
<hr/>Site powered by <a href="https://github.com/gochan-org/gochan" target="_blank">Gochan</a> v3.8.0
<hr/>Site powered by <a href="https://github.com/gochan-org/gochan" target="_blank">Gochan</a> v3.9.0
</body>
</html>

View file

@ -18,6 +18,7 @@ const (
Catalog = "catalog.html"
JsConsts = "consts.js"
ErrorPage = "error.html"
FrontIntro = "front_intro.html"
FrontPage = "front.html"
ManageAnnouncements = "manage_announcements.html"
ManageAppeals = "manage_appeals.html"
@ -66,6 +67,9 @@ var (
ErrorPage: {
files: []string{"error.html"},
},
FrontIntro: {
files: []string{"front_intro.html"},
},
FrontPage: {
files: []string{"front.html", "topbar.html", "front_intro.html", "page_header.html", "page_footer.html"},
},

View file

@ -10,6 +10,7 @@ import (
"os"
"path"
"strconv"
"time"
"github.com/gochan-org/gochan/pkg/building"
"github.com/gochan-org/gochan/pkg/config"
@ -425,29 +426,125 @@ func registerAdminPages() {
Callback: func(writer http.ResponseWriter, request *http.Request, staff *gcsql.Staff, wantsJSON bool, infoEv, errEv *zerolog.Event) (output interface{}, err error) {
buf := bytes.NewBufferString("")
selectedTemplate := request.PostFormValue("templateselect")
selectedTemplate := request.FormValue("override")
templatesDir := config.GetSystemCriticalConfig().TemplateDir
var overriding string
var templateStr string
var templatePath string
var successStr string
if selectedTemplate != "" {
errEv.Str("selectedTemplate", selectedTemplate)
gcutil.LogStr("selectedTemplate", selectedTemplate, infoEv, errEv)
templatePath, err := gctemplates.GetTemplatePath(selectedTemplate)
if err != nil {
if templatePath, err = gctemplates.GetTemplatePath(selectedTemplate); err != nil {
errEv.Err(err).Caller().Msg("unable to load selected template")
return "", fmt.Errorf("template %q does not exist", selectedTemplate)
}
errEv.Str("templatePath", templatePath)
ba, err := os.ReadFile(templatePath)
if err != nil {
errEv.Err(err).Caller().Send()
return "", fmt.Errorf("unable to load selected template %q", selectedTemplate)
}
templateStr = string(ba)
} else if overriding = request.PostFormValue("overriding"); overriding != "" {
if templateStr = request.PostFormValue("templatetext"); templateStr == "" {
writer.WriteHeader(http.StatusBadRequest)
errEv.Caller().Int("status", http.StatusBadRequest).
Msg("received an empty template string")
return "", errors.New("received an empty template string")
}
if _, err = gctemplates.ParseTemplate(selectedTemplate, templateStr); err != nil {
// unable to parse submitted template
errEv.Err(err).Caller().Int("status", http.StatusBadRequest).Send()
writer.WriteHeader(http.StatusBadRequest)
return "", err
}
overrideDir := path.Join(templatesDir, "override")
overridePath := path.Join(overrideDir, overriding)
gcutil.LogStr("overridePath", overridePath, infoEv, errEv)
if _, err = os.Stat(overrideDir); os.IsNotExist(err) {
// override dir doesn't exist, create it
if err = os.Mkdir(overrideDir, config.GC_DIR_MODE); err != nil {
errEv.Err(err).Caller().
Int("status", http.StatusInternalServerError).
Msg("Unable to create override directory")
writer.WriteHeader(http.StatusInternalServerError)
return "", err
}
} else if err != nil {
// got an error checking for override dir
errEv.Err(err).Caller().
Int("status", http.StatusInternalServerError).
Msg("Unable to check if override directory exists")
writer.WriteHeader(http.StatusInternalServerError)
return "", err
}
serverutil.MinifyTemplate(gctemplates.ManageTemplates, map[string]any{
// get the original template file, or the latest override if there are any
templatePath, err := gctemplates.GetTemplatePath(overriding)
if err != nil {
errEv.Err(err).Caller().
Int("status", http.StatusInternalServerError).
Msg("Unable to get original template path")
writer.WriteHeader(http.StatusInternalServerError)
return "", err
}
// read original template path into []byte to be backed up
ba, err := os.ReadFile(templatePath)
if err != nil {
errEv.Err(err).Caller().
Int("status", http.StatusInternalServerError).
Msg("Unable to read original template file")
writer.WriteHeader(http.StatusInternalServerError)
return "", err
}
// back up template to override/<overriding>-<timestamp>.bkp
backupPath := path.Join(overrideDir, overriding) + time.Now().Format("-2006-01-02_15-04-05.bkp")
gcutil.LogStr("backupPath", backupPath, infoEv, errEv)
if err = os.WriteFile(backupPath, ba, config.GC_FILE_MODE); err != nil {
errEv.Err(err).Caller().
Int("status", http.StatusInternalServerError).
Msg("Unable to back up template file")
writer.WriteHeader(http.StatusInternalServerError)
return "", errors.New("unable to back up original template file")
}
// write changes to disk
if err = os.WriteFile(overridePath, []byte(templateStr), config.GC_FILE_MODE); err != nil {
errEv.Err(err).Caller().
Int("status", http.StatusInternalServerError).
Msg("Unable to save changes")
writer.WriteHeader(http.StatusInternalServerError)
return "", err
}
// reload template
if err = gctemplates.InitTemplates(overriding); err != nil {
errEv.Err(err).Caller().
Int("status", http.StatusInternalServerError).
Msg("Unable to reinitialize template")
writer.WriteHeader(http.StatusInternalServerError)
return "", err
}
successStr = fmt.Sprintf("%q saved successfully.\n Original backed up to %s",
overriding, backupPath)
infoEv.Msg("Template successfully saved and reloaded")
}
data := map[string]any{
"templates": gctemplates.GetTemplateList(),
"templatesDir": templatesDir,
"templatePath": templatePath,
"selectedTemplate": selectedTemplate,
"templateText": templateStr,
}, buf, "text/html")
"success": successStr,
}
if templateStr != "" && successStr == "" {
data["templateText"] = templateStr
}
serverutil.MinifyTemplate(gctemplates.ManageTemplates, data, buf, "text/html")
return buf.String(), nil
}},
Action{

View file

@ -1,17 +1,30 @@
<div style="text-align: center;">
<form action="{{webPath "manage/templates"}}" method="POST" id="template-override">
<form action="{{webPath "manage/templates"}}" method="{{with $.templateText}}POST{{else}}GET{{end}}" id="template-override">
{{with $.templateText}}
<b>Editing: {{$.selectedTemplate}}</b>
<input type="hidden" name="overriding" value="{{$.selectedTemplate}}">
<textarea name="templatetext" class="template-text" rows="16" spellcheck="false">{{$.templateText}}</textarea>
<input type="submit" name="dooverride" value="Submit" onsubmit="return prompt('Are you sure you want to override the template?')">
<input type="submit" name="cancel" value="Cancel"/>
<input type="submit" name="dooverride" value="Submit" onclick="return confirm('Are you sure you want to override the template?')"/>
<input type="submit" name="cancel" value="Cancel"/ onclick="window.history.back()"/>
</form>
</div>
<p>
When you submit your changes to a template, the latest change (or the original if there are no changes yet)
will be backed up to the "overrides" subdirectory of your configured templates directory, {{$.templatesDir}},
with a timestamp appended to the filename.
</p>
{{else}}
Select a template: <select name="templateselect">
{{- with .success}}
<div style="display:inline-block; outline: 4px solid green">
{{$.success}}<br/>
You may need to rebuild the respective page(s), or rebuild everything <a href='{{webPath "/manage/rebuildall"}}'>here</a>.
</div><br/><br/>{{- end -}}
Select a template: <select name="override">
{{range $t, $template := .templates}}
<option value="{{$template}}">{{$template}}</option>
{{end}}
</select>
<input type="submit" name="dotemplatechoose" value="Select template" />
{{end}}
<input type="submit" value="Select template" />
</form>
</div>
{{end}}