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 ?
+
-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 }