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:
parent
6fbfb731bd
commit
e968dc875a
9 changed files with 134 additions and 20 deletions
2
build.py
2
build.py
|
@ -38,7 +38,7 @@ release_files = (
|
||||||
"README.md",
|
"README.md",
|
||||||
)
|
)
|
||||||
|
|
||||||
GOCHAN_VERSION = "3.8.0"
|
GOCHAN_VERSION = "3.9.0"
|
||||||
DATABASE_VERSION = "2" # stored in DBNAME.DBPREFIXdatabase_version
|
DATABASE_VERSION = "2" # stored in DBNAME.DBPREFIXdatabase_version
|
||||||
|
|
||||||
PATH_NOTHING = -1
|
PATH_NOTHING = -1
|
||||||
|
|
|
@ -7,7 +7,7 @@ local url = require("url")
|
||||||
local check_key_url = "https://rest.akismet.com/1.1/verify-key"
|
local check_key_url = "https://rest.akismet.com/1.1/verify-key"
|
||||||
|
|
||||||
local base_headers = {}
|
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"
|
base_headers["Content-Type"] = "application/x-www-form-urlencoded"
|
||||||
|
|
||||||
local key = "" -- read from akismet_key.txt
|
local key = "" -- read from akismet_key.txt
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "gochan.js",
|
"name": "gochan.js",
|
||||||
"version": "3.8.0",
|
"version": "3.9.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "./ts/main.ts",
|
"main": "./ts/main.ts",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
|
|
@ -7,6 +7,6 @@
|
||||||
<h1>404: File not found</h1>
|
<h1>404: File not found</h1>
|
||||||
<img src="/error/lol 404.gif" border="0" alt="">
|
<img src="/error/lol 404.gif" border="0" alt="">
|
||||||
<p>The requested file could not be found on this server.</p>
|
<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>
|
</body>
|
||||||
</html>
|
</html>
|
|
@ -7,6 +7,6 @@
|
||||||
<h1>Error 500: Internal Server error</h1>
|
<h1>Error 500: Internal Server error</h1>
|
||||||
<img src="/error/server500.gif" border="0" alt="">
|
<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>
|
<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>
|
</body>
|
||||||
</html>
|
</html>
|
|
@ -7,6 +7,6 @@
|
||||||
<h1>Error 502: Bad gateway</h1>
|
<h1>Error 502: Bad gateway</h1>
|
||||||
<img src="/error/server500.gif" border="0" alt="">
|
<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>
|
<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>
|
</body>
|
||||||
</html>
|
</html>
|
|
@ -18,6 +18,7 @@ const (
|
||||||
Catalog = "catalog.html"
|
Catalog = "catalog.html"
|
||||||
JsConsts = "consts.js"
|
JsConsts = "consts.js"
|
||||||
ErrorPage = "error.html"
|
ErrorPage = "error.html"
|
||||||
|
FrontIntro = "front_intro.html"
|
||||||
FrontPage = "front.html"
|
FrontPage = "front.html"
|
||||||
ManageAnnouncements = "manage_announcements.html"
|
ManageAnnouncements = "manage_announcements.html"
|
||||||
ManageAppeals = "manage_appeals.html"
|
ManageAppeals = "manage_appeals.html"
|
||||||
|
@ -66,6 +67,9 @@ var (
|
||||||
ErrorPage: {
|
ErrorPage: {
|
||||||
files: []string{"error.html"},
|
files: []string{"error.html"},
|
||||||
},
|
},
|
||||||
|
FrontIntro: {
|
||||||
|
files: []string{"front_intro.html"},
|
||||||
|
},
|
||||||
FrontPage: {
|
FrontPage: {
|
||||||
files: []string{"front.html", "topbar.html", "front_intro.html", "page_header.html", "page_footer.html"},
|
files: []string{"front.html", "topbar.html", "front_intro.html", "page_header.html", "page_footer.html"},
|
||||||
},
|
},
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/gochan-org/gochan/pkg/building"
|
"github.com/gochan-org/gochan/pkg/building"
|
||||||
"github.com/gochan-org/gochan/pkg/config"
|
"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) {
|
Callback: func(writer http.ResponseWriter, request *http.Request, staff *gcsql.Staff, wantsJSON bool, infoEv, errEv *zerolog.Event) (output interface{}, err error) {
|
||||||
buf := bytes.NewBufferString("")
|
buf := bytes.NewBufferString("")
|
||||||
|
|
||||||
selectedTemplate := request.PostFormValue("templateselect")
|
selectedTemplate := request.FormValue("override")
|
||||||
|
templatesDir := config.GetSystemCriticalConfig().TemplateDir
|
||||||
|
var overriding string
|
||||||
var templateStr string
|
var templateStr string
|
||||||
|
var templatePath string
|
||||||
|
var successStr string
|
||||||
if selectedTemplate != "" {
|
if selectedTemplate != "" {
|
||||||
errEv.Str("selectedTemplate", selectedTemplate)
|
gcutil.LogStr("selectedTemplate", selectedTemplate, infoEv, errEv)
|
||||||
|
|
||||||
templatePath, err := gctemplates.GetTemplatePath(selectedTemplate)
|
if templatePath, err = gctemplates.GetTemplatePath(selectedTemplate); err != nil {
|
||||||
if err != nil {
|
|
||||||
errEv.Err(err).Caller().Msg("unable to load selected template")
|
errEv.Err(err).Caller().Msg("unable to load selected template")
|
||||||
return "", fmt.Errorf("template %q does not exist", selectedTemplate)
|
return "", fmt.Errorf("template %q does not exist", selectedTemplate)
|
||||||
}
|
}
|
||||||
|
errEv.Str("templatePath", templatePath)
|
||||||
ba, err := os.ReadFile(templatePath)
|
ba, err := os.ReadFile(templatePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errEv.Err(err).Caller().Send()
|
errEv.Err(err).Caller().Send()
|
||||||
return "", fmt.Errorf("unable to load selected template %q", selectedTemplate)
|
return "", fmt.Errorf("unable to load selected template %q", selectedTemplate)
|
||||||
}
|
}
|
||||||
templateStr = string(ba)
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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")
|
||||||
}
|
}
|
||||||
|
|
||||||
serverutil.MinifyTemplate(gctemplates.ManageTemplates, map[string]any{
|
data := map[string]any{
|
||||||
"templates": gctemplates.GetTemplateList(),
|
"templates": gctemplates.GetTemplateList(),
|
||||||
|
"templatesDir": templatesDir,
|
||||||
|
"templatePath": templatePath,
|
||||||
"selectedTemplate": selectedTemplate,
|
"selectedTemplate": selectedTemplate,
|
||||||
"templateText": templateStr,
|
"success": successStr,
|
||||||
}, buf, "text/html")
|
}
|
||||||
|
if templateStr != "" && successStr == "" {
|
||||||
|
data["templateText"] = templateStr
|
||||||
|
}
|
||||||
|
serverutil.MinifyTemplate(gctemplates.ManageTemplates, data, buf, "text/html")
|
||||||
return buf.String(), nil
|
return buf.String(), nil
|
||||||
}},
|
}},
|
||||||
Action{
|
Action{
|
||||||
|
|
|
@ -1,17 +1,30 @@
|
||||||
<div style="text-align: center;">
|
<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}}
|
{{with $.templateText}}
|
||||||
<b>Editing: {{$.selectedTemplate}}</b>
|
<b>Editing: {{$.selectedTemplate}}</b>
|
||||||
|
<input type="hidden" name="overriding" value="{{$.selectedTemplate}}">
|
||||||
<textarea name="templatetext" class="template-text" rows="16" spellcheck="false">{{$.templateText}}</textarea>
|
<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="dooverride" value="Submit" onclick="return confirm('Are you sure you want to override the template?')"/>
|
||||||
<input type="submit" name="cancel" value="Cancel"/>
|
<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}}
|
{{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}}
|
{{range $t, $template := .templates}}
|
||||||
<option value="{{$template}}">{{$template}}</option>
|
<option value="{{$template}}">{{$template}}</option>
|
||||||
{{end}}
|
{{end}}
|
||||||
</select>
|
</select>
|
||||||
<input type="submit" name="dotemplatechoose" value="Select template" />
|
<input type="submit" value="Select template" />
|
||||||
{{end}}
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
{{end}}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue