miki

Miki: personal wiki with the fmd markup format
git clone https://wtenison.com/repo/miki.git
Log | Files | Refs | README | LICENSE

commit 921013e4a47a87afebb7a9af7e85a88d5fbfa056
parent c85271fa741bf9c683f013d4eb3f64da37bb5c11
Author: weetat <wtenison@protonmail.com>
Date:   Thu, 27 Feb 2025 22:17:16 +0000

Load fmd source into the editor textarea

Add ReadFileFMD and check the extension before reading .fmd or .json
files.

Diffstat:
Msrc/filesystem/directories.go | 13++++++-------
Msrc/filesystem/files.go | 29+++++++++++++++++++++++++----
Msrc/filesystem/filesystem.go | 8++++----
Msrc/fmd/fmd.go | 23+++++++++++++++--------
Msrc/network/routes.go | 54+++++++++++++++++++++++++++++++++++++++---------------
Mweb/edit/index.html | 10+++++++---
Aweb/edit/styles.css | 6++++++
Aweb/global/meta.tmpl.html | 5+++++
Mweb/home/index.html | 15++++-----------
Mweb/subject/index.html | 17+++++------------
10 files changed, 116 insertions(+), 64 deletions(-)

diff --git a/src/filesystem/directories.go b/src/filesystem/directories.go @@ -15,25 +15,25 @@ const ( ) type DirectoryPackage struct { - Root string // The root directory of the resource. - DependencyFiles []string // The set of valid resource files. + Root string // The root directory of the resource. + DependencyFiles []string // The set of valid resource files. // DependencyData interface{} // Any relevant resource data. } // func MakeDirectoryPkg(resSig DirectorySignature) (DirectoryPackage, error) { -func MakeDirectoryPkg(directory string, depth SearchDepth, filePattern string) (DirectoryPackage, error) { +func MakeDirectoryPkg(directoryPath string, depth SearchDepth, filePattern string) (DirectoryPackage, error) { - _dirPkg := DirectoryPackage{Root: filepath.Clean(directory)} + _dirPkg := DirectoryPackage{Root: filepath.Clean(directoryPath)} // Check for valid input parameters. if _dirPkg.Root == "" || depth < -1 { - _retErr := fmt.Errorf("MakeDirectoryDir:invalid directory signature (%s, %d)", _dirPkg.Root, depth) + _retErr := fmt.Errorf("MakeDirectoryPkg:invalid directory signature (%s, %d)", _dirPkg.Root, depth) return _dirPkg, _retErr } // Check if input directory exists. if _, _err := os.Stat(_dirPkg.Root); _err != nil { - _retErr := fmt.Errorf("MakeDirectoryDir:os.Stat:%s", _err) + _retErr := fmt.Errorf("MakeDirectoryPkg:os.Stat:%s", _err) return _dirPkg, _retErr } @@ -47,7 +47,6 @@ func MakeDirectoryPkg(directory string, depth SearchDepth, filePattern string) ( // A variable to store root sub-directory files. _subDirPkgDeps := []string{} - for _, _f := range _fileList { // Collete all valid sub-directory files. // Recurse into valid sub-directory files. diff --git a/src/filesystem/files.go b/src/filesystem/files.go @@ -4,17 +4,38 @@ import ( "encoding/json" "fmt" "os" + "path/filepath" ) -func ReadFileJSON(filePath string, outputDataContainer interface{}) error { +func ReadFileFMD(inputFilePath string) (string, error) { - _fsData, _err := os.ReadFile(filePath) + _fileName := filepath.Base(inputFilePath) + if filepath.Ext(_fileName) != ".fmd" { + return "", fmt.Errorf("ReadFileFMD:filepath.Ext:%s:invalid file extension", _fileName) + } + + _fsData, _err := os.ReadFile(inputFilePath) + if _err != nil { + return "", fmt.Errorf("ReadFileFMD:os.ReadFile:%s:%s", inputFilePath, _err.Error()) + } + + return string(_fsData), nil +} + +func ReadFileJSON(inputFilePath string, outputDataContainer any) error { + + _fileName := filepath.Base(inputFilePath) + if filepath.Ext(_fileName) != ".json" { + return fmt.Errorf("ReadFileJSON:filepath.Ext:%s:invalid file extension", _fileName) + } + + _fsData, _err := os.ReadFile(inputFilePath) if _err != nil { - return fmt.Errorf("ReadFileJSON:os.ReadFile:%s:%s", filePath, _err.Error()) + return fmt.Errorf("ReadFileJSON:os.ReadFile:%s:%s", inputFilePath, _err.Error()) } if _err = json.Unmarshal(_fsData, &outputDataContainer); _err != nil { - return fmt.Errorf("ReadFileJSON:json.Unmarshal:%s:%s", filePath, _err.Error()) + return fmt.Errorf("ReadFileJSON:json.Unmarshal:%s:%s", inputFilePath, _err.Error()) } return nil diff --git a/src/filesystem/filesystem.go b/src/filesystem/filesystem.go @@ -19,21 +19,21 @@ func Init() { } if _err := ReadFileJSON("sys/config.json", &_fsDataStruct); _err != nil { - log.Panicf("__PANIC\tfilesystem:Init:%s", _err) + log.Panicf("__PANIC:filesystem:Init:%s", _err) } Dirs["data"] = _fsDataStruct.DataDirectory Dirs["web"] = _fsDataStruct.WebDirectory - log.Printf("INFO\tfilesystem:Init:Dirs:%v", Dirs) + log.Printf("INFO:filesystem:Init:Dirs:%v", Dirs) //// GET GLOBAL WEB RESOURCES var _err error WebGlobalPkg, _err = MakeDirectoryPkg(filepath.Join(Dirs["web"], "/global"), SEARCH_DEPTH_ZERO, "*.html") if _err != nil { - log.Panicf("__PANIC\tfilesystem:Init:%s", _err) + log.Panicf("__PANIC:filesystem:Init:%s", _err) } - log.Printf("INFO\tfilesystem:Init:WebGlobals:%v", WebGlobalPkg) + log.Printf("INFO:filesystem:Init:WebGlobals:%v", WebGlobalPkg) } diff --git a/src/fmd/fmd.go b/src/fmd/fmd.go @@ -4,12 +4,19 @@ import ( "bytes" "log" "os" + "path/filepath" ) -func WriteFMDToHTMLFile(inputFile string, outputFile string) { - _fileBytes, _err := os.ReadFile(inputFile) +func WriteFMDToHTMLFile(inputFilePath string, outputFilePath string) { + _fileName := filepath.Base(inputFilePath) + if filepath.Ext(_fileName) != ".fmd" { + log.Printf("WriteFMDToHTMLFile:filepath.Ext:%s:invalid file extension", _fileName) + return + } + + _fileBytes, _err := os.ReadFile(inputFilePath) if _err != nil { - log.Println("_ERROR\tfmd:WriteFMDToHTMLFile:ReadFile:", inputFile, ":", _err) + log.Println("_ERROR\tfmd:WriteFMDToHTMLFile:ReadFile:", inputFilePath, ":", _err) } _l := MakeLexer(_fileBytes) @@ -22,15 +29,15 @@ func WriteFMDToHTMLFile(inputFile string, outputFile string) { _outputBytes := bytes.NewBufferString(interpret(_ast)) - if _err = os.WriteFile(outputFile, _outputBytes.Bytes(), 0666); _err != nil { - log.Println("_ERROR\tfmd:WriteFMDToHTMLFile:os.WriteFile:", inputFile, ":", _err) + if _err = os.WriteFile(outputFilePath, _outputBytes.Bytes(), 0666); _err != nil { + log.Println("_ERROR\tfmd:WriteFMDToHTMLFile:os.WriteFile:", inputFilePath, ":", _err) } } -func WritFMDToHTMLString(filePath string) string { - _fileBytes, _err := os.ReadFile(filePath) +func WritFMDToHTMLString(inputFilePath string) string { + _fileBytes, _err := os.ReadFile(inputFilePath) if _err != nil { - log.Println("_ERROR\tfmd:WriteFMDToHTMLString:ReadFile:", filePath, ":", _err) + log.Println("_ERROR\tfmd:WriteFMDToHTMLString:ReadFile:", inputFilePath, ":", _err) } _l := MakeLexer(_fileBytes) diff --git a/src/network/routes.go b/src/network/routes.go @@ -42,7 +42,7 @@ func handlePageHome(w http.ResponseWriter, r *http.Request) { // Collect HTML template files from directory. _rPkg, _err := mfs.MakeDirectoryPkg(filepath.Join(mfs.Dirs["web"], r.URL.String()), mfs.SEARCH_DEPTH_ZERO, "*.html") if _err != nil { - log.Printf("_ERROR\tnetwork:handlePage(\"/subject\"):%s", _err) + log.Printf("_ERROR:network:handlePage(\"/subject\"):%s", _err) http.NotFound(w, r) return } @@ -53,7 +53,7 @@ func handlePageHome(w http.ResponseWriter, r *http.Request) { // Create template from package. _tmpl, _err := template.ParseFiles(_rPkg.DependencyFiles...) if _err != nil { - log.Printf("_ERROR\tnetwork:handlePage(\"/home\"):%s", _err) + log.Printf("_ERROR:network:handlePage(\"/home\"):%s", _err) http.Error(w, "_ERROR:network:handlePage(\"/home\"):template.ParseFiles", http.StatusInternalServerError) return } @@ -65,7 +65,7 @@ func handlePageHome(w http.ResponseWriter, r *http.Request) { // Render template. if _err = _tmpl.ExecuteTemplate(w, "index.html", _templateDataContainer); _err != nil { - log.Printf("_ERROR\tnetwork:handlePageDefault(\"/\"):%s", _err) + log.Printf("_ERROR:network:handlePageDefault(\"/\"):%s", _err) http.Error(w, "_ERROR:network:handlePageDefault(\"/\"):template.ExecuteTemplate", http.StatusInternalServerError) return } @@ -78,7 +78,7 @@ func handlePageSubject(w http.ResponseWriter, r *http.Request) { // Collect HTML template files from directory. _rPkg, _err := mfs.MakeDirectoryPkg(filepath.Join(mfs.Dirs["web"], r.URL.Path), mfs.SEARCH_DEPTH_ZERO, "*.html") if _err != nil { - log.Printf("_ERROR\tnetwork:handlePage(\"/subject\"):%s", _err) + log.Printf("_ERROR:network:handlePage(\"/subject\"):%s", _err) http.NotFound(w, r) return } @@ -89,40 +89,40 @@ func handlePageSubject(w http.ResponseWriter, r *http.Request) { // Create template from package. _tmpl, _err := template.ParseFiles(_rPkg.DependencyFiles...) if _err != nil { - log.Printf("_ERROR\tnetwork:handlePage(\"/subject\"):%s", _err) + log.Printf("_ERROR:network:handlePage(\"/subject\"):%s", _err) http.Error(w, "_ERROR:network:handlePage(\"/subject\"):template.ParseFiles", http.StatusInternalServerError) return } + // Parse URL for query parameters. _urlContent, _err := url.Parse(r.URL.String()) if _err != nil { - log.Printf("_ERROR\tnetwork:handlePage(\"/subject\"):%s", _err) + log.Printf("_ERROR:network:handlePage(\"/subject\"):%s", _err) http.Error(w, "_ERROR:network:handlePage(\"/subject\"):url.Parse", http.StatusInternalServerError) } _urlQuerySubject, _err := url.ParseQuery(_urlContent.RawQuery) if _err != nil { - log.Printf("_ERROR\tnetwork:handlePage(\"/subject\"):%s", _err) + log.Printf("_ERROR:network:handlePage(\"/subject\"):%s", _err) http.Error(w, "_ERROR:network:handlePage(\"/subject\"):url.ParseQuery", http.StatusInternalServerError) } _fileName := _urlQuerySubject.Get("s") - _fileName = filepath.Base(_fileName) + // Assign rendered FMD file to buffer. var _templateDataContainer struct { FileName string FileText string } _templateDataContainer.FileName = _fileName _templateDataContainer.FileText = fmd.WritFMDToHTMLString(filepath.Join(mfs.Dirs["data"], "/fmd/"+_fileName+".fmd")) - if _templateDataContainer.FileText == "" { _templateDataContainer.FileText = "No File Found" } // Render template. if _err = _tmpl.ExecuteTemplate(w, "index.html", _templateDataContainer); _err != nil { - log.Printf("_ERROR\tnetwork:handlePageDefault(\"/\"):%s", _err) + log.Printf("_ERROR:network:handlePageDefault(\"/\"):%s", _err) http.Error(w, "_ERROR:network:handlePageDefault(\"/\"):template.ExecuteTemplate", http.StatusInternalServerError) return } @@ -133,9 +133,9 @@ func handlePageSubject(w http.ResponseWriter, r *http.Request) { func handlePageEdit(w http.ResponseWriter, r *http.Request) { // Collect HTML template files from directory. - _rPkg, _err := mfs.MakeDirectoryPkg(filepath.Join(mfs.Dirs["web"], r.URL.String()), mfs.SEARCH_DEPTH_ZERO, "*.html") + _rPkg, _err := mfs.MakeDirectoryPkg(filepath.Join(mfs.Dirs["web"], r.URL.Path), mfs.SEARCH_DEPTH_ZERO, "*.html") if _err != nil { - log.Printf("_ERROR\tnetwork:handlePageDefault(\"/\"):%s", _err) + log.Printf("_ERROR:network:handlePageDefault(\"/\"):%s", _err) http.NotFound(w, r) return } @@ -143,17 +143,41 @@ func handlePageEdit(w http.ResponseWriter, r *http.Request) { // Add 'global' file dependencies. _rPkg.DependencyFiles = append(_rPkg.DependencyFiles, mfs.WebGlobalPkg.DependencyFiles...) + // Get file name from URL + _urlContent, _err := url.Parse(r.URL.String()) + if _err != nil { + log.Printf("_ERROR:network:handlePage(\"/subject\"):%s", _err) + http.Error(w, "_ERROR:network:handlePage(\"/subject\"):url.Parse", http.StatusInternalServerError) + } + + // Parse URL for query parameters. + _urlQuerySubject, _err := url.ParseQuery(_urlContent.RawQuery) + if _err != nil { + log.Printf("_ERROR:network:handlePage(\"/subject\"):%s", _err) + http.Error(w, "_ERROR:network:handlePage(\"/subject\"):url.ParseQuery", http.StatusInternalServerError) + } + _fileName := _urlQuerySubject.Get("s") + + // Extract file content into bufffer. + var _templateDataContainer struct { + FileText string + } + _templateDataContainer.FileText, _err = mfs.ReadFileFMD(filepath.Join(mfs.Dirs["data"], "/fmd/"+_fileName+".fmd")) + if _err != nil { + _templateDataContainer.FileText = _err.Error() + } + // Create template from package. _tmpl, _err := template.ParseFiles(_rPkg.DependencyFiles...) if _err != nil { - log.Printf("_ERROR\tnetwork:handlePageDefault(\"/\"):%s", _err) + log.Printf("_ERROR:network:handlePageDefault(\"/\"):%s", _err) http.Error(w, "_ERROR:network:handlePageDefault(\"/\"):template.ParseFiles", http.StatusInternalServerError) return } // Render template. - if _err = _tmpl.ExecuteTemplate(w, "index.html", nil); _err != nil { - log.Printf("_ERROR\tnetwork:handlePageDefault(\"/\"):%s", _err) + if _err = _tmpl.ExecuteTemplate(w, "index.html", _templateDataContainer); _err != nil { + log.Printf("_ERROR:network:handlePageDefault(\"/\"):%s", _err) http.Error(w, "_ERROR:network:handlePageDefault(\"/\"):template.ExecuteTemplate", http.StatusInternalServerError) return } diff --git a/web/edit/index.html b/web/edit/index.html @@ -2,10 +2,12 @@ <html> <head> + <title>Miki/Edit</title> <meta name="viewport" charset="utf-8" content="width=device-width, initial-scale=1.0" /> - <link rel="stylesheet" type="text/css" href="/web/global/styles.css" /> - <script src="/web/global/script.js" defer></script> + {{template "meta"}} + <link rel="stylesheet" type="text/css" href="/web/edit/styles.css"> + </head> <body> @@ -17,7 +19,9 @@ <section id="left"></section> <section id="main" class="__container"> - <textarea name="editor" id="0">{{.fileTextFMD}}</textarea> + + <textarea name="editor" id="0">{{.FileText}}</textarea> + </section> <section id="right"></section> diff --git a/web/edit/styles.css b/web/edit/styles.css @@ -0,0 +1,5 @@ +@layer entity { + textarea { + height: 75vh; + } +} +\ No newline at end of file diff --git a/web/global/meta.tmpl.html b/web/global/meta.tmpl.html @@ -0,0 +1,4 @@ +{{define "meta"}} +<link rel="stylesheet" type="text/css" href="/web/global/styles.css" /> +<script src="/web/global/script.js" defer></script> +{{end}} +\ No newline at end of file diff --git a/web/home/index.html b/web/home/index.html @@ -2,10 +2,11 @@ <html> <head> + <title>Miki/Home</title> <meta name="viewport" charset="utf-8" content="width=device-width, initial-scale=1.0" /> - <link rel="stylesheet" type="text/css" href="/web/global/styles.css" /> - <script src="/web/global/script.js" defer></script> + {{template "meta"}} + </head> <body> @@ -18,15 +19,7 @@ <section id="subject_"> - <!-- <section id="_card" class="__container_bg-1"> - - </section> --> - - <section id="_body"> - - {{.FileText}} - - </section> + {{.FileText}} </section> diff --git a/web/subject/index.html b/web/subject/index.html @@ -2,10 +2,11 @@ <html> <head> - <title>Miki/{{.FileName}}</title> + + <title>Miki/Edit/{{.FileName}}</title> <meta name="viewport" charset="utf-8" content="width=device-width, initial-scale=1.0" /> - <link rel="stylesheet" type="text/css" href="/web/global/styles.css" /> - <script src="/web/global/script.js" defer></script> + {{template "meta"}} + </head> <body> @@ -18,15 +19,7 @@ <section id="subject_"> - <!-- <section id="_card" class="__container_bg-1"> - - </section> --> - - <section id="_body"> - - {{.FileText}} - - </section> + {{.FileText}} </section>