Compare commits
	
		
			6 Commits
		
	
	
		
			d2b21e7405
			...
			bc4d8fa37e
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| bc4d8fa37e | |||
| 1368593c75 | |||
| e4bef7006c | |||
| afa1b65563 | |||
| a9bef63174 | |||
| 4d944ef65a | 
							
								
								
									
										28
									
								
								cmd/backend/files.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								cmd/backend/files.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | |||||||
|  | package backend | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"io" | ||||||
|  | 	"os" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func CopyFile(src, dst string) error { | ||||||
|  | 	srcFile, err := os.Open(src) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return fmt.Errorf("error opening source file: %v", err) | ||||||
|  | 	} | ||||||
|  | 	defer srcFile.Close() | ||||||
|  |  | ||||||
|  | 	dstFile, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return fmt.Errorf("error opening destination file: %v", err) | ||||||
|  | 	} | ||||||
|  | 	defer dstFile.Close() | ||||||
|  |  | ||||||
|  | 	_, err = io.Copy(dstFile, srcFile) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return fmt.Errorf("error copying file: %v", err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return dstFile.Sync() | ||||||
|  | } | ||||||
| @@ -10,7 +10,10 @@ import ( | |||||||
| 	"github.com/gorilla/sessions" | 	"github.com/gorilla/sessions" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type CookieStore struct{ sessions.CookieStore } | type ( | ||||||
|  | 	CookieStore struct{ sessions.CookieStore } | ||||||
|  | 	Session     struct{ sessions.Session } | ||||||
|  | ) | ||||||
|  |  | ||||||
| func NewKey() ([]byte, error) { | func NewKey() ([]byte, error) { | ||||||
| 	key := make([]byte, 32) | 	key := make([]byte, 32) | ||||||
|   | |||||||
| @@ -33,27 +33,6 @@ type EditorHTMLData struct { | |||||||
| 	Tags         []*b.Tag | 	Tags         []*b.Tag | ||||||
| } | } | ||||||
|  |  | ||||||
| func copyFile(src, dst string) error { |  | ||||||
| 	srcFile, err := os.Open(src) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return fmt.Errorf("error opening source file: %v", err) |  | ||||||
| 	} |  | ||||||
| 	defer srcFile.Close() |  | ||||||
|  |  | ||||||
| 	dstFile, err := os.Create(dst) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return fmt.Errorf("error opening destination file: %v", err) |  | ||||||
| 	} |  | ||||||
| 	defer dstFile.Close() |  | ||||||
|  |  | ||||||
| 	_, err = io.Copy(dstFile, srcFile) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return fmt.Errorf("error copying file: %v", err) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return dstFile.Sync() |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func WriteArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { | func WriteArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { | ||||||
| 	return func(w http.ResponseWriter, r *http.Request) { | 	return func(w http.ResponseWriter, r *http.Request) { | ||||||
| 		session, err := getSession(w, r, c, s) | 		session, err := getSession(w, r, c, s) | ||||||
| @@ -61,14 +40,13 @@ func WriteArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { | |||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		data := new(EditorHTMLData) | 		data := &EditorHTMLData{Action: "submit"} | ||||||
|  |  | ||||||
| 		if session.Values["article"] == nil { | 		if session.Values["article"] == nil { | ||||||
| 			data = &EditorHTMLData{Article: new(b.Article)} | 			data = &EditorHTMLData{Article: new(b.Article)} | ||||||
| 		} else { | 		} else { | ||||||
| 			data = session.Values["article"].(*EditorHTMLData) | 			data = session.Values["article"].(*EditorHTMLData) | ||||||
| 		} | 		} | ||||||
| 		// data.Mode = EditMode |  | ||||||
|  |  | ||||||
| 		data.Tags, err = db.GetTagList() | 		data.Tags, err = db.GetTagList() | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| @@ -77,8 +55,6 @@ func WriteArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { | |||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		data.Action = "submit" |  | ||||||
|  |  | ||||||
| 		tmpl, err := template.ParseFiles(c.WebDir + "/templates/editor.html") | 		tmpl, err := template.ParseFiles(c.WebDir + "/templates/editor.html") | ||||||
| 		template.Must(tmpl, err).ExecuteTemplate(w, "page-content", data) | 		template.Must(tmpl, err).ExecuteTemplate(w, "page-content", data) | ||||||
| 	} | 	} | ||||||
| @@ -696,7 +672,7 @@ func AllowEditArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc | |||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if err = copyFile(fmt.Sprint(c.ArticleDir, "/", oldID, ".md"), fmt.Sprint(c.ArticleDir, "/", newID, ".md")); err != nil { | 		if err = b.CopyFile(fmt.Sprint(c.ArticleDir, "/", oldID, ".md"), fmt.Sprint(c.ArticleDir, "/", newID, ".md")); err != nil { | ||||||
| 			log.Println(err) | 			log.Println(err) | ||||||
| 			http.Error(w, err.Error(), http.StatusInternalServerError) | 			http.Error(w, err.Error(), http.StatusInternalServerError) | ||||||
| 			return | 			return | ||||||
| @@ -762,94 +738,3 @@ func EditArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { | |||||||
| 		template.Must(tmpl, err).ExecuteTemplate(w, "page-content", data) | 		template.Must(tmpl, err).ExecuteTemplate(w, "page-content", data) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func SaveArticle(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { |  | ||||||
| 	return func(w http.ResponseWriter, r *http.Request) { |  | ||||||
| 		session, err := getSession(w, r, c, s) |  | ||||||
| 		if err != nil { |  | ||||||
| 			return |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		session.Values["article"] = nil |  | ||||||
| 		if err = session.Save(r, w); err != nil { |  | ||||||
| 			log.Println(err) |  | ||||||
| 			http.Error(w, err.Error(), http.StatusInternalServerError) |  | ||||||
| 			return |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		article := &b.Article{ |  | ||||||
| 			Title:         r.PostFormValue("article-title"), |  | ||||||
| 			Description:   r.PostFormValue("article-description"), |  | ||||||
| 			Published:     false, |  | ||||||
| 			Rejected:      false, |  | ||||||
| 			AuthorID:      session.Values["id"].(int64), |  | ||||||
| 			IsInIssue:     r.PostFormValue("issue") == "on", |  | ||||||
| 			AutoGenerated: false, |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		oldID, err := strconv.ParseInt(r.PathValue("id"), 10, 64) |  | ||||||
| 		if err != nil { |  | ||||||
| 			log.Println(err) |  | ||||||
| 			http.Error(w, err.Error(), http.StatusInternalServerError) |  | ||||||
| 			return |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		fmt.Println(oldID) |  | ||||||
| 		if oldID != 0 { |  | ||||||
| 			if err = db.DeleteArticle(oldID); err != nil { |  | ||||||
| 				log.Println(err) |  | ||||||
| 				http.Error(w, err.Error(), http.StatusInternalServerError) |  | ||||||
| 				return |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			if err = os.Remove(fmt.Sprint(c.ArticleDir, "/", oldID, ".md")); err != nil { |  | ||||||
| 				log.Println(err) |  | ||||||
| 				http.Error(w, err.Error(), http.StatusInternalServerError) |  | ||||||
| 				return |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		article.ID, err = db.AddArticle(article) |  | ||||||
| 		if err != nil { |  | ||||||
| 			log.Println(err) |  | ||||||
| 			http.Error(w, err.Error(), http.StatusInternalServerError) |  | ||||||
| 			return |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		articleAbsName := fmt.Sprint(c.ArticleDir, "/", article.ID, ".md") |  | ||||||
| 		if err = os.WriteFile(articleAbsName, []byte(r.PostFormValue("article-content")), 0644); err != nil { |  | ||||||
| 			log.Println(err) |  | ||||||
| 			http.Error(w, err.Error(), http.StatusInternalServerError) |  | ||||||
| 			return |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		article.Link = fmt.Sprint(c.Domain, "/article/serve/", article.ID) |  | ||||||
| 		if err = db.UpdateAttributes(&b.Attribute{Table: "articles", ID: article.ID, AttName: "link", Value: article.Link}); err != nil { |  | ||||||
| 			log.Println(err) |  | ||||||
| 			http.Error(w, err.Error(), http.StatusInternalServerError) |  | ||||||
| 			return |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		r.ParseForm() |  | ||||||
| 		tags := make([]int64, 0) |  | ||||||
| 		for _, tag := range r.Form["tags"] { |  | ||||||
| 			tagID, err := strconv.ParseInt(tag, 10, 64) |  | ||||||
| 			if err != nil { |  | ||||||
| 				log.Println(err) |  | ||||||
| 				http.Error(w, err.Error(), http.StatusInternalServerError) |  | ||||||
| 				return |  | ||||||
| 			} |  | ||||||
| 			tags = append(tags, tagID) |  | ||||||
| 		} |  | ||||||
| 		if err = db.WriteArticleTags(article.ID, tags); err != nil { |  | ||||||
| 			log.Println(err) |  | ||||||
| 			http.Error(w, err.Error(), http.StatusInternalServerError) |  | ||||||
| 			return |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html") |  | ||||||
| 		tmpl = template.Must(tmpl, err) |  | ||||||
| 		tmpl.ExecuteTemplate(w, "page-content", session.Values["role"]) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|   | |||||||
| @@ -1,6 +1,7 @@ | |||||||
| package frontend | package frontend | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
|  | 	"errors" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"html/template" | 	"html/template" | ||||||
| 	"log" | 	"log" | ||||||
| @@ -26,6 +27,26 @@ func saveSession(w http.ResponseWriter, r *http.Request, s *b.CookieStore, u *b. | |||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // getSession is used for verifying that the user is logged in and returns their session and an error. | ||||||
|  | func getSession(w http.ResponseWriter, r *http.Request, c *b.Config, s *b.CookieStore) (*b.Session, error) { | ||||||
|  | 	msg := "Keine gültige Session. Bitte erneut anmelden." | ||||||
|  | 	tmpl, tmplErr := template.ParseFiles(c.WebDir+"/templates/index.html", c.WebDir+"/templates/login.html") | ||||||
|  |  | ||||||
|  | 	tmpSession, err := s.Get(r, "cookie") | ||||||
|  | 	if err != nil { | ||||||
|  | 		template.Must(tmpl, tmplErr).ExecuteTemplate(w, "page-content", msg) | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	session := &b.Session{Session: *tmpSession} | ||||||
|  | 	if session.IsNew { | ||||||
|  | 		template.Must(tmpl, tmplErr).ExecuteTemplate(w, "page-content", msg) | ||||||
|  | 		return session, errors.New("error: no existing session") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return session, nil | ||||||
|  | } | ||||||
|  |  | ||||||
| func HomePage(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { | func HomePage(c *b.Config, db *b.DB, s *b.CookieStore) http.HandlerFunc { | ||||||
| 	return func(w http.ResponseWriter, r *http.Request) { | 	return func(w http.ResponseWriter, r *http.Request) { | ||||||
| 		numRows, err := db.CountEntries("users") | 		numRows, err := db.CountEntries("users") | ||||||
|   | |||||||
| @@ -1,29 +0,0 @@ | |||||||
| package frontend |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"errors" |  | ||||||
| 	"html/template" |  | ||||||
| 	"net/http" |  | ||||||
|  |  | ||||||
| 	"github.com/gorilla/sessions" |  | ||||||
| 	b "streifling.com/jason/cpolis/cmd/backend" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| // getSession is used for verifying that the user is logged in and returns their session and an error. |  | ||||||
| func getSession(w http.ResponseWriter, r *http.Request, c *b.Config, s *b.CookieStore) (*sessions.Session, error) { |  | ||||||
| 	msg := "Keine gültige Session. Bitte erneut anmelden." |  | ||||||
| 	tmpl, tmplErr := template.ParseFiles(c.WebDir+"/templates/index.html", c.WebDir+"/templates/login.html") |  | ||||||
|  |  | ||||||
| 	session, err := s.Get(r, "cookie") |  | ||||||
| 	if err != nil { |  | ||||||
| 		template.Must(tmpl, tmplErr).ExecuteTemplate(w, "page-content", msg) |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if session.IsNew { |  | ||||||
| 		template.Must(tmpl, tmplErr).ExecuteTemplate(w, "page-content", msg) |  | ||||||
| 		return session, errors.New("error: no existing session") |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return session, nil |  | ||||||
| } |  | ||||||
| @@ -62,7 +62,6 @@ func main() { | |||||||
| 	mux.HandleFunc("GET /article/review-edit/{id}", f.ReviewArticle(config, db, store, "allow-edit", "Artikel bearbeiten", "Bearbeiten erlauben")) | 	mux.HandleFunc("GET /article/review-edit/{id}", f.ReviewArticle(config, db, store, "allow-edit", "Artikel bearbeiten", "Bearbeiten erlauben")) | ||||||
| 	mux.HandleFunc("GET /article/review-rejected/{id}", f.ReviewRejectedArticle(config, db, store)) | 	mux.HandleFunc("GET /article/review-rejected/{id}", f.ReviewRejectedArticle(config, db, store)) | ||||||
| 	mux.HandleFunc("GET /article/review-unpublished/{id}", f.ReviewArticle(config, db, store, "publish", "Artikel veröffentlichen", "Veröffentlichen")) | 	mux.HandleFunc("GET /article/review-unpublished/{id}", f.ReviewArticle(config, db, store, "publish", "Artikel veröffentlichen", "Veröffentlichen")) | ||||||
| 	mux.HandleFunc("GET /article/save/{id}", f.SaveArticle(config, db, store)) |  | ||||||
| 	mux.HandleFunc("GET /article/serve/{id}", c.ServeArticle(config, db)) | 	mux.HandleFunc("GET /article/serve/{id}", c.ServeArticle(config, db)) | ||||||
| 	mux.HandleFunc("GET /article/write", f.WriteArticle(config, db, store)) | 	mux.HandleFunc("GET /article/write", f.WriteArticle(config, db, store)) | ||||||
| 	mux.HandleFunc("GET /hub", f.ShowHub(config, db, store)) | 	mux.HandleFunc("GET /hub", f.ShowHub(config, db, store)) | ||||||
|   | |||||||
| @@ -35,7 +35,7 @@ | |||||||
|  |  | ||||||
|     <footer class="text-center text-gray-500 my-8"> |     <footer class="text-center text-gray-500 my-8"> | ||||||
|         <p>© 2024 Jason Streifling. Alle Rechte vorbehalten.</p> |         <p>© 2024 Jason Streifling. Alle Rechte vorbehalten.</p> | ||||||
|         <p>v0.11.0 - <strong>Alpha: Drastische Änderungen und Fehler vorbehalten.</strong></p> |         <p>v0.11.1 - <strong>Alpha: Drastische Änderungen und Fehler vorbehalten.</strong></p> | ||||||
|     </footer> |     </footer> | ||||||
|  |  | ||||||
|     <script src="https://unpkg.com/htmx.org@2.0.2"></script> |     <script src="https://unpkg.com/htmx.org@2.0.2"></script> | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user