Compare commits

..

57 Commits

Author SHA1 Message Date
548d2c6023 Incorporated issues 2024-03-28 07:00:37 +01:00
509e1d41db Corrected copyright 2024-03-28 06:59:39 +01:00
63d5fbd127 Disabled option to do transaction from view 2024-03-28 06:58:59 +01:00
f5c1a5e8d0 Added copyright 2024-03-17 15:29:12 +01:00
40d1104a66 Set pubDate to published time and date 2024-03-17 09:41:09 +01:00
736673c33f Now everyone only sees their own rejected articles 2024-03-17 09:15:37 +01:00
1a2e18359c Added ability to view tags when rejecting and change tags when reworking articles 2024-03-17 08:46:49 +01:00
d1d3a81565 Implemented retry logic on all transactions 2024-03-15 18:37:24 +01:00
bc2302d31f Implement retry logic for UpdateAttributes 2024-03-15 15:18:02 +01:00
1b02e3fad2 Added logout 2024-03-12 20:27:39 +01:00
dc06a6e9aa Fixed dumb routing mistake 2024-03-12 19:56:22 +01:00
63370ada01 Added ability to edit user info 2024-03-11 21:08:27 +01:00
5145e1cd94 Added ability to reject and rework article 2024-03-10 15:03:46 +01:00
28eb7e236a Split up db.go into multiple files 2024-03-09 11:06:03 +01:00
4a7883f886 Also missed rss.go 2024-03-09 10:27:55 +01:00
b69a0688ef Missed main when converting to MVC 2024-03-09 10:27:04 +01:00
0e18c7a7db Changed everything to MVC 2024-03-09 10:25:20 +01:00
3ab9a8fe10 Converted RSS feed to be DB based 2024-03-09 10:12:46 +01:00
6dfd49a5cd Reachieve basic functionality 2024-03-07 20:11:28 +01:00
5455bdb12b Articles and tags are now inserted into DB correctly 2024-03-07 15:31:00 +01:00
9eaafdc712 Converted articles and tags to DB base 2024-03-06 20:53:17 +01:00
d127be4c93 Handle rollbackError with log.Fatalf() 2024-03-06 16:58:41 +01:00
34832e397f Corrected transaction for ChangePassword() 2024-03-06 16:51:08 +01:00
2c0b4878f4 Use transaction when necessary 2024-03-06 15:37:59 +01:00
f0e078c011 Load *ArticleList, *Taglist and *Channel correctly 2024-03-06 15:37:42 +01:00
a8fc28af36 Moved main.go into cmd 2024-03-05 18:26:50 +01:00
e4f085f762 Added Tags to RSS feed as categories 2024-03-05 18:20:34 +01:00
6136f83dfc Converted RSS package to git.streifling.com/jason/rss 2024-03-05 17:13:59 +01:00
21170c9cc2 A bit of cleaning up 2024-03-05 16:38:18 +01:00
6502aa7ec1 Added partial support for tags 2024-03-03 13:56:49 +01:00
e5bdc235b6 Initial sessions implementation 2024-03-03 09:16:49 +01:00
655992c8b2 Just a bit of cleaning up 2024-03-02 09:09:55 +01:00
aa7fcd6075 Created func for minimum spec for rss and article structs, thereby crushing an annoying bug that was caused by not initializing channels but waiting for messages to go through them 2024-03-02 00:28:42 +01:00
f9cc90a948 Changed articles and rss to channels 2024-03-01 21:01:38 +01:00
7f2433c30b Implemented proper User struct 2024-03-01 12:25:53 +01:00
f34efc95dd Added ability to publish articles 2024-03-01 11:30:31 +01:00
935d0a1ca4 Added article list for written but non-published articles 2024-02-27 14:10:27 +01:00
48d4d482b2 Convert title and description to plain text 2024-02-27 09:03:21 +01:00
8dae3ca21e Implemented hub 2024-02-24 15:31:33 +01:00
6f02852212 Add ability to display feed 2024-02-24 14:49:29 +01:00
4cc2110c4b Added messages and field memory for adding user 2024-02-24 13:25:32 +01:00
04cbee097c Require all fields to be filled out when creating a new user 2024-02-24 12:10:34 +01:00
93423ae606 Implemented logging to file 2024-02-24 11:41:01 +01:00
41113b24a8 Check if user already exists and bug fix 2024-02-24 10:56:12 +01:00
2247f316a3 Added ability to add user 2024-02-24 10:28:12 +01:00
9beedf9b2b Added ability to login 2024-02-24 09:54:25 +01:00
7d6f96a185 Check user credentials before adding user 2024-02-22 20:12:09 +01:00
8d47146a7c Added ability to update Passwords 2024-02-22 19:27:41 +01:00
4853184ba1 Added ability to add user 2024-02-22 18:49:51 +01:00
50895249df Changed error messages 2024-02-22 15:23:29 +01:00
6e91253908 Added HTML sanitizer 2024-02-22 15:22:45 +01:00
9bb6010319 Added initial support for MySQL databases 2024-02-18 16:37:13 +01:00
75a0af055c Handle misssed errors for encoding and decoding feeds 2024-02-18 14:31:28 +01:00
171a0dd250 Added description and a way to save and restore the RSS feed. 2024-02-18 14:01:06 +01:00
372882a252 Create RSS from HTML 2024-02-18 12:41:49 +01:00
2d0b53a254 Show HTML on website 2024-02-18 10:48:37 +01:00
2447f50bac First implementation of web based editor to HTML pipeline 2024-02-18 10:07:49 +01:00
23 changed files with 170 additions and 544 deletions

View File

@ -1,58 +0,0 @@
package control
import (
"flag"
"fmt"
"path/filepath"
)
type CliArgs struct {
DBName string
KeyFile string
LogFile string
Port string
PicsDir string
RSSFile string
WebDir string
}
func HandleCliArgs() (*CliArgs, error) {
var err error
cliArgs := new(CliArgs)
keyFile := flag.String("key", "/var/www/cpolis/cpolis.key", "key file")
logFile := flag.String("log", "/var/log/cpolis.log", "log file")
picsDir := flag.String("pics", "/var/www/cpolis/pics", "pictures directory")
cliArgs.Port = fmt.Sprint(":", flag.Int("port", 8080, "port"))
rssFile := flag.String("rss", "/var/www/cpolis/cpolis.rss", "RSS file")
webDir := flag.String("web", "/var/www/cpolis/web", "web directory")
flag.StringVar(&cliArgs.DBName, "db", "cpolis", "DB name")
flag.Parse()
cliArgs.KeyFile, err = filepath.Abs(*keyFile)
if err != nil {
return nil, fmt.Errorf("error finding absolute path for KeyFile: %v", err)
}
cliArgs.LogFile, err = filepath.Abs(*logFile)
if err != nil {
return nil, fmt.Errorf("error finding absolute path for LogFile: %v", err)
}
cliArgs.PicsDir, err = filepath.Abs(*picsDir)
if err != nil {
return nil, fmt.Errorf("error finding absolute path for PicsDir: %v", err)
}
cliArgs.RSSFile, err = filepath.Abs(*rssFile)
if err != nil {
return nil, fmt.Errorf("error finding absolute path for RSSFile: %v", err)
}
cliArgs.WebDir, err = filepath.Abs(*webDir)
if err != nil {
return nil, fmt.Errorf("error finding absolute path for WebDir: %v", err)
}
return cliArgs, nil
}

View File

@ -2,8 +2,6 @@ package control
import ( import (
"fmt" "fmt"
"io"
"os"
"time" "time"
"git.streifling.com/jason/rss" "git.streifling.com/jason/rss"
@ -50,82 +48,3 @@ func GetChannel(db *model.DB, title, link, description string) (*rss.Channel, er
return channel, nil return channel, nil
} }
func GenerateRSS(db *model.DB, title, link, desc string) (*string, error) {
channel := &rss.Channel{
Title: title,
Link: link,
Description: desc,
Items: make([]*rss.Item, 0),
}
articles, err := db.GetCertainArticles(true, false)
if err != nil {
return nil, fmt.Errorf("error getting published articles for RSS feed: %v", err)
}
for _, article := range articles {
tags, err := db.GetArticleTags(article.ID)
if err != nil {
return nil, fmt.Errorf("error getting tags for articles for RSS feed: %v", err)
}
tagNames := make([]string, 0)
for _, tag := range tags {
tagNames = append(tagNames, tag.Name)
}
tagNames = append(tagNames, fmt.Sprint("Orient Express ", article.IssueID))
user, err := db.GetUser(article.AuthorID)
if err != nil {
return nil, fmt.Errorf("error getting user user info for RSS feed: %v", err)
}
articleTitle, err := ConvertToPlain(article.Title)
if err != nil {
return nil, fmt.Errorf("error converting title to plain text for RSS feed: %v", err)
}
articleDescription, err := ConvertToPlain(article.Description)
if err != nil {
return nil, fmt.Errorf("error converting description to plain text for RSS feed: %v", err)
}
articleContent, err := ConvertToHTML(article.Content)
if err != nil {
return nil, fmt.Errorf("error converting content to HTML for RSS feed: %v", err)
}
channel.Items = append(channel.Items, &rss.Item{
Title: articleTitle,
Author: user.FirstName + user.LastName,
PubDate: article.Created.Format(time.RFC1123Z),
Description: articleDescription,
Content: &rss.Content{Value: articleContent},
Categories: tagNames,
})
}
feed := rss.NewFeed()
feed.Channels = append(feed.Channels, channel)
rss, err := feed.ToXML()
if err != nil {
return nil, fmt.Errorf("error converting RSS feed to XML: %v", err)
}
return &rss, nil
}
func SaveRSS(filename string, feed *string) error {
file, err := os.Create(filename)
if err != nil {
return fmt.Errorf("error creating file for RSS feed: %v", err)
}
defer file.Close()
file.Chmod(0644)
if _, err = io.WriteString(file, *feed); err != nil {
return fmt.Errorf("error writing to RSS file: %v", err)
}
return nil
}

View File

@ -16,67 +16,62 @@ func init() {
} }
func main() { func main() {
args, err := control.HandleCliArgs() logFile, err := os.OpenFile("tmp/cpolis.log",
if err != nil { os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
log.Fatalln(err)
}
logFile, err := os.OpenFile(args.LogFile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
if err != nil { if err != nil {
log.Fatalln(err) log.Fatalln(err)
} }
defer logFile.Close() defer logFile.Close()
log.SetOutput(logFile) // log.SetOutput(logFile)
db, err := model.OpenDB(args.DBName) db, err := model.OpenDB("cpolis")
if err != nil { if err != nil {
log.Fatalln(err) log.Fatalln(err)
} }
defer db.Close() defer db.Close()
key, err := control.LoadKey(args.KeyFile) key, err := control.LoadKey("tmp/key.gob")
if err != nil { if err != nil {
key, err = control.NewKey() key, err = control.NewKey()
if err != nil { if err != nil {
log.Fatalln(err) log.Fatalln(err)
} }
control.SaveKey(key, args.KeyFile) control.SaveKey(key, "tmp/key.gob")
} }
store := control.NewCookieStore(key) store := control.NewCookieStore(key)
mux := http.NewServeMux() mux := http.NewServeMux()
mux.Handle("/web/static/", http.StripPrefix("/web/static/", mux.Handle("/web/static/", http.StripPrefix("/web/static/",
http.FileServer(http.Dir(args.WebDir+"/static/")))) http.FileServer(http.Dir("web/static/"))))
mux.HandleFunc("/", view.HomePage(args, db, store)) mux.HandleFunc("/", view.HomePage(db, store))
mux.HandleFunc("GET /create-tag/", view.CreateTag(args)) mux.HandleFunc("GET /create-tag/", view.CreateTag)
mux.HandleFunc("GET /create-user/", view.CreateUser(args)) mux.HandleFunc("GET /create-user/", view.CreateUser)
mux.HandleFunc("GET /edit-user/", view.EditUser(args, db, store)) mux.HandleFunc("GET /edit-user/", view.EditUser(db, store))
mux.HandleFunc("GET /hub/", view.ShowHub(args, db, store)) mux.HandleFunc("GET /hub/", view.ShowHub(db, store))
mux.HandleFunc("GET /logout/", view.Logout(args, store)) mux.HandleFunc("GET /logout/", view.Logout(store))
mux.HandleFunc("GET /publish-issue/", view.PublishLatestIssue(args, db, store)) mux.HandleFunc("GET /publish-issue/", view.PublishLatestIssue(db))
mux.HandleFunc("GET /rejected-articles/", view.ShowRejectedArticles(args, db, store)) mux.HandleFunc("GET /rejected-articles/", view.ShowRejectedArticles(db, store))
mux.HandleFunc("GET /rss/", view.ShowRSS(args, mux.HandleFunc("GET /rss/", view.ShowRSS(
db, db,
"Freimaurer Distrikt Niedersachsen und Sachsen-Anhalt", "Freimaurer Distrikt Niedersachsen und Sachsen-Anhalt",
"https://distrikt-ni-st.de", "https://distrikt-ni-st.de",
"Freiheit, Gleichheit, Brüderlichkeit, Toleranz und Humanität", "Freiheit, Gleichheit, Brüderlichkeit, Toleranz und Humanität",
)) ))
mux.HandleFunc("GET /this-issue/", view.ShowCurrentArticles(args, db)) mux.HandleFunc("GET /this-issue/", view.ShowCurrentArticles(db))
mux.HandleFunc("GET /unpublished-articles/", view.ShowUnpublishedArticles(args, db)) mux.HandleFunc("GET /unpublished-articles/", view.ShowUnpublishedArticles(db))
mux.HandleFunc("GET /write-article/", view.WriteArticle(args, db)) mux.HandleFunc("GET /write-article/", view.WriteArticle(db))
mux.HandleFunc("POST /add-tag/", view.AddTag(args, db, store)) mux.HandleFunc("POST /add-tag/", view.AddTag(db, store))
mux.HandleFunc("POST /add-user/", view.AddUser(args, db, store)) mux.HandleFunc("POST /add-user/", view.AddUser(db, store))
mux.HandleFunc("POST /login/", view.Login(args, db, store)) mux.HandleFunc("POST /login/", view.Login(db, store))
mux.HandleFunc("POST /publish-article/", view.PublishArticle(args, db, store)) mux.HandleFunc("POST /publish-article/", view.PublishArticle(db, store))
mux.HandleFunc("POST /reject-article/", view.RejectArticle(args, db, store)) mux.HandleFunc("POST /reject-article/", view.RejectArticle(db, store))
mux.HandleFunc("POST /resubmit-article/", view.ResubmitArticle(args, db, store)) mux.HandleFunc("POST /resubmit-article/", view.ResubmitArticle(db, store))
mux.HandleFunc("POST /review-rejected-article/", view.ReviewRejectedArticle(args, db, store)) mux.HandleFunc("POST /review-rejected-article/", view.ReviewRejectedArticle(db, store))
mux.HandleFunc("POST /review-unpublished-article/", view.ReviewUnpublishedArticle(args, db, store)) mux.HandleFunc("POST /review-unpublished-article/", view.ReviewUnpublishedArticle(db, store))
mux.HandleFunc("POST /submit-article/", view.SubmitArticle(args, db, store)) mux.HandleFunc("POST /submit-article/", view.SubmitArticle(db, store))
mux.HandleFunc("POST /update-user/", view.UpdateUser(args, db, store)) mux.HandleFunc("POST /update-user/", view.UpdateUser(db, store))
mux.HandleFunc("POST /upload-image/", view.UploadImage(args))
log.Fatalln(http.ListenAndServe(args.Port, mux)) log.Fatalln(http.ListenAndServe(":8080", mux))
} }

View File

@ -105,7 +105,7 @@ func (db *DB) GetArticle(id int64) (*Article, error) {
func (db *DB) GetCertainArticles(published, rejected bool) ([]*Article, error) { func (db *DB) GetCertainArticles(published, rejected bool) ([]*Article, error) {
query := ` query := `
SELECT id, title, created, description, content, author_id, issue_id SELECT id, title, created, description, content, author_id
FROM articles FROM articles
WHERE published = ? WHERE published = ?
AND rejected = ? AND rejected = ?
@ -121,8 +121,7 @@ func (db *DB) GetCertainArticles(published, rejected bool) ([]*Article, error) {
var created []byte var created []byte
if err = rows.Scan(&article.ID, &article.Title, &created, if err = rows.Scan(&article.ID, &article.Title, &created,
&article.Description, &article.Content, &article.AuthorID, &article.Description, &article.Content, &article.AuthorID); err != nil {
&article.IssueID); err != nil {
return nil, fmt.Errorf("error scanning article row: %v", err) return nil, fmt.Errorf("error scanning article row: %v", err)
} }

View File

@ -6,7 +6,10 @@ import (
) )
func (db *DB) WriteArticleTags(articleID int64, tagIDs []int64) error { func (db *DB) WriteArticleTags(articleID int64, tagIDs []int64) error {
query := "INSERT INTO articles_tags (article_id, tag_id) VALUES (?, ?)" query := `
INSERT INTO articles_tags (article_id, tag_id)
VALUES (?, ?)
`
for i := 0; i < TxMaxRetries; i++ { for i := 0; i < TxMaxRetries; i++ {
err := func() error { err := func() error {
@ -65,8 +68,8 @@ func (db *DB) GetArticleTags(articleID int64) ([]*Tag, error) {
} }
func (db *DB) UpdateArticleTags(articleID int64, tagIDs []int64) error { func (db *DB) UpdateArticleTags(articleID int64, tagIDs []int64) error {
deleteQuery := "DELETE FROM articles_tags WHERE article_id = ?" query := `
insertQuery := "INSERT INTO articles_tags (article_id, tag_id) VALUES (?, ?)" `
for i := 0; i < TxMaxRetries; i++ { for i := 0; i < TxMaxRetries; i++ {
err := func() error { err := func() error {
@ -75,22 +78,6 @@ func (db *DB) UpdateArticleTags(articleID int64, tagIDs []int64) error {
return fmt.Errorf("error starting transaction: %v", err) return fmt.Errorf("error starting transaction: %v", err)
} }
if _, err := tx.Exec(deleteQuery, articleID); err != nil {
if rollbackErr := tx.Rollback(); rollbackErr != nil {
log.Fatalf("transaction error: %v, rollback error: %v", err, rollbackErr)
}
return fmt.Errorf("error deleting entries from articles_tags before inserting new ones: %v", err)
}
for _, tagID := range tagIDs {
if _, err := tx.Exec(insertQuery, articleID, tagID); err != nil {
if rollbackErr := tx.Rollback(); rollbackErr != nil {
log.Fatalf("transaction error: %v, rollback error: %v", err, rollbackErr)
}
return fmt.Errorf("error inserting new entries into articles_tags: %v", err)
}
}
if err = tx.Commit(); err != nil { if err = tx.Commit(); err != nil {
return fmt.Errorf("error committing transaction: %v", err) return fmt.Errorf("error committing transaction: %v", err)
} }

View File

@ -23,6 +23,7 @@ func (db *DB) AddIssue() (int64, error) {
} }
func (db *DB) PublishLatestIssue() error { func (db *DB) PublishLatestIssue() error {
var id int64
txOptions := &sql.TxOptions{Isolation: sql.LevelSerializable} txOptions := &sql.TxOptions{Isolation: sql.LevelSerializable}
updateQuery := "UPDATE issues SET published = true WHERE published = false" updateQuery := "UPDATE issues SET published = true WHERE published = false"
insertQuery := "INSERT INTO issues (published) VALUES (?)" insertQuery := "INSERT INTO issues (published) VALUES (?)"
@ -34,7 +35,7 @@ func (db *DB) PublishLatestIssue() error {
return fmt.Errorf("error starting transaction: %v", err) return fmt.Errorf("error starting transaction: %v", err)
} }
if _, err := tx.Exec(updateQuery); err != nil { if _, err := tx.Exec(updateQuery, id); err != nil {
if rollbackErr := tx.Rollback(); rollbackErr != nil { if rollbackErr := tx.Rollback(); rollbackErr != nil {
log.Fatalf("transaction error: %v, rollback error: %v", err, rollbackErr) log.Fatalf("transaction error: %v, rollback error: %v", err, rollbackErr)
} }

View File

@ -1,12 +1,9 @@
package view package view
import ( import (
"fmt"
"html/template" "html/template"
"io"
"log" "log"
"net/http" "net/http"
"os"
"strconv" "strconv"
"time" "time"
@ -14,21 +11,21 @@ import (
"streifling.com/jason/cpolis/cmd/model" "streifling.com/jason/cpolis/cmd/model"
) )
func ShowHub(c *control.CliArgs, db *model.DB, s *control.CookieStore) http.HandlerFunc { func ShowHub(db *model.DB, s *control.CookieStore) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
session, err := s.Get(r, "cookie") session, err := s.Get(r, "cookie")
if err != nil { if err != nil {
tmpl, err := template.ParseFiles(c.WebDir + "/templates/login.html") tmpl, err := template.ParseFiles("web/templates/login.html")
msg := "Session nicht mehr gültig. Bitte erneut anmelden." msg := "Session nicht mehr gültig. Bitte erneut anmelden."
template.Must(tmpl, err).ExecuteTemplate(w, "page-content", msg) template.Must(tmpl, err).ExecuteTemplate(w, "page-content", msg)
} }
tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html") tmpl, err := template.ParseFiles("web/templates/hub.html")
template.Must(tmpl, err).ExecuteTemplate(w, "page-content", session.Values["role"].(int)) template.Must(tmpl, err).ExecuteTemplate(w, "page-content", session.Values["role"].(int))
} }
} }
func WriteArticle(c *control.CliArgs, db *model.DB) http.HandlerFunc { func WriteArticle(db *model.DB) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
tags, err := db.GetTagList() tags, err := db.GetTagList()
if err != nil { if err != nil {
@ -37,16 +34,16 @@ func WriteArticle(c *control.CliArgs, db *model.DB) http.HandlerFunc {
return return
} }
tmpl, err := template.ParseFiles(c.WebDir + "/templates/editor.html") tmpl, err := template.ParseFiles("web/templates/editor.html")
template.Must(tmpl, err).ExecuteTemplate(w, "page-content", tags) template.Must(tmpl, err).ExecuteTemplate(w, "page-content", tags)
} }
} }
func SubmitArticle(c *control.CliArgs, db *model.DB, s *control.CookieStore) http.HandlerFunc { func SubmitArticle(db *model.DB, s *control.CookieStore) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
session, err := s.Get(r, "cookie") session, err := s.Get(r, "cookie")
if err != nil { if err != nil {
tmpl, err := template.ParseFiles(c.WebDir + "/templates/login.html") tmpl, err := template.ParseFiles("web/templates/login.html")
msg := "Session nicht mehr gültig. Bitte erneut anmelden." msg := "Session nicht mehr gültig. Bitte erneut anmelden."
template.Must(tmpl, err).ExecuteTemplate(w, "page-content", msg) template.Must(tmpl, err).ExecuteTemplate(w, "page-content", msg)
} }
@ -84,13 +81,13 @@ func SubmitArticle(c *control.CliArgs, db *model.DB, s *control.CookieStore) htt
return return
} }
tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html") tmpl, err := template.ParseFiles("web/templates/hub.html")
tmpl = template.Must(tmpl, err) tmpl = template.Must(tmpl, err)
tmpl.ExecuteTemplate(w, "page-content", session.Values["role"]) tmpl.ExecuteTemplate(w, "page-content", session.Values["role"])
} }
} }
func ResubmitArticle(c *control.CliArgs, db *model.DB, s *control.CookieStore) http.HandlerFunc { func ResubmitArticle(db *model.DB, s *control.CookieStore) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
id, err := strconv.ParseInt(r.PostFormValue("article-id"), 10, 64) id, err := strconv.ParseInt(r.PostFormValue("article-id"), 10, 64)
if err != nil { if err != nil {
@ -103,7 +100,7 @@ func ResubmitArticle(c *control.CliArgs, db *model.DB, s *control.CookieStore) h
description := r.PostFormValue("article-description") description := r.PostFormValue("article-description")
content := r.PostFormValue("article-content") content := r.PostFormValue("article-content")
if err = db.UpdateAttributes( if err := db.UpdateAttributes(
&model.Attribute{Table: "articles", ID: id, AttName: "title", Value: title}, &model.Attribute{Table: "articles", ID: id, AttName: "title", Value: title},
&model.Attribute{Table: "articles", ID: id, AttName: "description", Value: description}, &model.Attribute{Table: "articles", ID: id, AttName: "description", Value: description},
&model.Attribute{Table: "articles", ID: id, AttName: "content", Value: content}, &model.Attribute{Table: "articles", ID: id, AttName: "content", Value: content},
@ -114,37 +111,20 @@ func ResubmitArticle(c *control.CliArgs, db *model.DB, s *control.CookieStore) h
return 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.UpdateArticleTags(id, tags); err != nil {
log.Println(err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
session, err := s.Get(r, "cookie") session, err := s.Get(r, "cookie")
if err != nil { if err != nil {
tmpl, err := template.ParseFiles(c.WebDir + "/templates/login.html") tmpl, err := template.ParseFiles("web/templates/login.html")
msg := "Session nicht mehr gültig. Bitte erneut anmelden." msg := "Session nicht mehr gültig. Bitte erneut anmelden."
template.Must(tmpl, err).ExecuteTemplate(w, "page-content", msg) template.Must(tmpl, err).ExecuteTemplate(w, "page-content", msg)
} }
tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html") tmpl, err := template.ParseFiles("web/templates/hub.html")
tmpl = template.Must(tmpl, err) tmpl = template.Must(tmpl, err)
tmpl.ExecuteTemplate(w, "page-content", session.Values["role"]) tmpl.ExecuteTemplate(w, "page-content", session.Values["role"])
} }
} }
func ShowUnpublishedArticles(c *control.CliArgs, db *model.DB) http.HandlerFunc { func ShowUnpublishedArticles(db *model.DB) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
unpublishedArticles, err := db.GetCertainArticles(false, false) unpublishedArticles, err := db.GetCertainArticles(false, false)
if err != nil { if err != nil {
@ -153,13 +133,13 @@ func ShowUnpublishedArticles(c *control.CliArgs, db *model.DB) http.HandlerFunc
return return
} }
tmpl, err := template.ParseFiles(c.WebDir + "/templates/unpublished-articles.html") tmpl, err := template.ParseFiles("web/templates/unpublished-articles.html")
tmpl = template.Must(tmpl, err) tmpl = template.Must(tmpl, err)
tmpl.ExecuteTemplate(w, "page-content", unpublishedArticles) tmpl.ExecuteTemplate(w, "page-content", unpublishedArticles)
} }
} }
func ShowRejectedArticles(c *control.CliArgs, db *model.DB, s *control.CookieStore) http.HandlerFunc { func ShowRejectedArticles(db *model.DB, s *control.CookieStore) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
type htmlData struct { type htmlData struct {
MyIDs map[int64]bool MyIDs map[int64]bool
@ -188,13 +168,13 @@ func ShowRejectedArticles(c *control.CliArgs, db *model.DB, s *control.CookieSto
} }
} }
tmpl, err := template.ParseFiles(c.WebDir + "/templates/rejected-articles.html") tmpl, err := template.ParseFiles("web/templates/rejected-articles.html")
tmpl = template.Must(tmpl, err) tmpl = template.Must(tmpl, err)
tmpl.ExecuteTemplate(w, "page-content", data) tmpl.ExecuteTemplate(w, "page-content", data)
} }
} }
func ReviewUnpublishedArticle(c *control.CliArgs, db *model.DB, s *control.CookieStore) http.HandlerFunc { func ReviewUnpublishedArticle(db *model.DB, s *control.CookieStore) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
type htmlData struct { type htmlData struct {
Article *model.Article Article *model.Article
@ -223,13 +203,13 @@ func ReviewUnpublishedArticle(c *control.CliArgs, db *model.DB, s *control.Cooki
return return
} }
tmpl, err := template.ParseFiles(c.WebDir + "/templates/to-be-published.html") tmpl, err := template.ParseFiles("web/templates/to-be-published.html")
tmpl = template.Must(tmpl, err) tmpl = template.Must(tmpl, err)
tmpl.ExecuteTemplate(w, "page-content", data) tmpl.ExecuteTemplate(w, "page-content", data)
} }
} }
func ReviewRejectedArticle(c *control.CliArgs, db *model.DB, s *control.CookieStore) http.HandlerFunc { func ReviewRejectedArticle(db *model.DB, s *control.CookieStore) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
type htmlData struct { type htmlData struct {
Selected map[int64]bool Selected map[int64]bool
@ -270,13 +250,13 @@ func ReviewRejectedArticle(c *control.CliArgs, db *model.DB, s *control.CookieSt
data.Selected[tag.ID] = true data.Selected[tag.ID] = true
} }
tmpl, err := template.ParseFiles(c.WebDir + "/templates/rework-article.html") tmpl, err := template.ParseFiles("web/templates/rework-article.html")
tmpl = template.Must(tmpl, err) tmpl = template.Must(tmpl, err)
tmpl.ExecuteTemplate(w, "page-content", data) tmpl.ExecuteTemplate(w, "page-content", data)
} }
} }
func PublishArticle(c *control.CliArgs, db *model.DB, s *control.CookieStore) http.HandlerFunc { func PublishArticle(db *model.DB, s *control.CookieStore) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
id, err := strconv.ParseInt(r.PostFormValue("id"), 10, 64) id, err := strconv.ParseInt(r.PostFormValue("id"), 10, 64)
if err != nil { if err != nil {
@ -287,7 +267,7 @@ func PublishArticle(c *control.CliArgs, db *model.DB, s *control.CookieStore) ht
session, err := s.Get(r, "cookie") session, err := s.Get(r, "cookie")
if err != nil { if err != nil {
tmpl, err := template.ParseFiles(c.WebDir + "/templates/login.html") tmpl, err := template.ParseFiles("web/templates/login.html")
msg := "Session nicht mehr gültig. Bitte erneut anmelden." msg := "Session nicht mehr gültig. Bitte erneut anmelden."
template.Must(tmpl, err).ExecuteTemplate(w, "page-content", msg) template.Must(tmpl, err).ExecuteTemplate(w, "page-content", msg)
} }
@ -308,30 +288,13 @@ func PublishArticle(c *control.CliArgs, db *model.DB, s *control.CookieStore) ht
return return
} }
feed, err := control.GenerateRSS( tmpl, err := template.ParseFiles("web/templates/hub.html")
db,
"Freimaurer Distrikt Niedersachsen und Sachsen-Anhalt",
"https://distrikt-ni-st.de",
"Freiheit, Gleichheit, Brüderlichkeit, Toleranz und Humanität",
)
if err != nil {
log.Println(err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
if err = control.SaveRSS(c.RSSFile, feed); 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 = template.Must(tmpl, err)
tmpl.ExecuteTemplate(w, "page-content", session.Values["role"]) tmpl.ExecuteTemplate(w, "page-content", session.Values["role"])
} }
} }
func RejectArticle(c *control.CliArgs, db *model.DB, s *control.CookieStore) http.HandlerFunc { func RejectArticle(db *model.DB, s *control.CookieStore) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
id, err := strconv.ParseInt(r.PostFormValue("id"), 10, 64) id, err := strconv.ParseInt(r.PostFormValue("id"), 10, 64)
if err != nil { if err != nil {
@ -342,7 +305,7 @@ func RejectArticle(c *control.CliArgs, db *model.DB, s *control.CookieStore) htt
session, err := s.Get(r, "cookie") session, err := s.Get(r, "cookie")
if err != nil { if err != nil {
tmpl, err := template.ParseFiles(c.WebDir + "/templates/login.html") tmpl, err := template.ParseFiles("web/templates/login.html")
msg := "Session nicht mehr gültig. Bitte erneut anmelden." msg := "Session nicht mehr gültig. Bitte erneut anmelden."
template.Must(tmpl, err).ExecuteTemplate(w, "page-content", msg) template.Must(tmpl, err).ExecuteTemplate(w, "page-content", msg)
} }
@ -355,13 +318,13 @@ func RejectArticle(c *control.CliArgs, db *model.DB, s *control.CookieStore) htt
return return
} }
tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html") tmpl, err := template.ParseFiles("web/templates/hub.html")
tmpl = template.Must(tmpl, err) tmpl = template.Must(tmpl, err)
tmpl.ExecuteTemplate(w, "page-content", session.Values["role"]) tmpl.ExecuteTemplate(w, "page-content", session.Values["role"])
} }
} }
func ShowCurrentArticles(c *control.CliArgs, db *model.DB) http.HandlerFunc { func ShowCurrentArticles(db *model.DB) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
articles, err := db.GetCurrentIssueArticles() articles, err := db.GetCurrentIssueArticles()
if err != nil { if err != nil {
@ -370,37 +333,20 @@ func ShowCurrentArticles(c *control.CliArgs, db *model.DB) http.HandlerFunc {
return return
} }
tmpl, err := template.ParseFiles(c.WebDir + "/templates/current-articles.html") tmpl, err := template.ParseFiles("web/templates/current-articles.html")
template.Must(tmpl, err).ExecuteTemplate(w, "page-content", articles) template.Must(tmpl, err).ExecuteTemplate(w, "page-content", articles)
} }
} }
func UploadImage(c *control.CliArgs) http.HandlerFunc { func PublishLatestIssue(db *model.DB) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
file, header, err := r.FormFile("article-image") if err := db.PublishLatestIssue(); err != nil {
if err != nil {
log.Println(err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
defer file.Close()
filename := fmt.Sprint(c.PicsDir, time.Now().Format("2006-01-02_15:04:05"), "-", header.Filename)
img, err := os.Create(filename)
if err != nil {
log.Println(err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
defer img.Close()
if _, err = io.Copy(img, file); err != nil {
log.Println(err) log.Println(err)
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
return return
} }
tmpl, err := template.ParseFiles(c.WebDir + "/templates/editor.html") tmpl, err := template.ParseFiles("web/templates/hub.html")
template.Must(tmpl, err).ExecuteTemplate(w, "editor-images", fmt.Sprint("![", header.Filename, "](", filename, ")")) template.Must(tmpl, err).ExecuteTemplate(w, "page-content", nil)
} }
} }

View File

@ -8,25 +8,23 @@ import (
"streifling.com/jason/cpolis/cmd/model" "streifling.com/jason/cpolis/cmd/model"
) )
func CreateTag(c *control.CliArgs) http.HandlerFunc { func CreateTag(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) { tmpl, err := template.ParseFiles("web/templates/add-tag.html")
tmpl, err := template.ParseFiles(c.WebDir + "/templates/add-tag.html")
template.Must(tmpl, err).ExecuteTemplate(w, "page-content", nil) template.Must(tmpl, err).ExecuteTemplate(w, "page-content", nil)
} }
}
func AddTag(c *control.CliArgs, db *model.DB, s *control.CookieStore) http.HandlerFunc { func AddTag(db *model.DB, s *control.CookieStore) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
db.AddTag(r.PostFormValue("tag")) db.AddTag(r.PostFormValue("tag"))
session, err := s.Get(r, "cookie") session, err := s.Get(r, "cookie")
if err != nil { if err != nil {
tmpl, err := template.ParseFiles(c.WebDir + "/templates/login.html") tmpl, err := template.ParseFiles("web/templates/login.html")
msg := "Session nicht mehr gültig. Bitte erneut anmelden." msg := "Session nicht mehr gültig. Bitte erneut anmelden."
template.Must(tmpl, err).ExecuteTemplate(w, "page-content", msg) template.Must(tmpl, err).ExecuteTemplate(w, "page-content", msg)
} }
tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html") tmpl, err := template.ParseFiles("web/templates/hub.html")
tmpl = template.Must(tmpl, err) tmpl = template.Must(tmpl, err)
tmpl.ExecuteTemplate(w, "page-content", session.Values["role"]) tmpl.ExecuteTemplate(w, "page-content", session.Values["role"])
} }

View File

@ -1,31 +0,0 @@
package view
import (
"html/template"
"log"
"net/http"
"streifling.com/jason/cpolis/cmd/control"
"streifling.com/jason/cpolis/cmd/model"
)
func PublishLatestIssue(c *control.CliArgs, db *model.DB, s *control.CookieStore) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if err := db.PublishLatestIssue(); err != nil {
log.Println(err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
session, err := s.Get(r, "cookie")
if err != nil {
tmpl, err := template.ParseFiles(c.WebDir + "/templates/login.html")
msg := "Session nicht mehr gültig. Bitte erneut anmelden."
template.Must(tmpl, err).ExecuteTemplate(w, "page-content", msg)
}
tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html")
tmpl = template.Must(tmpl, err)
tmpl.ExecuteTemplate(w, "page-content", session.Values["role"])
}
}

View File

@ -12,7 +12,7 @@ import (
"streifling.com/jason/cpolis/cmd/model" "streifling.com/jason/cpolis/cmd/model"
) )
func ShowRSS(c *control.CliArgs, db *model.DB, title, link, desc string) http.HandlerFunc { func ShowRSS(db *model.DB, title, link, desc string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
channel := &rss.Channel{ channel := &rss.Channel{
Title: title, Title: title,
@ -88,7 +88,7 @@ func ShowRSS(c *control.CliArgs, db *model.DB, title, link, desc string) http.Ha
return return
} }
files := []string{c.WebDir + "/templates/index.html", c.WebDir + "/templates/feed.rss"} files := []string{"web/templates/index.html", "web/templates/feed.rss"}
tmpl, err := template.ParseFiles(files...) tmpl, err := template.ParseFiles(files...)
template.Must(tmpl, err).Execute(w, rss) template.Must(tmpl, err).Execute(w, rss)
} }

View File

@ -27,26 +27,26 @@ func saveSession(w http.ResponseWriter, r *http.Request, s *control.CookieStore,
return nil return nil
} }
func HomePage(c *control.CliArgs, db *model.DB, s *control.CookieStore) http.HandlerFunc { func HomePage(db *model.DB, s *control.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")
if err != nil { if err != nil {
log.Fatalln(err) log.Fatalln(err)
} }
files := []string{c.WebDir + "/templates/index.html"} files := []string{"web/templates/index.html"}
if numRows == 0 { if numRows == 0 {
files = append(files, c.WebDir+"/templates/add-user.html") files = append(files, "web/templates/add-user.html")
tmpl, err := template.ParseFiles(files...) tmpl, err := template.ParseFiles(files...)
template.Must(tmpl, err).Execute(w, nil) template.Must(tmpl, err).Execute(w, nil)
} else { } else {
session, _ := s.Get(r, "cookie") session, _ := s.Get(r, "cookie")
if auth, ok := session.Values["authenticated"].(bool); auth && ok { if auth, ok := session.Values["authenticated"].(bool); auth && ok {
files = append(files, c.WebDir+"/templates/hub.html") files = append(files, "web/templates/hub.html")
tmpl, err := template.ParseFiles(files...) tmpl, err := template.ParseFiles(files...)
template.Must(tmpl, err).Execute(w, session.Values["role"]) template.Must(tmpl, err).Execute(w, session.Values["role"])
} else { } else {
files = append(files, c.WebDir+"/templates/login.html") files = append(files, "web/templates/login.html")
tmpl, err := template.ParseFiles(files...) tmpl, err := template.ParseFiles(files...)
template.Must(tmpl, err).Execute(w, nil) template.Must(tmpl, err).Execute(w, nil)
} }
@ -54,7 +54,7 @@ func HomePage(c *control.CliArgs, db *model.DB, s *control.CookieStore) http.Han
} }
} }
func Login(c *control.CliArgs, db *model.DB, s *control.CookieStore) http.HandlerFunc { func Login(db *model.DB, s *control.CookieStore) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
userName := r.PostFormValue("username") userName := r.PostFormValue("username")
password := r.PostFormValue("password") password := r.PostFormValue("password")
@ -84,16 +84,16 @@ func Login(c *control.CliArgs, db *model.DB, s *control.CookieStore) http.Handle
return return
} }
tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html") tmpl, err := template.ParseFiles("web/templates/hub.html")
template.Must(tmpl, err).ExecuteTemplate(w, "page-content", user.Role) template.Must(tmpl, err).ExecuteTemplate(w, "page-content", user.Role)
} }
} }
func Logout(c *control.CliArgs, s *control.CookieStore) http.HandlerFunc { func Logout(s *control.CookieStore) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
session, err := s.Get(r, "cookie") session, err := s.Get(r, "cookie")
if err != nil { if err != nil {
tmpl, err := template.ParseFiles(c.WebDir + "/templates/login.html") tmpl, err := template.ParseFiles("web/templates/login.html")
msg := "Session nicht mehr gültig. Bitte erneut anmelden." msg := "Session nicht mehr gültig. Bitte erneut anmelden."
template.Must(tmpl, err).ExecuteTemplate(w, "page-content", msg) template.Must(tmpl, err).ExecuteTemplate(w, "page-content", msg)
} }
@ -106,7 +106,7 @@ func Logout(c *control.CliArgs, s *control.CookieStore) http.HandlerFunc {
return return
} }
tmpl, err := template.ParseFiles(c.WebDir + "/templates/login.html") tmpl, err := template.ParseFiles("web/templates/login.html")
template.Must(tmpl, err).ExecuteTemplate(w, "page-content", nil) template.Must(tmpl, err).ExecuteTemplate(w, "page-content", nil)
} }
} }

View File

@ -31,14 +31,12 @@ func checkUserStrings(user *model.User) (string, int, bool) {
} }
} }
func CreateUser(c *control.CliArgs) http.HandlerFunc { func CreateUser(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) { tmpl, err := template.ParseFiles("web/templates/add-user.html")
tmpl, err := template.ParseFiles(c.WebDir + "/templates/add-user.html")
template.Must(tmpl, err).ExecuteTemplate(w, "page-content", nil) template.Must(tmpl, err).ExecuteTemplate(w, "page-content", nil)
} }
}
func AddUser(c *control.CliArgs, db *model.DB, s *control.CookieStore) http.HandlerFunc { func AddUser(db *model.DB, s *control.CookieStore) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
role, err := strconv.Atoi(r.PostFormValue("role")) role, err := strconv.Atoi(r.PostFormValue("role"))
if err != nil { if err != nil {
@ -61,7 +59,7 @@ func AddUser(c *control.CliArgs, db *model.DB, s *control.CookieStore) http.Hand
if len(htmlData.UserName) == 0 || len(htmlData.FirstName) == 0 || if len(htmlData.UserName) == 0 || len(htmlData.FirstName) == 0 ||
len(htmlData.LastName) == 0 || len(pass) == 0 || len(pass2) == 0 { len(htmlData.LastName) == 0 || len(pass) == 0 || len(pass2) == 0 {
htmlData.Msg = "Alle Felder müssen ausgefüllt werden." htmlData.Msg = "Alle Felder müssen ausgefüllt werden."
tmpl, err := template.ParseFiles(c.WebDir + "/templates/add-user.html") tmpl, err := template.ParseFiles("web/templates/add-user.html")
template.Must(tmpl, err).ExecuteTemplate(w, "page-content", htmlData) template.Must(tmpl, err).ExecuteTemplate(w, "page-content", htmlData)
return return
} }
@ -69,7 +67,7 @@ func AddUser(c *control.CliArgs, db *model.DB, s *control.CookieStore) http.Hand
if !ok { if !ok {
htmlData.Msg = fmt.Sprint(userString, " ist zu lang. Maximal ", htmlData.Msg = fmt.Sprint(userString, " ist zu lang. Maximal ",
stringLen, " Zeichen erlaubt.") stringLen, " Zeichen erlaubt.")
tmpl, err := template.ParseFiles(c.WebDir + "/templates/add-user.html") tmpl, err := template.ParseFiles("web/templates/add-user.html")
template.Must(tmpl, err).ExecuteTemplate(w, "page-content", htmlData) template.Must(tmpl, err).ExecuteTemplate(w, "page-content", htmlData)
return return
} }
@ -77,13 +75,13 @@ func AddUser(c *control.CliArgs, db *model.DB, s *control.CookieStore) http.Hand
if id != 0 { if id != 0 {
htmlData.Msg = fmt.Sprint(htmlData.UserName, htmlData.Msg = fmt.Sprint(htmlData.UserName,
" ist bereits vergeben. Bitte anderen Benutzernamen wählen.") " ist bereits vergeben. Bitte anderen Benutzernamen wählen.")
tmpl, err := template.ParseFiles(c.WebDir + "/templates/add-user.html") tmpl, err := template.ParseFiles("web/templates/add-user.html")
template.Must(tmpl, err).ExecuteTemplate(w, "page-content", htmlData) template.Must(tmpl, err).ExecuteTemplate(w, "page-content", htmlData)
return return
} }
if pass != pass2 { if pass != pass2 {
htmlData.Msg = "Die Passwörter stimmen nicht überein." htmlData.Msg = "Die Passwörter stimmen nicht überein."
tmpl, err := template.ParseFiles(c.WebDir + "/templates/add-user.html") tmpl, err := template.ParseFiles("web/templates/add-user.html")
template.Must(tmpl, err).ExecuteTemplate(w, "page-content", htmlData) template.Must(tmpl, err).ExecuteTemplate(w, "page-content", htmlData)
return return
} }
@ -119,16 +117,16 @@ func AddUser(c *control.CliArgs, db *model.DB, s *control.CookieStore) http.Hand
} }
} }
tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html") tmpl, err := template.ParseFiles("web/templates/hub.html")
template.Must(tmpl, err).ExecuteTemplate(w, "page-content", 0) template.Must(tmpl, err).ExecuteTemplate(w, "page-content", 0)
} }
} }
func EditUser(c *control.CliArgs, db *model.DB, s *control.CookieStore) http.HandlerFunc { func EditUser(db *model.DB, s *control.CookieStore) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
session, err := s.Get(r, "cookie") session, err := s.Get(r, "cookie")
if err != nil { if err != nil {
tmpl, err := template.ParseFiles(c.WebDir + "/templates/login.html") tmpl, err := template.ParseFiles("web/templates/login.html")
msg := "Session nicht mehr gültig. Bitte erneut anmelden." msg := "Session nicht mehr gültig. Bitte erneut anmelden."
template.Must(tmpl, err).ExecuteTemplate(w, "page-content", msg) template.Must(tmpl, err).ExecuteTemplate(w, "page-content", msg)
} }
@ -140,16 +138,16 @@ func EditUser(c *control.CliArgs, db *model.DB, s *control.CookieStore) http.Han
return return
} }
tmpl, err := template.ParseFiles(c.WebDir + "/templates/edit-user.html") tmpl, err := template.ParseFiles("web/templates/edit-user.html")
template.Must(tmpl, err).ExecuteTemplate(w, "page-content", user) template.Must(tmpl, err).ExecuteTemplate(w, "page-content", user)
} }
} }
func UpdateUser(c *control.CliArgs, db *model.DB, s *control.CookieStore) http.HandlerFunc { func UpdateUser(db *model.DB, s *control.CookieStore) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
session, err := s.Get(r, "cookie") session, err := s.Get(r, "cookie")
if err != nil { if err != nil {
tmpl, err := template.ParseFiles(c.WebDir + "/templates/login.html") tmpl, err := template.ParseFiles("web/templates/login.html")
msg := "Session nicht mehr gültig. Bitte erneut anmelden." msg := "Session nicht mehr gültig. Bitte erneut anmelden."
template.Must(tmpl, err).ExecuteTemplate(w, "page-content", msg) template.Must(tmpl, err).ExecuteTemplate(w, "page-content", msg)
} }
@ -169,7 +167,7 @@ func UpdateUser(c *control.CliArgs, db *model.DB, s *control.CookieStore) http.H
if len(userData.UserName) == 0 || len(userData.FirstName) == 0 || if len(userData.UserName) == 0 || len(userData.FirstName) == 0 ||
len(userData.LastName) == 0 { len(userData.LastName) == 0 {
userData.Msg = "Alle Felder mit * müssen ausgefüllt sein." userData.Msg = "Alle Felder mit * müssen ausgefüllt sein."
tmpl, err := template.ParseFiles(c.WebDir + "/templates/edit-user.html") tmpl, err := template.ParseFiles("web/templates/edit-user.html")
tmpl = template.Must(tmpl, err) tmpl = template.Must(tmpl, err)
tmpl.ExecuteTemplate(w, "page-content", userData.Msg) tmpl.ExecuteTemplate(w, "page-content", userData.Msg)
return return
@ -179,7 +177,7 @@ func UpdateUser(c *control.CliArgs, db *model.DB, s *control.CookieStore) http.H
if !ok { if !ok {
userData.Msg = fmt.Sprint(userString, " ist zu lang. Maximal ", userData.Msg = fmt.Sprint(userString, " ist zu lang. Maximal ",
stringLen, " Zeichen erlaubt.") stringLen, " Zeichen erlaubt.")
tmpl, err := template.ParseFiles(c.WebDir + "/templates/edit-user.html") tmpl, err := template.ParseFiles("web/templates/edit-user.html")
tmpl = template.Must(tmpl, err) tmpl = template.Must(tmpl, err)
tmpl.ExecuteTemplate(w, "page-content", userData) tmpl.ExecuteTemplate(w, "page-content", userData)
return return
@ -189,7 +187,7 @@ func UpdateUser(c *control.CliArgs, db *model.DB, s *control.CookieStore) http.H
if id != userData.ID { if id != userData.ID {
userData.Msg = "Benutzername bereits vergeben." userData.Msg = "Benutzername bereits vergeben."
userData.UserName = "" userData.UserName = ""
tmpl, err := template.ParseFiles(c.WebDir + "/templates/edit-user.html") tmpl, err := template.ParseFiles("web/templates/edit-user.html")
tmpl = template.Must(tmpl, err) tmpl = template.Must(tmpl, err)
tmpl.ExecuteTemplate(w, "page-content", userData) tmpl.ExecuteTemplate(w, "page-content", userData)
return return
@ -205,11 +203,11 @@ func UpdateUser(c *control.CliArgs, db *model.DB, s *control.CookieStore) http.H
newPass, newPass,
newPass2); err != nil { newPass2); err != nil {
userData.Msg = "Aktualisierung der Benutzerdaten fehlgeschlagen." userData.Msg = "Aktualisierung der Benutzerdaten fehlgeschlagen."
tmpl, err := template.ParseFiles(c.WebDir + "/templates/edit-user.html") tmpl, err := template.ParseFiles("web/templates/edit-user.html")
template.Must(tmpl, err).ExecuteTemplate(w, "page-content", userData) template.Must(tmpl, err).ExecuteTemplate(w, "page-content", userData)
} }
tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html") tmpl, err := template.ParseFiles("web/templates/hub.html")
tmpl = template.Must(tmpl, err) tmpl = template.Must(tmpl, err)
tmpl.ExecuteTemplate(w, "page-content", session.Values["role"].(int)) tmpl.ExecuteTemplate(w, "page-content", session.Values["role"].(int))
} }

View File

@ -1,10 +1,8 @@
{{define "page-content"}} {{define "page-content"}}
<h2>Neuer Benutzer</h2> <h2>Neuer Benutzer</h2>
<form> <form>
<input required name="tag" placeholder="Tag" type="text" /> <input required name="tag" placeholder="Tag" type="text" />
<input type="submit" value="Anlegen" hx-post="/add-tag/" hx-target="#page-content" /> <input type="submit" value="Anlegen" hx-post="/add-tag/" hx-target="#page-content" />
</form> </form>
<button hx-get="/hub/" hx-target="#page-content">Abbrechen</button> <button hx-get="/hub/" hx-target="#page-content">Abbrechen</button>
{{end}} {{end}}

View File

@ -1,18 +1,13 @@
{{define "page-content"}} {{define "page-content"}}
<h2>Neuer Benutzer</h2> <h2>Neuer Benutzer</h2>
<form> <form>
<div>
<input required name="username" placeholder="Benutzername" type="text" value="{{.UserName}}" /> <input required name="username" placeholder="Benutzername" type="text" value="{{.UserName}}" />
<input required name="password" placeholder="Passwort" type="password" /> <input required name="password" placeholder="Passwort" type="password" />
<input required name="password2" placeholder="Passwort wiederholen" type="password" /> <input required name="password2" placeholder="Passwort wiederholen" type="password" />
</div>
<div>
<input required name="first-name" placeholder="Vorname" type="text" value="{{.FirstName}}" /> <input required name="first-name" placeholder="Vorname" type="text" value="{{.FirstName}}" />
<input required name="last-name" placeholder="Nachname" type="text" value="{{.LastName}}" /> <input required name="last-name" placeholder="Nachname" type="text" value="{{.LastName}}" />
</div>
<div>
<input required id="author" name="role" type="radio" value="3" {{if eq .Role 3 }}checked{{end}} /> <input required id="author" name="role" type="radio" value="3" {{if eq .Role 3 }}checked{{end}} />
<label for="author">Autor</label> <label for="author">Autor</label>
<input required id="editor" name="role" type="radio" value="2" {{if eq .Role 2 }}checked{{end}} /> <input required id="editor" name="role" type="radio" value="2" {{if eq .Role 2 }}checked{{end}} />
@ -21,11 +16,9 @@
<label for="publisher">Herausgeber</label> <label for="publisher">Herausgeber</label>
<input required id="admin" name="role" type="radio" value="0" {{if eq .Role 0 }}checked{{end}} /> <input required id="admin" name="role" type="radio" value="0" {{if eq .Role 0 }}checked{{end}} />
<label for="admin">Admin</label> <label for="admin">Admin</label>
</div>
<input type="submit" value="Anlegen" hx-post="/add-user/" hx-target="#page-content" /> <input type="submit" value="Anlegen" hx-post="/add-user/" hx-target="#page-content" />
</form> </form>
<button hx-get="/hub/" hx-target="#page-content">Abbrechen</button> <button hx-get="/hub/" hx-target="#page-content">Abbrechen</button>
<script> <script>

View File

@ -1,13 +1,10 @@
{{define "page-content"}} {{define "page-content"}}
<div>
{{range .}} {{range .}}
<div> <div>
<h1>{{.Title}}</h1> <h1>{{.Title}}</h1>
<p>{{.Description}}</p> <p>{{.Description}}</p>
</div> </div>
{{end}} {{end}}
</div>
<button hx-get="/publish-issue/" hx-target="#page-content">Ausgabe publizieren</button> <button hx-get="/publish-issue/" hx-target="#page-content">Ausgabe publizieren</button>
<button hx-get="/hub/" hx-target="#page-content">Abbrechen</button> <button hx-get="/hub/" hx-target="#page-content">Abbrechen</button>
{{end}} {{end}}

View File

@ -1,19 +1,13 @@
{{define "page-content"}} {{define "page-content"}}
<form> <form>
<div>
<input name="username" type="text" value="{{.UserName}}" /> <input name="username" type="text" value="{{.UserName}}" />
<input name="first-name" type="text" value="{{.FirstName}}" /> <input name="first-name" type="text" value="{{.FirstName}}" />
<input name="last-name" type="text" value="{{.LastName}}" /> <input name="last-name" type="text" value="{{.LastName}}" />
</div>
<div>
<input name="old-password" placeholder="Altes Passwort" type="password" /> <input name="old-password" placeholder="Altes Passwort" type="password" />
<input name="password" placeholder="Neues Passwort" type="password" /> <input name="password" placeholder="Neues Passwort" type="password" />
<input name="password2" placeholder="Wiederholen" type="password" /> <input name="password2" placeholder="Wiederholen" type="password" />
</div>
<input type="submit" value="Aktualisieren" hx-post="/update-user/" hx-target="#page-content" /> <input type="submit" value="Aktualisieren" hx-post="/update-user/" hx-target="#page-content" />
</form> </form>
<button hx-get="/hub/" hx-target="#page-content">Abbrechen</button>
{{end}} {{end}}

View File

@ -1,57 +1,13 @@
{{define "page-content"}} {{define "page-content"}}
<h2>Editor</h2> <h2>Editor</h2>
<form> <form>
<div>
<input name="article-title" placeholder="Titel" type="text" /> <input name="article-title" placeholder="Titel" type="text" />
<textarea name="article-description" placeholder="Beschreibung"></textarea> <textarea name="article-description" placeholder="Beschreibung"></textarea>
<textarea name="article-content" placeholder="Artikel"></textarea> <textarea name="article-content" placeholder="Artikel"></textarea>
</div>
<div>
{{range .}} {{range .}}
<div>
<input id="{{.Name}}" name="tags" type="checkbox" value="{{.ID}}" /> <input id="{{.Name}}" name="tags" type="checkbox" value="{{.ID}}" />
<label for="{{.Name}}">{{.Name}}</label> <label for="{{.Name}}">{{.Name}}</label>
</div>
{{end}} {{end}}
</div>
<div id="editor-images">
<input name="article-image" type="file" hx-encoding="multipart/form-data" hx-post="/upload-image/"
hx-swap="beforeend" hx-target="#editor-images" />
</div>
<input type="submit" value="Senden" hx-post="/submit-article/" hx-target="#page-content" /> <input type="submit" value="Senden" hx-post="/submit-article/" hx-target="#page-content" />
</form> </form>
<button hx-get="/hub/" hx-target="#page-content">Abbrechen</button>
<script>
function copyToClipboard(text) {
event.preventDefault(); // Get-Request verhindern
var textarea = document.createElement("textarea");
textarea.textContent = text;
document.body.appendChild(textarea);
textarea.select();
try {
document.execCommand('copy');
} catch (err) {
console.warn('Fehler beim Kopieren', err);
}
document.body.removeChild(textarea);
}
</script>
{{end}}
{{define "editor-images"}}
{{if gt (len .) 0}}
<div>
{{.}}
<button onclick="copyToClipboard('{{.}}')">Kopieren</button>
</div>
{{end}}
{{end}} {{end}}

View File

@ -1,25 +1,17 @@
{{define "page-content"}} {{define "page-content"}}
<h2>Hub</h2> <h2>Hub</h2>
<div>
<button hx-get="/write-article/" hx-target="#page-content">Artikel schreiben</button> <button hx-get="/write-article/" hx-target="#page-content">Artikel schreiben</button>
<button hx-get="/rejected-articles/" hx-target="#page-content">Abgelehnte Artikel</button> <button hx-get="/rejected-articles/" hx-target="#page-content">Abgelehnte Artikel</button>
<button hx-get="/rss/" hx-target="#page-content">RSS Feed</button> <button hx-get="/rss/" hx-target="#page-content">RSS Feed</button>
<button hx-get="/edit-user/" hx-target="#page-content">Benutzer bearbeiten</button> <button hx-get="/edit-user/" hx-target="#page-content">Benutzer bearbeiten</button>
</div>
{{if lt . 3}} {{if lt . 3}}
<div>
<button hx-get="/unpublished-articles/" hx-target="#page-content">Unveröffentlichte Artikel</button> <button hx-get="/unpublished-articles/" hx-target="#page-content">Unveröffentlichte Artikel</button>
<button hx-get="/create-tag/" hx-target="#page-content">Neuer Tag</button> <button hx-get="/create-tag/" hx-target="#page-content">Neuer Tag</button>
</div>
{{end}} {{end}}
{{if lt . 2}} {{if lt . 2}}
<div>
<button hx-get="/this-issue/" hx-target="#page-content">Diese Ausgabe</button> <button hx-get="/this-issue/" hx-target="#page-content">Diese Ausgabe</button>
</div>
{{end}} {{end}}
{{if eq . 0}} {{if eq . 0}}
<div>
<button hx-get="/create-user/" hx-target="#page-content">Benutzer hinzufügen</button> <button hx-get="/create-user/" hx-target="#page-content">Benutzer hinzufügen</button>
</div>
{{end}} {{end}}
{{end}} {{end}}

View File

@ -1,11 +1,8 @@
{{define "page-content"}} {{define "page-content"}}
<h2>Anmeldung</h2> <h2>Anmeldung</h2>
<form> <form>
<div>
<input name="username" placeholder="Benutzername" type="text" /> <input name="username" placeholder="Benutzername" type="text" />
<input name="password" placeholder="Passwort" type="password" /> <input name="password" placeholder="Passwort" type="password" />
</div>
<input type="submit" value="Anmelden" hx-post="/login/" hx-target="#page-content" /> <input type="submit" value="Anmelden" hx-post="/login/" hx-target="#page-content" />
</form> </form>
{{end}} {{end}}

View File

@ -1,18 +1,12 @@
{{define "page-content"}} {{define "page-content"}}
<form> <form>
<div>
{{range .RejectedArticles}} {{range .RejectedArticles}}
<div>
{{if index $.MyIDs .ID}} {{if index $.MyIDs .ID}}
<input required id="{{.ID}}" name="id" type="radio" value="{{.ID}}" /> <input required id="{{.ID}}" name="id" type="radio" value="{{.ID}}" />
<label for="{{.ID}}">{{.Title}}</label> <label for="{{.ID}}">{{.Title}}</label>
{{end}} {{end}}
</div>
{{end}} {{end}}
</div>
<input type="submit" value="Auswählen" hx-post="/review-rejected-article/" hx-target="#page-content" /> <input type="submit" value="Auswählen" hx-post="/review-rejected-article/" hx-target="#page-content" />
</form> </form>
<button hx-get="/hub/" hx-target="#page-content">Zurück</button> <button hx-get="/hub/" hx-target="#page-content">Zurück</button>
{{end}} {{end}}

View File

@ -1,59 +1,16 @@
{{define "page-content"}} {{define "page-content"}}
<h2>Editor</h2> <h2>Editor</h2>
<form> <form>
<div>
<input name="article-title" placeholder="Titel" type="text" value="{{.Article.Title}}" /> <input name="article-title" placeholder="Titel" type="text" value="{{.Article.Title}}" />
<textarea name="article-description" placeholder="Beschreibung">{{.Article.Description}}</textarea> <textarea name="article-description" placeholder="Beschreibung">{{.Article.Description}}</textarea>
<textarea name="article-content" placeholder="Artikel">{{.Article.Content}}</textarea> <textarea name="article-content" placeholder="Artikel">{{.Article.Content}}</textarea>
<input name="article-id" type="hidden" value="{{.Article.ID}}" /> <input name="article-id" type="hidden" value="{{.Article.ID}}" />
</div>
<div>
{{range .Tags}} {{range .Tags}}
<div> <input id="tag-{{.Name}}" name="tags" type="checkbox" value="{{.ID}}" {{if index $.Selected .ID}}checked{{end}} />
<input id="tag-{{.Name}}" name="tags" type="checkbox" value="{{.ID}}" {{if index $.Selected
.ID}}checked{{end}} />
<label for="tag-{{.Name}}">{{.Name}}</label> <label for="tag-{{.Name}}">{{.Name}}</label>
</div>
{{end}} {{end}}
</div>
<div id="editor-images">
<input name="article-image" type="file" hx-encoding="multipart/form-data" hx-post="/upload-image/"
hx-swap="beforeend" hx-target="#editor-images" />
</div>
<input type="submit" value="Senden" hx-post="/resubmit-article/" hx-target="#page-content" /> <input type="submit" value="Senden" hx-post="/resubmit-article/" hx-target="#page-content" />
</form> </form>
<button hx-get="/hub/" hx-target="#page-content">Zurück</button>
<script>
function copyToClipboard(text) {
event.preventDefault(); // Get-Request verhindern
var textarea = document.createElement("textarea");
textarea.textContent = text;
document.body.appendChild(textarea);
textarea.select();
try {
document.execCommand('copy');
} catch (err) {
console.warn('Fehler beim Kopieren', err);
}
document.body.removeChild(textarea);
}
</script>
{{end}}
{{define "editor-images"}}
{{if gt (len .) 0}}
<div>
{{.}}
<button onclick="copyToClipboard('{{.}}')">Kopieren</button>
</div>
{{end}}
{{end}} {{end}}

View File

@ -1,16 +1,10 @@
{{define "page-content"}} {{define "page-content"}}
<form> <form>
<div>
{{range .}} {{range .}}
<div>
<input required id="{{.ID}}" name="id" type="radio" value="{{.ID}}" /> <input required id="{{.ID}}" name="id" type="radio" value="{{.ID}}" />
<label for="{{.ID}}">{{.Title}}</label> <label for="{{.ID}}">{{.Title}}</label>
</div>
{{end}} {{end}}
</div>
<input type="submit" value="Auswählen" hx-post="/review-unpublished-article/" hx-target="#page-content" /> <input type="submit" value="Auswählen" hx-post="/review-unpublished-article/" hx-target="#page-content" />
</form> </form>
<button hx-get="/hub/" hx-target="#page-content">Zurück</button> <button hx-get="/hub/" hx-target="#page-content">Zurück</button>
{{end}} {{end}}