diff --git a/cmd/backend/articles.go b/cmd/backend/articles.go index 23a4e0b..ffee3af 100644 --- a/cmd/backend/articles.go +++ b/cmd/backend/articles.go @@ -115,6 +115,31 @@ func (db *DB) GetArticle(id int64) (*Article, error) { return article, nil } +func (db *DB) GetArticleByUUID(u uuid.UUID) (*Article, error) { + query := ` + SELECT id, title, created, banner_link, summary, published, creator_id, issue_id, edited_id, clicks, is_in_issue, auto_generated + FROM articles + WHERE uuid = ? + ` + row := db.QueryRow(query, u.String()) + + article := new(Article) + var created []byte + var err error + + if err := row.Scan(&article.ID, &article.Title, &created, &article.BannerLink, &article.Summary, &article.Published, &article.CreatorID, &article.IssueID, &article.EditedID, &article.Clicks, &article.IsInIssue, &article.AutoGenerated); err != nil { + return nil, fmt.Errorf("error scanning article row: %v", err) + } + + article.UUID = u + article.Created, err = time.Parse("2006-01-02 15:04:05", string(created)) + if err != nil { + return nil, fmt.Errorf("error parsing created: %v", err) + } + + return article, nil +} + func (db *DB) GetCertainArticles(attribute string, value bool) ([]*Article, error) { query := fmt.Sprintf(` SELECT id, title, created, banner_link, summary, creator_id, issue_id, clicks, published, rejected, is_in_issue, auto_generated, uuid diff --git a/cmd/backend/config.go b/cmd/backend/config.go index 5fcb0f3..a2cdb31 100644 --- a/cmd/backend/config.go +++ b/cmd/backend/config.go @@ -52,7 +52,7 @@ func newConfig() *Config { PDFDir: "/var/www/cpolis/pdfs", PicsDir: "/var/www/cpolis/pics", Port: ":8080", - Version: "v0.15.0", + Version: "v0.15.2", WebDir: "/var/www/cpolis/web", } } @@ -91,7 +91,7 @@ func mkFile(path string, filePerm, dirPerm fs.FileMode) (string, error) { } fileName := stringSlice[len(stringSlice)-1] - file, err := os.Create(dir + "/" + fileName) + file, err := os.Create(filepath.Join(dir, fileName)) if err != nil { return "", fmt.Errorf("error creating %v: %v", fileName, err) } @@ -158,6 +158,10 @@ func (c *Config) setupConfig(cliConfig *Config) error { if cliConfig.AESKeyFile != defaultConfig.AESKeyFile { c.AESKeyFile = cliConfig.AESKeyFile } + c.AESKeyFile, err = filepath.Abs(c.AESKeyFile) + if err != nil { + return fmt.Errorf("error setting absolute filepath for AESKeyFile: %v", err) + } c.AESKeyFile, err = mkFile(c.AESKeyFile, 0600, 0700) if err != nil { return fmt.Errorf("error setting up file: %v", err) @@ -166,6 +170,10 @@ func (c *Config) setupConfig(cliConfig *Config) error { if cliConfig.ArticleDir != defaultConfig.ArticleDir { c.ArticleDir = cliConfig.ArticleDir } + c.ArticleDir, err = filepath.Abs(c.ArticleDir) + if err != nil { + return fmt.Errorf("error setting absolute filepath for ArticleDir: %v", err) + } c.ArticleDir, err = mkDir(c.ArticleDir, 0700) if err != nil { return fmt.Errorf("error setting up directory: %v", err) @@ -174,6 +182,10 @@ func (c *Config) setupConfig(cliConfig *Config) error { if cliConfig.AtomFile != defaultConfig.AtomFile { c.AtomFile = cliConfig.AtomFile } + c.AtomFile, err = filepath.Abs(c.AtomFile) + if err != nil { + return fmt.Errorf("error setting absolute filepath for AtomFile: %v", err) + } c.AtomFile, err = mkFile(c.AtomFile, 0644, 0744) if err != nil { return fmt.Errorf("error setting up file: %v", err) @@ -202,6 +214,10 @@ func (c *Config) setupConfig(cliConfig *Config) error { if cliConfig.FirebaseKey != defaultConfig.FirebaseKey { c.FirebaseKey = cliConfig.FirebaseKey } + c.FirebaseKey, err = filepath.Abs(c.FirebaseKey) + if err != nil { + return fmt.Errorf("error setting absolute filepath for FirebaseKey: %v", err) + } c.FirebaseKey, err = mkFile(c.FirebaseKey, 0600, 0700) if err != nil { return fmt.Errorf("error setting up file: %v", err) @@ -214,6 +230,10 @@ func (c *Config) setupConfig(cliConfig *Config) error { if cliConfig.LogFile != defaultConfig.LogFile { c.LogFile = cliConfig.LogFile } + c.LogFile, err = filepath.Abs(c.LogFile) + if err != nil { + return fmt.Errorf("error setting absolute filepath for LogFile: %v", err) + } c.LogFile, err = mkFile(c.LogFile, 0600, 0700) if err != nil { return fmt.Errorf("error setting up file: %v", err) @@ -238,6 +258,10 @@ func (c *Config) setupConfig(cliConfig *Config) error { if cliConfig.PDFDir != defaultConfig.PDFDir { c.PDFDir = cliConfig.PDFDir } + c.PDFDir, err = filepath.Abs(c.PDFDir) + if err != nil { + return fmt.Errorf("error setting absolute filepath for PDFDir: %v", err) + } c.PDFDir, err = mkDir(c.PDFDir, 0700) if err != nil { return fmt.Errorf("error setting up directory: %v", err) @@ -246,6 +270,10 @@ func (c *Config) setupConfig(cliConfig *Config) error { if cliConfig.PicsDir != defaultConfig.PicsDir { c.PicsDir = cliConfig.PicsDir } + c.PicsDir, err = filepath.Abs(c.PicsDir) + if err != nil { + return fmt.Errorf("error setting absolute filepath for PicsDir: %v", err) + } c.PicsDir, err = mkDir(c.PicsDir, 0700) if err != nil { return fmt.Errorf("error setting up directory: %v", err) @@ -262,6 +290,10 @@ func (c *Config) setupConfig(cliConfig *Config) error { if cliConfig.WebDir != defaultConfig.WebDir { c.WebDir = cliConfig.WebDir } + c.WebDir, err = filepath.Abs(c.WebDir) + if err != nil { + return fmt.Errorf("error setting absolute filepath for WebDir: %v", err) + } c.WebDir, err = mkDir(c.WebDir, 0700) if err != nil { return fmt.Errorf("error setting up directory: %v", err) diff --git a/cmd/backend/docx.go b/cmd/backend/docx.go index c44ee73..37f895c 100644 --- a/cmd/backend/docx.go +++ b/cmd/backend/docx.go @@ -14,15 +14,13 @@ import ( func ConvertToMarkdown(c *Config, filename string) ([]byte, error) { var stderr bytes.Buffer - articleID := uuid.New() - articleFileName := fmt.Sprint("/tmp/", articleID, ".md") - - tmpDir, err := os.MkdirTemp("/tmp", "cpolis_images") + tmpDir, err := os.MkdirTemp(os.TempDir(), "cpolis_images") if err != nil { return nil, fmt.Errorf("error creating temporary directory: %v", err) } defer os.RemoveAll(tmpDir) + articleFileName := filepath.Join(os.TempDir(), fmt.Sprint(uuid.New(), ".md")) cmd := exec.Command("pandoc", "-s", "-f", "docx", "-t", "commonmark_x", "-o", articleFileName, "--extract-media", tmpDir, filename) // TODO: Is writing to a file necessary? cmd.Stderr = &stderr if err = cmd.Run(); err != nil { @@ -52,7 +50,7 @@ func ConvertToMarkdown(c *Config, filename string) ([]byte, error) { return nil, fmt.Errorf("error saving image %v: %v", name, err) } - articleContent = regexp.MustCompile(name).ReplaceAll(articleContent, []byte(c.PicsDir+"/"+newImageName)) + articleContent = regexp.MustCompile(name).ReplaceAll(articleContent, []byte(c.Domain+"/image/serve/"+newImageName)) } return articleContent, nil diff --git a/cmd/backend/images.go b/cmd/backend/images.go index 398e201..a8dce5f 100644 --- a/cmd/backend/images.go +++ b/cmd/backend/images.go @@ -6,11 +6,9 @@ import ( "image" "io" "io/fs" - "log" "os" "path/filepath" "strings" - "time" "github.com/chai2010/webp" "github.com/disintegration/imaging" @@ -49,58 +47,67 @@ func SaveImage(src io.Reader, maxHeight, maxWidth int, path string) (string, err return filename, nil } -func CleanUpImages(c *Config) { - for { - if err := filepath.Walk(c.PicsDir, func(path string, info fs.FileInfo, err error) error { - if err != nil { - return err +func CleanUpImages(c *Config, db *DB) error { + if err := filepath.Walk(c.PicsDir, func(path string, info fs.FileInfo, err error) error { + if err != nil { + return fmt.Errorf("error walking images filepath: %v", err) + } + + if !info.IsDir() { + imageName := info.Name() + imagePath := path + imageWasFound := false + + if err = filepath.Walk(c.ArticleDir, func(path string, info fs.FileInfo, err error) error { + if err != nil { + return fmt.Errorf("error walking articles filepath: %v", err) + } + + if !info.IsDir() { + mdFile, err := os.Open(path) + if err != nil { + return fmt.Errorf("error opening article %v: %v", info.Name(), err) + } + defer mdFile.Close() + + scanner := bufio.NewScanner(mdFile) + + for scanner.Scan() { + if strings.Contains(scanner.Text(), imageName) { + imageWasFound = true + } + } + + return scanner.Err() + } + + return nil + }); err != nil { + return fmt.Errorf("error walking articles filepath: %v", err) } - if !info.IsDir() { - imageName := info.Name() - absImageName := path + users, err := db.GetAllUsers(c) + if err != nil { + return fmt.Errorf("error getting all users: %v", err) + } - if err = filepath.Walk(c.ArticleDir, func(path string, info fs.FileInfo, err error) error { - if err != nil { - return err - } - - if !info.IsDir() { - mdFile, err := os.Open(path) - if err != nil { - return err - } - defer mdFile.Close() - - scanner := bufio.NewScanner(mdFile) - imageWasFound := false - - for scanner.Scan() { - if strings.Contains(scanner.Text(), imageName) { - imageWasFound = true - } - } - - if !imageWasFound { - if err = os.Remove(absImageName); err != nil { - return err - } - } - - return scanner.Err() - } - - return nil - }); err != nil { - return err + for _, user := range users { + if imageName == user.ProfilePicLink { + imageWasFound = true } } - return nil - }); err != nil { - log.Println(err) + if !imageWasFound { + if err = os.Remove(imagePath); err != nil { + return fmt.Errorf("error removing unused image: %v", err) + } + } } - time.Sleep(time.Hour) + return nil + }); err != nil { + return fmt.Errorf("error cleaning up: %v", err) } + + return nil } diff --git a/cmd/calls/articles.go b/cmd/calls/articles.go index 4b5d518..3e46703 100644 --- a/cmd/calls/articles.go +++ b/cmd/calls/articles.go @@ -5,8 +5,8 @@ import ( "log" "net/http" "os" - "strconv" + "github.com/google/uuid" b "streifling.com/jason/cpolis/cmd/backend" ) @@ -37,15 +37,15 @@ func ServeArticle(c *b.Config, db *b.DB) http.HandlerFunc { return } - idString := r.PathValue("id") - id, err := strconv.ParseInt(idString, 10, 64) + uuidString := r.PathValue("uuid") + uuid, err := uuid.Parse(uuidString) if err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) return } - article, err := db.GetArticle(id) + article, err := db.GetArticleByUUID(uuid) if err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) @@ -56,7 +56,7 @@ func ServeArticle(c *b.Config, db *b.DB) http.HandlerFunc { return } - articleAbsName := fmt.Sprint(c.ArticleDir, "/", article.ID, ".md") + articleAbsName := fmt.Sprint(c.ArticleDir, "/", article.UUID, ".md") contentBytes, err := os.ReadFile(articleAbsName) if err != nil { log.Println(err) @@ -87,15 +87,14 @@ func ServeArticle(c *b.Config, db *b.DB) http.HandlerFunc { func ServeClicks(db *b.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - idString := r.PathValue("id") - id, err := strconv.ParseInt(idString, 10, 64) + uuid, err := uuid.Parse(r.PathValue("uuid")) if err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) return } - article, err := db.GetArticle(id) + article, err := db.GetArticleByUUID(uuid) if err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) diff --git a/cmd/calls/atom.go b/cmd/calls/atom.go index 6110d4f..d205795 100644 --- a/cmd/calls/atom.go +++ b/cmd/calls/atom.go @@ -1,9 +1,7 @@ package calls import ( - "log" "net/http" - "path/filepath" b "streifling.com/jason/cpolis/cmd/backend" ) @@ -14,13 +12,6 @@ func ServeAtomFeed(c *b.Config) http.HandlerFunc { return } - absFilepath, err := filepath.Abs(c.AtomFile) - if err != nil { - log.Println(err) - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - http.ServeFile(w, r, absFilepath) + http.ServeFile(w, r, c.AtomFile) } } diff --git a/cmd/calls/images.go b/cmd/calls/images.go index 7dae6a4..e8edab2 100644 --- a/cmd/calls/images.go +++ b/cmd/calls/images.go @@ -1,7 +1,6 @@ package calls import ( - "log" "net/http" "path/filepath" @@ -17,13 +16,6 @@ func ServeImage(c *b.Config, s map[string]*f.Session) http.HandlerFunc { } } - absFilepath, err := filepath.Abs(c.PicsDir) - if err != nil { - log.Println(err) - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - http.ServeFile(w, r, absFilepath+"/"+r.PathValue("pic")) + http.ServeFile(w, r, filepath.Join(c.PicsDir, r.PathValue("pic"))) } } diff --git a/cmd/frontend/articles.go b/cmd/frontend/articles.go index f112600..c8947f5 100644 --- a/cmd/frontend/articles.go +++ b/cmd/frontend/articles.go @@ -6,6 +6,7 @@ import ( "log" "net/http" "os" + "path/filepath" "strconv" "strings" "time" @@ -83,7 +84,7 @@ func WriteArticle(c *b.Config, db *b.DB, s map[string]*Session) http.HandlerFunc return } - tmpl, err := template.ParseFiles(c.WebDir + "/templates/editor.html") + tmpl, err := template.ParseFiles(filepath.Join(c.WebDir, "templates", "editor.html")) if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", data); err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) @@ -205,7 +206,7 @@ func SubmitArticle(c *b.Config, db *b.DB, s map[string]*Session) http.HandlerFun data := new(struct{ Role int }) data.Role = session.User.Role - tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html") + tmpl, err := template.ParseFiles(filepath.Join(c.WebDir, "templates", "hub.html")) tmpl = template.Must(tmpl, err) if err = tmpl.ExecuteTemplate(w, "page-content", data); err != nil { log.Println(err) @@ -340,7 +341,7 @@ func ResubmitArticle(c *b.Config, db *b.DB, s map[string]*Session) http.HandlerF data := new(struct{ Role int }) data.Role = session.User.Role - tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html") + tmpl, err := template.ParseFiles(filepath.Join(c.WebDir, "templates", "hub.html")) tmpl = template.Must(tmpl, err) if err = tmpl.ExecuteTemplate(w, "page-content", data); err != nil { log.Println(err) @@ -384,7 +385,7 @@ func ShowUnpublishedUnrejectedAndPublishedRejectedArticles(c *b.Config, db *b.DB } } - tmpl, err := template.ParseFiles(c.WebDir + "/templates/unpublished-articles.html") + tmpl, err := template.ParseFiles(filepath.Join(c.WebDir, "templates", "unpublished-articles.html")) if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", articles); err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) @@ -420,7 +421,7 @@ func ShowRejectedArticles(c *b.Config, db *b.DB, s map[string]*Session) http.Han } } - tmpl, err := template.ParseFiles(c.WebDir + "/templates/rejected-articles.html") + tmpl, err := template.ParseFiles(filepath.Join(c.WebDir, "templates", "rejected-articles.html")) tmpl = template.Must(tmpl, err) if err = tmpl.ExecuteTemplate(w, "page-content", data); err != nil { log.Println(err) @@ -524,7 +525,7 @@ func ReviewRejectedArticle(c *b.Config, db *b.DB, s map[string]*Session) http.Ha data.Action = fmt.Sprint("resubmit/", data.Article.ID) - tmpl, err := template.ParseFiles(c.WebDir + "/templates/editor.html") + tmpl, err := template.ParseFiles(filepath.Join(c.WebDir, "templates", "editor.html")) tmpl = template.Must(tmpl, err) if err = tmpl.ExecuteTemplate(w, "page-content", data); err != nil { log.Println(err) @@ -614,7 +615,7 @@ func PublishArticle(c *b.Config, db *b.DB, s map[string]*Session) http.HandlerFu data := new(struct{ Role int }) data.Role = session.User.Role - tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html") + tmpl, err := template.ParseFiles(filepath.Join(c.WebDir, "templates", "hub.html")) tmpl = template.Must(tmpl, err) if err = tmpl.ExecuteTemplate(w, "page-content", data); err != nil { log.Println(err) @@ -648,7 +649,7 @@ func RejectArticle(c *b.Config, db *b.DB, s map[string]*Session) http.HandlerFun data := new(struct{ Role int }) data.Role = session.User.Role - tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html") + tmpl, err := template.ParseFiles(filepath.Join(c.WebDir, "templates", "hub.html")) tmpl = template.Must(tmpl, err) if err = tmpl.ExecuteTemplate(w, "page-content", data); err != nil { log.Println(err) @@ -672,7 +673,7 @@ func ShowCurrentIssue(c *b.Config, db *b.DB, s map[string]*Session) http.Handler return } - tmpl, err := template.ParseFiles(c.WebDir + "/templates/current-issue.html") + tmpl, err := template.ParseFiles(filepath.Join(c.WebDir, "templates", "current-issue.html")) if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", articles); err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) @@ -707,7 +708,7 @@ func ShowPublishedArticles(c *b.Config, db *b.DB, s map[string]*Session, action } } - tmpl, err := template.ParseFiles(c.WebDir + "/templates/published-articles.html") + tmpl, err := template.ParseFiles(filepath.Join(c.WebDir, "templates", "published-articles.html")) tmpl = template.Must(tmpl, err) if err = tmpl.ExecuteTemplate(w, "page-content", data); err != nil { log.Println(err) @@ -802,7 +803,7 @@ func ReviewArticle(c *b.Config, db *b.DB, s map[string]*Session, action, title, return } - tmpl, err := template.ParseFiles(c.WebDir + "/templates/review-article.html") + tmpl, err := template.ParseFiles(filepath.Join(c.WebDir, "templates", "review-article.html")) if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", data); err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) @@ -845,6 +846,13 @@ func DeleteArticle(c *b.Config, db *b.DB, s map[string]*Session) http.HandlerFun return } + go func(c *b.Config, db *b.DB) { + if err = b.CleanUpImages(c, db); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + } + }(c, db) + feed, err := b.GenerateAtomFeed(c, db) if err != nil { log.Println(err) @@ -860,7 +868,7 @@ func DeleteArticle(c *b.Config, db *b.DB, s map[string]*Session) http.HandlerFun data := new(struct{ Role int }) data.Role = session.User.Role - tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html") + tmpl, err := template.ParseFiles(filepath.Join(c.WebDir, "templates", "hub.html")) tmpl = template.Must(tmpl, err) if err = tmpl.ExecuteTemplate(w, "page-content", data); err != nil { log.Println(err) @@ -953,7 +961,7 @@ func AllowEditArticle(c *b.Config, db *b.DB, s map[string]*Session) http.Handler data := new(struct{ Role int }) data.Role = session.User.Role - tmpl := template.Must(template.ParseFiles(c.WebDir + "/templates/hub.html")) + tmpl := template.Must(template.ParseFiles(filepath.Join(c.WebDir, "templates", "hub.html"))) if err = tmpl.ExecuteTemplate(w, "page-content", data); err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) @@ -1015,7 +1023,7 @@ func EditArticle(c *b.Config, db *b.DB, s map[string]*Session) http.HandlerFunc data.Action = fmt.Sprint("save/", data.Article.ID) - tmpl, err := template.ParseFiles(c.WebDir + "/templates/editor.html") + tmpl, err := template.ParseFiles(filepath.Join(c.WebDir, "templates", "editor.html")) if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", data); err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) diff --git a/cmd/frontend/docx.go b/cmd/frontend/docx.go index 9cf4712..98dbf48 100644 --- a/cmd/frontend/docx.go +++ b/cmd/frontend/docx.go @@ -44,22 +44,15 @@ func UploadDocx(c *b.Config, db *b.DB, s map[string]*Session) http.HandlerFunc { return } - docxFilename := fmt.Sprint(uuid.New(), ".docx") - absDocxFilepath, err := filepath.Abs("/tmp/" + docxFilename) - if err != nil { + docxFilepath := filepath.Join(os.TempDir(), fmt.Sprint(uuid.New(), ".docx")) + if err = os.WriteFile(docxFilepath, buf.Bytes(), 0644); err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) return } + defer os.Remove(docxFilepath) - if err = os.WriteFile(absDocxFilepath, buf.Bytes(), 0644); err != nil { - log.Println(err) - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - defer os.Remove(absDocxFilepath) - - mdString, err := b.ConvertToMarkdown(c, absDocxFilepath) + mdString, err := b.ConvertToMarkdown(c, docxFilepath) if err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) @@ -67,15 +60,8 @@ func UploadDocx(c *b.Config, db *b.DB, s map[string]*Session) http.HandlerFunc { } uuidName := uuid.New() - mdFilename := fmt.Sprint(uuidName, ".md") - absMdFilepath, err := filepath.Abs(c.ArticleDir + "/" + mdFilename) - if err != nil { - log.Println(err) - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - if err = os.WriteFile(absMdFilepath, mdString, 0644); err != nil { + mdFilepath := filepath.Join(c.ArticleDir, fmt.Sprint(uuidName, ".md")) + if err = os.WriteFile(mdFilepath, mdString, 0644); err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) return diff --git a/cmd/frontend/homepage.go b/cmd/frontend/homepage.go index 3e41905..29e7a46 100644 --- a/cmd/frontend/homepage.go +++ b/cmd/frontend/homepage.go @@ -4,6 +4,7 @@ import ( "html/template" "log" "net/http" + "path/filepath" "time" b "streifling.com/jason/cpolis/cmd/backend" @@ -24,14 +25,14 @@ func HomePage(c *b.Config, db *b.DB, s map[string]*Session) http.HandlerFunc { data.Version = c.Version files := make([]string, 2) - files[0] = c.WebDir + "/templates/index.html" + files[0] = filepath.Join(c.WebDir, "templates", "index.html") if numRows == 0 { data.Role = b.NonExistent data.Title = "Erster Benutzer (Administrator)" data.ButtonText = "Anlegen" data.URL = "/user/add-first" - files[1] = c.WebDir + "/templates/edit-user.html" + files[1] = filepath.Join(c.WebDir, "templates", "edit-user.html") tmpl, err := template.ParseFiles(files...) if err = template.Must(tmpl, err).Execute(w, data); err != nil { log.Println(err) @@ -41,7 +42,7 @@ func HomePage(c *b.Config, db *b.DB, s map[string]*Session) http.HandlerFunc { } else { cookie, err := r.Cookie("cpolis_session") if err != nil { - files[1] = c.WebDir + "/templates/login.html" + files[1] = filepath.Join(c.WebDir, "templates", "login.html") tmpl, err := template.ParseFiles(files...) if err = template.Must(tmpl, err).Execute(w, data); err != nil { log.Println(err) @@ -56,7 +57,7 @@ func HomePage(c *b.Config, db *b.DB, s map[string]*Session) http.HandlerFunc { cookie.Expires = time.Now() http.SetCookie(w, cookie) - files[1] = c.WebDir + "/templates/login.html" + files[1] = filepath.Join(c.WebDir, "templates", "login.html") tmpl, err := template.ParseFiles(files...) if err = template.Must(tmpl, err).Execute(w, data); err != nil { log.Println(err) @@ -67,7 +68,7 @@ func HomePage(c *b.Config, db *b.DB, s map[string]*Session) http.HandlerFunc { } data.Role = session.User.Role - files[1] = c.WebDir + "/templates/hub.html" + files[1] = filepath.Join(c.WebDir, "templates", "hub.html") tmpl, err := template.ParseFiles(files...) if err = template.Must(tmpl, err).Execute(w, data); err != nil { log.Println(err) @@ -89,7 +90,7 @@ func ShowHub(c *b.Config, db *b.DB, s map[string]*Session) http.HandlerFunc { data := new(struct{ Role int }) data.Role = session.User.Role - tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html") + tmpl, err := template.ParseFiles(filepath.Join(c.WebDir, "templates", "hub.html")) if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", data); err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) diff --git a/cmd/frontend/images.go b/cmd/frontend/images.go index 870b46a..fb785f0 100644 --- a/cmd/frontend/images.go +++ b/cmd/frontend/images.go @@ -5,6 +5,7 @@ import ( "html/template" "log" "net/http" + "path/filepath" b "streifling.com/jason/cpolis/cmd/backend" ) @@ -70,7 +71,7 @@ func UploadImage(c *b.Config, s map[string]*Session, fileKey, htmlFile, htmlTemp data := new(struct{ Image string }) data.Image = filename - tmpl, err := template.ParseFiles(c.WebDir + "/templates/" + htmlFile) + tmpl, err := template.ParseFiles(filepath.Join(c.WebDir, "templates", htmlFile)) if err = template.Must(tmpl, err).ExecuteTemplate(w, htmlTemplate, data); err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) diff --git a/cmd/frontend/issues.go b/cmd/frontend/issues.go index ee663af..7c41f75 100644 --- a/cmd/frontend/issues.go +++ b/cmd/frontend/issues.go @@ -6,6 +6,7 @@ import ( "log" "net/http" "os" + "path/filepath" "time" "github.com/google/uuid" @@ -91,7 +92,7 @@ func PublishLatestIssue(c *b.Config, db *b.DB, s map[string]*Session) http.Handl data := new(struct{ Role int }) data.Role = session.User.Role - tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html") + tmpl, err := template.ParseFiles(filepath.Join(c.WebDir, "templates", "hub.html")) tmpl = template.Must(tmpl, err) if err = tmpl.ExecuteTemplate(w, "page-content", data); err != nil { log.Println(err) diff --git a/cmd/frontend/pdf.go b/cmd/frontend/pdf.go index 5e4c399..3648d03 100644 --- a/cmd/frontend/pdf.go +++ b/cmd/frontend/pdf.go @@ -44,17 +44,11 @@ func UploadPDF(c *b.Config, s map[string]*Session) http.HandlerFunc { return } - oldFilename := header.Filename - oldFilename = strings.Join(strings.Split(oldFilename, ".")[:len(oldFilename)-1], ".") + oldFilename := strings.Join(strings.Split(header.Filename, ".")[:len(header.Filename)-1], ".") filename := fmt.Sprint(oldFilename, ".", uuid.New(), ".pdf") - absFilepath, err := filepath.Abs(c.PDFDir + "/" + filename) - if err != nil { - log.Println(err) - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } + filepath := filepath.Join(c.PDFDir, filename) - if err = b.WriteFile(absFilepath, file); err != nil { + if err = b.WriteFile(filepath, file); err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) return diff --git a/cmd/frontend/sessions.go b/cmd/frontend/sessions.go index 4b1dcc8..2a4b59d 100644 --- a/cmd/frontend/sessions.go +++ b/cmd/frontend/sessions.go @@ -7,6 +7,7 @@ import ( "html/template" "log" "net/http" + "path/filepath" "time" "github.com/google/uuid" @@ -67,7 +68,7 @@ func StartSessions() (map[string]*Session, chan string) { // their session and an error. It also handles cases where the user is not // logged in. func ManageSession(w http.ResponseWriter, r *http.Request, c *b.Config, s map[string]*Session) (*Session, error) { - tmpl, tmplErr := template.ParseFiles(c.WebDir+"/templates/index.html", c.WebDir+"/templates/login.html") + tmpl, tmplErr := template.ParseFiles(filepath.Join(c.WebDir, "templates", "index.html"), filepath.Join(c.WebDir, "templates", "login.html")) cookie, err := r.Cookie("cpolis_session") if err != nil { @@ -124,7 +125,7 @@ func Login(c *b.Config, db *b.DB, s map[string]*Session, sessionExpiryChan chan s[session.cookie.Value] = session http.SetCookie(w, session.cookie) - tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html") + tmpl, err := template.ParseFiles(filepath.Join(c.WebDir, "templates", "hub.html")) if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", user); err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) @@ -135,7 +136,7 @@ func Login(c *b.Config, db *b.DB, s map[string]*Session, sessionExpiryChan chan func Logout(c *b.Config, s map[string]*Session) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - tmpl, tmplErr := template.ParseFiles(c.WebDir + "/templates/login.html") + tmpl, tmplErr := template.ParseFiles(filepath.Join(c.WebDir, "templates", "login.html")) cookie, err := r.Cookie("cpolis_session") if err != nil { diff --git a/cmd/frontend/tags.go b/cmd/frontend/tags.go index aa2762a..1cdee8c 100644 --- a/cmd/frontend/tags.go +++ b/cmd/frontend/tags.go @@ -4,6 +4,7 @@ import ( "html/template" "log" "net/http" + "path/filepath" b "streifling.com/jason/cpolis/cmd/backend" ) @@ -15,7 +16,7 @@ func CreateTag(c *b.Config, s map[string]*Session) http.HandlerFunc { return } - tmpl, err := template.ParseFiles(c.WebDir + "/templates/add-tag.html") + tmpl, err := template.ParseFiles(filepath.Join(c.WebDir, "templates", "add-tag.html")) if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", nil); err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) @@ -42,7 +43,7 @@ func AddTag(c *b.Config, db *b.DB, s map[string]*Session) http.HandlerFunc { data := new(struct{ Role int }) data.Role = session.User.Role - tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html") + tmpl, err := template.ParseFiles(filepath.Join(c.WebDir, "templates", "hub.html")) tmpl = template.Must(tmpl, err) if err = tmpl.ExecuteTemplate(w, "page-content", data); err != nil { log.Println(err) diff --git a/cmd/frontend/users.go b/cmd/frontend/users.go index 12a1faf..158e57f 100644 --- a/cmd/frontend/users.go +++ b/cmd/frontend/users.go @@ -5,6 +5,7 @@ import ( "html/template" "log" "net/http" + "path/filepath" "sort" "strconv" @@ -57,7 +58,7 @@ func CreateUser(c *b.Config, s map[string]*Session) http.HandlerFunc { URL: "/user/add", } - tmpl, err := template.ParseFiles(c.WebDir + "/templates/edit-user.html") + tmpl, err := template.ParseFiles(filepath.Join(c.WebDir, "templates", "edit-user.html")) if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", data); err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) @@ -134,7 +135,7 @@ func AddUser(c *b.Config, db *b.DB, s map[string]*Session) http.HandlerFunc { data := new(struct{ Role int }) data.Role = session.User.Role - tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html") + tmpl, err := template.ParseFiles(filepath.Join(c.WebDir, "templates", "hub.html")) tmpl = template.Must(tmpl, err) if err = tmpl.ExecuteTemplate(w, "page-content", data); err != nil { log.Println(err) @@ -167,7 +168,7 @@ func EditSelf(c *b.Config, db *b.DB, s map[string]*Session) http.HandlerFunc { Image: user.ProfilePicLink, } - tmpl, err := template.ParseFiles(c.WebDir + "/templates/edit-user.html") + tmpl, err := template.ParseFiles(filepath.Join(c.WebDir, "templates", "edit-user.html")) if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", data); err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) @@ -242,7 +243,7 @@ func UpdateSelf(c *b.Config, db *b.DB, s map[string]*Session) http.HandlerFunc { data := new(struct{ Role int }) data.Role = session.User.Role - tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html") + tmpl, err := template.ParseFiles(filepath.Join(c.WebDir, "templates", "hub.html")) tmpl = template.Must(tmpl, err) if err = tmpl.ExecuteTemplate(w, "page-content", data); err != nil { log.Println(err) @@ -312,7 +313,7 @@ func AddFirstUser(c *b.Config, db *b.DB, s map[string]*Session, sessionExpiryCha data := new(struct{ Role int }) data.Role = user.Role - tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html") + tmpl, err := template.ParseFiles(filepath.Join(c.WebDir, "templates", "hub.html")) if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", data); err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) @@ -343,7 +344,7 @@ func ShowAllUsers(c *b.Config, db *b.DB, s map[string]*Session, action string) h } delete(data.Users, session.User.ID) - tmpl, err := template.ParseFiles(c.WebDir + "/templates/show-all-users.html") + tmpl, err := template.ParseFiles(filepath.Join(c.WebDir, "templates", "show-all-users.html")) if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", data); err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) @@ -381,7 +382,7 @@ func EditUser(c *b.Config, db *b.DB, s map[string]*Session) http.HandlerFunc { Image: user.ProfilePicLink, } - tmpl, err := template.ParseFiles(c.WebDir + "/templates/edit-user.html") + tmpl, err := template.ParseFiles(filepath.Join(c.WebDir, "templates", "edit-user.html")) if err = template.Must(tmpl, err).ExecuteTemplate(w, "page-content", data); err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) @@ -466,7 +467,7 @@ func UpdateUser(c *b.Config, db *b.DB, s map[string]*Session) http.HandlerFunc { data := new(struct{ Role int }) data.Role = session.User.Role - tmpl := template.Must(template.ParseFiles(c.WebDir + "/templates/hub.html")) + tmpl := template.Must(template.ParseFiles(filepath.Join(c.WebDir, "templates", "hub.html"))) if err = tmpl.ExecuteTemplate(w, "page-content", data); err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) @@ -499,7 +500,7 @@ func DeleteUser(c *b.Config, db *b.DB, s map[string]*Session) http.HandlerFunc { data := new(struct{ Role int }) data.Role = session.User.Role - tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html") + tmpl, err := template.ParseFiles(filepath.Join(c.WebDir, "templates", "hub.html")) tmpl = template.Must(tmpl, err) if err = tmpl.ExecuteTemplate(w, "page-content", data); err != nil { log.Println(err) diff --git a/cmd/main.go b/cmd/main.go index 1ce834f..bb07bca 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -4,6 +4,7 @@ import ( "log" "net/http" "os" + "time" b "streifling.com/jason/cpolis/cmd/backend" c "streifling.com/jason/cpolis/cmd/calls" @@ -32,7 +33,14 @@ func main() { sessions, sessionExpiryChan := f.StartSessions() defer close(sessionExpiryChan) - // go b.CleanUpImages(config) + go func(c *b.Config, db *b.DB) { + for { + if err = b.CleanUpImages(c, db); err != nil { + log.Println(err) + } + time.Sleep(time.Hour * 24) + } + }(config, db) mux := http.NewServeMux() mux.Handle("/web/static/", http.StripPrefix("/web/static/", @@ -52,8 +60,8 @@ func main() { mux.HandleFunc("GET /article/review-edit/{id}", f.ReviewArticle(config, db, sessions, "allow-edit", "Artikel bearbeiten", "Bearbeiten erlauben")) mux.HandleFunc("GET /article/review-rejected/{id}", f.ReviewRejectedArticle(config, db, sessions)) mux.HandleFunc("GET /article/review-unpublished/{id}", f.ReviewArticle(config, db, sessions, "publish", "Artikel veröffentlichen", "Veröffentlichen")) - mux.HandleFunc("GET /article/serve/{id}", c.ServeArticle(config, db)) - mux.HandleFunc("GET /article/serve/{id}/clicks", c.ServeClicks(db)) + mux.HandleFunc("GET /article/serve/{uuid}", c.ServeArticle(config, db)) + mux.HandleFunc("GET /article/serve/{uuid}/clicks", c.ServeClicks(db)) mux.HandleFunc("GET /article/write", f.WriteArticle(config, db, sessions)) mux.HandleFunc("GET /atom/serve", c.ServeAtomFeed(config)) mux.HandleFunc("GET /hub", f.ShowHub(config, db, sessions))