From 7a1ebaee7aae9d774d7e3cab2207ab9c2e7aa8f3 Mon Sep 17 00:00:00 2001 From: sad Date: Thu, 15 Feb 2024 16:28:01 -0700 Subject: [PATCH] implement config file and local directory --- README.md | 80 ++++++++++++++++++++++----------------------- assets/_layout.html | 4 ++- config.toml | 12 +++++++ dev.sh | 22 ------------- go.mod | 1 + go.sum | 2 ++ src/main.go | 78 ++++++++++++++++++++++++++++++------------- src/render.go | 58 ++++++++++++++++++++++---------- 8 files changed, 153 insertions(+), 104 deletions(-) create mode 100644 config.toml delete mode 100644 dev.sh diff --git a/README.md b/README.md index 9d9b4ff..c4b0542 100644 --- a/README.md +++ b/README.md @@ -1,70 +1,71 @@ -H0wdy!!! +# TCP-WIKI -feel free to commit, leave suggestions/ideas, issues, or really anything <3 +Feel free to commit, leave suggestions/ideas, issues, or really anything <3 -# What is TCP.WIKI ? +# What is TCP-WIKI ? +
example screenshot
-https://tcp.ac/i/IFAZE +TCP.WIKI is a secure and verifiable wiki platform designed for projects, code, courses, documents, articles, blogs, tutorials, and more. +### Project Goals -## Project Goals -secure and verifiable wiki for projects, code, courses, documents, articles, tutorials, and more +The aim is to provide a secure, minimal, and easily verifiable wiki environment that supports a wide range of content types, from technical documentation, to educational materials, to blogs, and more. ## Setup -**For a normal user you can follow this process:** -First clone the repo: +First clone this repository: ```bash git clone https://git.tcp.direct/S4D/tcp-wiki.git ``` Then you have to cd into the repo's folder and run/compile: ```bash -cd tcp-wiki/src -go run . -``` -Then you goto your browser and visit: http://127.0.0.1:8080/ - -**For a develeper setup you can follow this process:** - -First clone the repo: -```bash -git clone ssh://git@git.tcp.direct:2222/S4D/tcp-wiki.git -``` -Then cd and run dev.sh -```bash cd tcp-wiki -bash dev.sh -``` -Then you just have to execute this to run the server: -```go -cd src && go run . +go run ./src ``` Then you goto your browser and visit: http://127.0.0.1:8080/ -This method just adds in some handy symlinks for development purposes +## Want to use with your own data? -## Want to use with your own repo? +All you have to do is modify the following lines in the `config.toml` file: -All you have to do is modify the following lines in the src/main.go file: -```go -const repoURL = "https://git.tcp.direct/S4D/tcp-wiki.git" -``` -Change `https://git.tcp.direct/S4D/tcp-wiki.git` to your repo link, and: -```go -const repoBRANCH = "main" +```toml +[Git] +UseGit = true # Set to false to use LocalPath +RepoURL = "https://git.tcp.direct/S4D/tcp-wiki.git" # Your Repo Here +Branch = "main" # Your Repo Branch Here +LocalPath = "data" # Directory to clone the git repo too ``` + +Change the `RepoURL` line `https://git.tcp.direct/S4D/tcp-wiki.git` to your repo link, change `main` to your specific repo's branch and you should be good to go! +#### Want to use a local directory other then git repo? + +To do this you just need to set `UseGit` to `false` and set your directory in config.toml + +```toml +[Git] +UseGit = false # Set this to false +RepoURL = "" # Ignored +Branch = "" # Ignored +LocalPath = "/home/crazy/blog" # The directory of your project +``` +make sure to also set `LocalPath` to the directory of your project + +> ### Want to use your own theme/layout? +> +> Have a look at the `assets/` directory for the templates + ## TODO -- [ ] config files +- [x] config file - [ ] Webhook support for auto pull on push/update of the git repo - [x] Git Branch support - [ ] add a star/upvote/like feature for pages - [x] edit/version tracker - [x] Author - [x] last edited - - [ ] last editor/commit [?] maybe working + - [x] last editor/commit - maybe working - [ ] PGP Signed & Verification - [ ] pgp signed intergration - [x] comments using bitcask - generated in comments.db/ @@ -76,7 +77,6 @@ change `main` to your specific repo's branch and you should be good to go! - [ ] set security controls per page - [ ] auto refresh on post - [x] dynamically generated links for all avaiable pages - - [ ] sitemap - - [ ] anti robot shit here - - [x] acual working pages!? + - [x] sitemap - kinda + - [x] working pages - [ ] image support diff --git a/assets/_layout.html b/assets/_layout.html index 5985075..489b747 100644 --- a/assets/_layout.html +++ b/assets/_layout.html @@ -24,13 +24,15 @@ {{ .Content }}
+ {{ if .UseGit }}
{{- if eq .Author .LastModifier -}} Authored: {{ .Author }} @ {{ .AuthoredDate.Format "2006/01/02" }} {{- else -}} Authored: {{ .Author }} @ {{ .AuthoredDate.Format "2006/01/02" }} - Modified: {{ .LastModifier }} @ {{ .LastModifiedDate.Format "2006/01/02" }} {{- end -}} -
+ + {{ end }}

Comments

{{ range .Comments }} diff --git a/config.toml b/config.toml new file mode 100644 index 0000000..9195c4f --- /dev/null +++ b/config.toml @@ -0,0 +1,12 @@ +[Server] +Port = ":8080" + +[Git] +UseGit = true +RepoURL = "https://git.tcp.direct/S4D/tcp-wiki.git" +Branch = "main" +LocalPath = "data" + +[Database] +Path = "comments.db" + diff --git a/dev.sh b/dev.sh deleted file mode 100644 index 75c7f3f..0000000 --- a/dev.sh +++ /dev/null @@ -1,22 +0,0 @@ -#/bin/bash -# this sets up super annoying shit like hard symlinks and whatever else -# but for now we can manage by editing via hardlinks. -# This sets up your local readme as the main page and the files in assets as public - -# Clone the repository -echo "Press Control+C when prompted" -go run ./src - - - -# Set up hard links -# !!! for main branch only !!! -rm data/assets/* -ln assets/_layout.html data/assets/_layout.html -ln assets/main.css data/assets/main.css -rm data/README.md -ln README.md data/README.md - -echo "Developer setup ready!" -echo "Go ahead and run go run src/" -echo "And Go to: http://127.0.0.1:8080" diff --git a/go.mod b/go.mod index b803a94..147ca25 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module git.tcp.direct/S4D/tcp-wiki go 1.20 require ( + github.com/BurntSushi/toml v1.3.2 // indirect github.com/Microsoft/go-winio v0.6.0 // indirect github.com/ProtonMail/go-crypto v0.0.0-20230331115716-d34776aa93ec // indirect github.com/acomagu/bufpipe v1.0.4 // indirect diff --git a/go.sum b/go.sum index 66432ed..d26463f 100644 --- a/go.sum +++ b/go.sum @@ -12,6 +12,8 @@ cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2k cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= +github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg= diff --git a/src/main.go b/src/main.go index 7f3bfe8..97d1ebb 100644 --- a/src/main.go +++ b/src/main.go @@ -14,21 +14,46 @@ import ( "github.com/go-git/go-git/v5" "github.com/prologic/bitcask" + "github.com/BurntSushi/toml" ) -const repoURL = "https://git.tcp.direct/S4D/tcp-wiki.git" -const repoBRANCH = "main" -const localPath = "data" +type Config struct { + Server struct { + Port string + } + Git struct { + UseGit bool + RepoURL string + Branch string + LocalPath string + } + Database struct { + Path string + } +} var commentsDB *bitcask.Bitcask func main() { - err := cloneRepository(repoURL, localPath) - if err != nil && err != git.ErrRepositoryAlreadyExists { - log.Fatalf("Failed to clone repository: %v", err) - } + var config Config + if _, err := toml.DecodeFile("config.toml", &config); err != nil { + log.Fatalf("Failed to load config: %v", err) + } - commentsDB, err = bitcask.Open("comments.db") + if config.Git.UseGit { + err := cloneRepository(config.Git.RepoURL, config.Git.LocalPath) + if err != nil && err != git.ErrRepositoryAlreadyExists { + log.Fatalf("Failed to clone repository: %v", err) + } + } else { + if _, err := os.Stat(config.Git.LocalPath); os.IsNotExist(err) { + os.MkdirAll(config.Git.LocalPath, os.ModePerm) + } + } + + var err error + + commentsDB, err = bitcask.Open(config.Database.Path) if err != nil { log.Fatalf("Failed to open comments database: %v", err) } @@ -36,10 +61,14 @@ func main() { fs := http.FileServer(http.Dir("./assets")) http.Handle("/assets/", http.StripPrefix("/assets/", fs)) - http.HandleFunc("/", handler) - http.HandleFunc("/submit_comment", submitCommentHandler) + http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + handler(&config, w, r) + }) + http.HandleFunc("/submit_comment", func(w http.ResponseWriter, r *http.Request) { + submitCommentHandler(w, r) + }) - srv := &http.Server{Addr: ":8080"} + srv := &http.Server{Addr: config.Server.Port} go func() { if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { log.Fatalf("ListenAndServe() failed: %v", err) @@ -49,12 +78,10 @@ func main() { fmt.Println("Server running at http://127.0.0.1:8080") fmt.Println("Press Ctrl-C to stop the server") - // Wait for interrupt signal to stop the server c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt, syscall.SIGTERM) <-c - // Shutdown the server gracefully ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() if err := srv.Shutdown(ctx); err != nil { @@ -63,18 +90,22 @@ func main() { fmt.Println("Server stopped") } -func handler(w http.ResponseWriter, r *http.Request) { +func handler(config *Config, w http.ResponseWriter, r *http.Request) { // For debugging - log.Printf("LOCAL PATH: %q", localPath) + log.Printf("Local Path: %q", config.Git.LocalPath) if r.URL.Path == "./assets/favicon.ico" { return } - err := pullRepository(localPath, repoBRANCH) - if err != nil { - log.Printf("Failed to pull repository: %v", err) - } + if config.Git.UseGit { + err := pullRepository(config.Git.LocalPath, config.Git.Branch) + if err != nil { + log.Printf("Failed to pull repository: %v", err) + http.Error(w, "Internal Server Error", http.StatusInternalServerError) + return + } + } filePath := strings.TrimPrefix(r.URL.Path, "/") if filePath == "" { @@ -86,33 +117,34 @@ func handler(w http.ResponseWriter, r *http.Request) { csp := "default-src 'self'; img-src 'self'; script-src 'self'; style-src 'self';" w.Header().Set("Content-Security-Policy", csp) - markdownFiles, err := listMarkdownFiles(localPath) + markdownFiles, err := listMarkdownFiles(config.Git.LocalPath) if err != nil { log.Printf("Error listing markdown files: %v", err) http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } - err = renderPage(w, r, localPath, filePath, commentsDB, markdownFiles) + err = renderPage(w, r, config, filePath, commentsDB, markdownFiles) if err != nil { log.Printf("Failed to render page: %v", err) http.Error(w, "File not found", http.StatusNotFound) } } - func listMarkdownFiles(localPath string) ([]string, error) { var files []string + err := filepath.Walk(localPath, func(path string, info os.FileInfo, err error) error { if err != nil { return err } + if !info.IsDir() && strings.HasSuffix(path, ".md") { relPath, err := filepath.Rel(localPath, path) if err != nil { return err } - // Ensure the path uses web-friendly slashes + relPath = strings.Replace(relPath, string(os.PathSeparator), "/", -1) files = append(files, relPath) } diff --git a/src/render.go b/src/render.go index e840730..62c65f1 100644 --- a/src/render.go +++ b/src/render.go @@ -21,22 +21,34 @@ type Page struct { Comments []Comment Path string Author string - AuthoredDate time.Time + AuthoredDate *time.Time LastModifier string - LastModifiedDate time.Time + LastModifiedDate *time.Time Pages []string + UseGit bool } -func renderPage(w http.ResponseWriter, r *http.Request, localPath, filePath string, commentsDB *bitcask.Bitcask, pages []string) error { - content, err := readFileFromRepo(localPath, filePath) - if err != nil { +func renderPage(w http.ResponseWriter, r *http.Request, config *Config, filePath string, commentsDB *bitcask.Bitcask, pages []string) error { + var content []byte + var err error + + if config.Git.UseGit { + content, err = readFileFromRepo(config.Git.LocalPath, filePath) + if err != nil { return err + } + } else { + fullPath := filepath.Join(config.Git.LocalPath, filePath) + content, err = ioutil.ReadFile(fullPath) + if err != nil { + return err + } } ext := filepath.Ext(filePath) switch ext { case ".md": - renderMarkdown(w, r, content, commentsDB, localPath, filePath, pages) // Now correctly includes `pages` + renderMarkdown(w, r, content, commentsDB, filePath, pages, config) case ".html", ".css": renderStatic(w, content, ext) default: @@ -45,23 +57,31 @@ func renderPage(w http.ResponseWriter, r *http.Request, localPath, filePath stri return nil } - -func renderMarkdown(w http.ResponseWriter, r *http.Request, content []byte, commentsDB *bitcask.Bitcask, localPath, filePath string, pages []string) { +func renderMarkdown(w http.ResponseWriter, r *http.Request, content []byte, commentsDB *bitcask.Bitcask, filePath string, pages []string, config *Config) { md := goldmark.New( goldmark.WithExtensions( - extension.GFM, // GitHub Flavored Markdown - highlighting.NewHighlighting( - highlighting.WithStyle("monokai"), + extension.GFM, + highlighting.NewHighlighting( + highlighting.WithStyle("monokai"), ), ), ) - author, authoredDate, lastModifier, lastModifiedDate, err := getAuthorAndLastModification(localPath, filePath) - if err != nil { - http.Error(w, "Error fetching author and last modification date", http.StatusInternalServerError) - return - } + var author, lastModifier string + var authoredDate, lastModifiedDate *time.Time + var err error + + if config.Git.UseGit { + var ad, lmd time.Time + author, ad, lastModifier, lmd, err = getAuthorAndLastModification(config.Git.LocalPath, filePath) + if err != nil { + http.Error(w, "Error fetching author and last modification date", http.StatusInternalServerError) + return + } + authoredDate = &ad + lastModifiedDate = &lmd + } var mdBuf bytes.Buffer err = md.Convert(content, &mdBuf) @@ -93,7 +113,9 @@ func renderMarkdown(w http.ResponseWriter, r *http.Request, content []byte, comm LastModifier: lastModifier, LastModifiedDate: lastModifiedDate, Pages: pages, + UseGit: config.Git.UseGit, } + t, err := template.New("layout").Parse(string(layout)) if err != nil { http.Error(w, "Error parsing layout", http.StatusInternalServerError) @@ -103,8 +125,8 @@ func renderMarkdown(w http.ResponseWriter, r *http.Request, content []byte, comm var buf bytes.Buffer err = t.Execute(&buf, page) if err != nil { - log.Printf("Error executing template: %v", err) // Add this line - http.Error(w, "Error rendering layout", http.StatusInternalServerError) + log.Printf("Error executing template: %v", err) + http.Error(w, "Error rendering layout", http.StatusInternalServerError) return }