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 (
"fmt"
"io"
"os"
"time"
"git.streifling.com/jason/rss"
@ -50,82 +48,3 @@ func GetChannel(db *model.DB, title, link, description string) (*rss.Channel, er
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() {
args, err := control.HandleCliArgs()
if err != nil {
log.Fatalln(err)
}
logFile, err := os.OpenFile(args.LogFile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
logFile, err := os.OpenFile("tmp/cpolis.log",
os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
if err != nil {
log.Fatalln(err)
}
defer logFile.Close()
log.SetOutput(logFile)
// log.SetOutput(logFile)
db, err := model.OpenDB(args.DBName)
db, err := model.OpenDB("cpolis")
if err != nil {
log.Fatalln(err)
}
defer db.Close()
key, err := control.LoadKey(args.KeyFile)
key, err := control.LoadKey("tmp/key.gob")
if err != nil {
key, err = control.NewKey()
if err != nil {
log.Fatalln(err)
}
control.SaveKey(key, args.KeyFile)
control.SaveKey(key, "tmp/key.gob")
}
store := control.NewCookieStore(key)
mux := http.NewServeMux()
mux.Handle("/web/static/", http.StripPrefix("/web/static/",
http.FileServer(http.Dir(args.WebDir+"/static/"))))
mux.HandleFunc("/", view.HomePage(args, db, store))
http.FileServer(http.Dir("web/static/"))))
mux.HandleFunc("/", view.HomePage(db, store))
mux.HandleFunc("GET /create-tag/", view.CreateTag(args))
mux.HandleFunc("GET /create-user/", view.CreateUser(args))
mux.HandleFunc("GET /edit-user/", view.EditUser(args, db, store))
mux.HandleFunc("GET /hub/", view.ShowHub(args, db, store))
mux.HandleFunc("GET /logout/", view.Logout(args, store))
mux.HandleFunc("GET /publish-issue/", view.PublishLatestIssue(args, db, store))
mux.HandleFunc("GET /rejected-articles/", view.ShowRejectedArticles(args, db, store))
mux.HandleFunc("GET /rss/", view.ShowRSS(args,
mux.HandleFunc("GET /create-tag/", view.CreateTag)
mux.HandleFunc("GET /create-user/", view.CreateUser)
mux.HandleFunc("GET /edit-user/", view.EditUser(db, store))
mux.HandleFunc("GET /hub/", view.ShowHub(db, store))
mux.HandleFunc("GET /logout/", view.Logout(store))
mux.HandleFunc("GET /publish-issue/", view.PublishLatestIssue(db))
mux.HandleFunc("GET /rejected-articles/", view.ShowRejectedArticles(db, store))
mux.HandleFunc("GET /rss/", view.ShowRSS(
db,
"Freimaurer Distrikt Niedersachsen und Sachsen-Anhalt",
"https://distrikt-ni-st.de",
"Freiheit, Gleichheit, Brüderlichkeit, Toleranz und Humanität",
))
mux.HandleFunc("GET /this-issue/", view.ShowCurrentArticles(args, db))
mux.HandleFunc("GET /unpublished-articles/", view.ShowUnpublishedArticles(args, db))
mux.HandleFunc("GET /write-article/", view.WriteArticle(args, db))
mux.HandleFunc("GET /this-issue/", view.ShowCurrentArticles(db))
mux.HandleFunc("GET /unpublished-articles/", view.ShowUnpublishedArticles(db))
mux.HandleFunc("GET /write-article/", view.WriteArticle(db))
mux.HandleFunc("POST /add-tag/", view.AddTag(args, db, store))
mux.HandleFunc("POST /add-user/", view.AddUser(args, db, store))
mux.HandleFunc("POST /login/", view.Login(args, db, store))
mux.HandleFunc("POST /publish-article/", view.PublishArticle(args, db, store))
mux.HandleFunc("POST /reject-article/", view.RejectArticle(args, db, store))
mux.HandleFunc("POST /resubmit-article/", view.ResubmitArticle(args, db, store))
mux.HandleFunc("POST /review-rejected-article/", view.ReviewRejectedArticle(args, db, store))
mux.HandleFunc("POST /review-unpublished-article/", view.ReviewUnpublishedArticle(args, db, store))
mux.HandleFunc("POST /submit-article/", view.SubmitArticle(args, db, store))
mux.HandleFunc("POST /update-user/", view.UpdateUser(args, db, store))
mux.HandleFunc("POST /upload-image/", view.UploadImage(args))
mux.HandleFunc("POST /add-tag/", view.AddTag(db, store))
mux.HandleFunc("POST /add-user/", view.AddUser(db, store))
mux.HandleFunc("POST /login/", view.Login(db, store))
mux.HandleFunc("POST /publish-article/", view.PublishArticle(db, store))
mux.HandleFunc("POST /reject-article/", view.RejectArticle(db, store))
mux.HandleFunc("POST /resubmit-article/", view.ResubmitArticle(db, store))
mux.HandleFunc("POST /review-rejected-article/", view.ReviewRejectedArticle(db, store))
mux.HandleFunc("POST /review-unpublished-article/", view.ReviewUnpublishedArticle(db, store))
mux.HandleFunc("POST /submit-article/", view.SubmitArticle(db, store))
mux.HandleFunc("POST /update-user/", view.UpdateUser(db, store))
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) {
query := `
SELECT id, title, created, description, content, author_id, issue_id
SELECT id, title, created, description, content, author_id
FROM articles
WHERE published = ?
AND rejected = ?
@ -121,8 +121,7 @@ func (db *DB) GetCertainArticles(published, rejected bool) ([]*Article, error) {
var created []byte
if err = rows.Scan(&article.ID, &article.Title, &created,
&article.Description, &article.Content, &article.AuthorID,
&article.IssueID); err != nil {
&article.Description, &article.Content, &article.AuthorID); err != nil {
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 {
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++ {
err := func() error {
@ -65,8 +68,8 @@ func (db *DB) GetArticleTags(articleID int64) ([]*Tag, error) {
}
func (db *DB) UpdateArticleTags(articleID int64, tagIDs []int64) error {
deleteQuery := "DELETE FROM articles_tags WHERE article_id = ?"
insertQuery := "INSERT INTO articles_tags (article_id, tag_id) VALUES (?, ?)"
query := `
`
for i := 0; i < TxMaxRetries; i++ {
err := func() error {
@ -75,22 +78,6 @@ func (db *DB) UpdateArticleTags(articleID int64, tagIDs []int64) error {
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 {
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 {
var id int64
txOptions := &sql.TxOptions{Isolation: sql.LevelSerializable}
updateQuery := "UPDATE issues SET published = true WHERE published = false"
insertQuery := "INSERT INTO issues (published) VALUES (?)"
@ -34,7 +35,7 @@ func (db *DB) PublishLatestIssue() error {
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 {
log.Fatalf("transaction error: %v, rollback error: %v", err, rollbackErr)
}

View File

@ -1,12 +1,9 @@
package view
import (
"fmt"
"html/template"
"io"
"log"
"net/http"
"os"
"strconv"
"time"
@ -14,21 +11,21 @@ import (
"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) {
session, err := s.Get(r, "cookie")
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."
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))
}
}
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) {
tags, err := db.GetTagList()
if err != nil {
@ -37,16 +34,16 @@ func WriteArticle(c *control.CliArgs, db *model.DB) http.HandlerFunc {
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)
}
}
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) {
session, err := s.Get(r, "cookie")
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."
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
}
tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html")
tmpl, err := template.ParseFiles("web/templates/hub.html")
tmpl = template.Must(tmpl, err)
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) {
id, err := strconv.ParseInt(r.PostFormValue("article-id"), 10, 64)
if err != nil {
@ -103,7 +100,7 @@ func ResubmitArticle(c *control.CliArgs, db *model.DB, s *control.CookieStore) h
description := r.PostFormValue("article-description")
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: "description", Value: description},
&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
}
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")
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."
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.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) {
unpublishedArticles, err := db.GetCertainArticles(false, false)
if err != nil {
@ -153,13 +133,13 @@ func ShowUnpublishedArticles(c *control.CliArgs, db *model.DB) http.HandlerFunc
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.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) {
type htmlData struct {
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.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) {
type htmlData struct {
Article *model.Article
@ -223,13 +203,13 @@ func ReviewUnpublishedArticle(c *control.CliArgs, db *model.DB, s *control.Cooki
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.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) {
type htmlData struct {
Selected map[int64]bool
@ -270,13 +250,13 @@ func ReviewRejectedArticle(c *control.CliArgs, db *model.DB, s *control.CookieSt
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.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) {
id, err := strconv.ParseInt(r.PostFormValue("id"), 10, 64)
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")
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."
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
}
feed, err := control.GenerateRSS(
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, err := template.ParseFiles("web/templates/hub.html")
tmpl = template.Must(tmpl, err)
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) {
id, err := strconv.ParseInt(r.PostFormValue("id"), 10, 64)
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")
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."
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
}
tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html")
tmpl, err := template.ParseFiles("web/templates/hub.html")
tmpl = template.Must(tmpl, err)
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) {
articles, err := db.GetCurrentIssueArticles()
if err != nil {
@ -370,37 +333,20 @@ func ShowCurrentArticles(c *control.CliArgs, db *model.DB) http.HandlerFunc {
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)
}
}
func UploadImage(c *control.CliArgs) http.HandlerFunc {
func PublishLatestIssue(db *model.DB) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
file, header, err := r.FormFile("article-image")
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 {
if err := db.PublishLatestIssue(); err != nil {
log.Println(err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
tmpl, err := template.ParseFiles(c.WebDir + "/templates/editor.html")
template.Must(tmpl, err).ExecuteTemplate(w, "editor-images", fmt.Sprint("![", header.Filename, "](", filename, ")"))
tmpl, err := template.ParseFiles("web/templates/hub.html")
template.Must(tmpl, err).ExecuteTemplate(w, "page-content", nil)
}
}

View File

@ -8,25 +8,23 @@ import (
"streifling.com/jason/cpolis/cmd/model"
)
func CreateTag(c *control.CliArgs) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
tmpl, err := template.ParseFiles(c.WebDir + "/templates/add-tag.html")
func CreateTag(w http.ResponseWriter, r *http.Request) {
tmpl, err := template.ParseFiles("web/templates/add-tag.html")
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) {
db.AddTag(r.PostFormValue("tag"))
session, err := s.Get(r, "cookie")
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."
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.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"
)
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) {
channel := &rss.Channel{
Title: title,
@ -88,7 +88,7 @@ func ShowRSS(c *control.CliArgs, db *model.DB, title, link, desc string) http.Ha
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...)
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
}
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) {
numRows, err := db.CountEntries("users")
if err != nil {
log.Fatalln(err)
}
files := []string{c.WebDir + "/templates/index.html"}
files := []string{"web/templates/index.html"}
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...)
template.Must(tmpl, err).Execute(w, nil)
} else {
session, _ := s.Get(r, "cookie")
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...)
template.Must(tmpl, err).Execute(w, session.Values["role"])
} else {
files = append(files, c.WebDir+"/templates/login.html")
files = append(files, "web/templates/login.html")
tmpl, err := template.ParseFiles(files...)
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) {
userName := r.PostFormValue("username")
password := r.PostFormValue("password")
@ -84,16 +84,16 @@ func Login(c *control.CliArgs, db *model.DB, s *control.CookieStore) http.Handle
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)
}
}
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) {
session, err := s.Get(r, "cookie")
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."
template.Must(tmpl, err).ExecuteTemplate(w, "page-content", msg)
}
@ -106,7 +106,7 @@ func Logout(c *control.CliArgs, s *control.CookieStore) http.HandlerFunc {
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)
}
}

View File

@ -31,14 +31,12 @@ func checkUserStrings(user *model.User) (string, int, bool) {
}
}
func CreateUser(c *control.CliArgs) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
tmpl, err := template.ParseFiles(c.WebDir + "/templates/add-user.html")
func CreateUser(w http.ResponseWriter, r *http.Request) {
tmpl, err := template.ParseFiles("web/templates/add-user.html")
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) {
role, err := strconv.Atoi(r.PostFormValue("role"))
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 ||
len(htmlData.LastName) == 0 || len(pass) == 0 || len(pass2) == 0 {
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)
return
}
@ -69,7 +67,7 @@ func AddUser(c *control.CliArgs, db *model.DB, s *control.CookieStore) http.Hand
if !ok {
htmlData.Msg = fmt.Sprint(userString, " ist zu lang. Maximal ",
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)
return
}
@ -77,13 +75,13 @@ func AddUser(c *control.CliArgs, db *model.DB, s *control.CookieStore) http.Hand
if id != 0 {
htmlData.Msg = fmt.Sprint(htmlData.UserName,
" 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)
return
}
if pass != pass2 {
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)
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)
}
}
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) {
session, err := s.Get(r, "cookie")
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."
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
}
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)
}
}
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) {
session, err := s.Get(r, "cookie")
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."
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 ||
len(userData.LastName) == 0 {
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.ExecuteTemplate(w, "page-content", userData.Msg)
return
@ -179,7 +177,7 @@ func UpdateUser(c *control.CliArgs, db *model.DB, s *control.CookieStore) http.H
if !ok {
userData.Msg = fmt.Sprint(userString, " ist zu lang. Maximal ",
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.ExecuteTemplate(w, "page-content", userData)
return
@ -189,7 +187,7 @@ func UpdateUser(c *control.CliArgs, db *model.DB, s *control.CookieStore) http.H
if id != userData.ID {
userData.Msg = "Benutzername bereits vergeben."
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.ExecuteTemplate(w, "page-content", userData)
return
@ -205,11 +203,11 @@ func UpdateUser(c *control.CliArgs, db *model.DB, s *control.CookieStore) http.H
newPass,
newPass2); err != nil {
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)
}
tmpl, err := template.ParseFiles(c.WebDir + "/templates/hub.html")
tmpl, err := template.ParseFiles("web/templates/hub.html")
tmpl = template.Must(tmpl, err)
tmpl.ExecuteTemplate(w, "page-content", session.Values["role"].(int))
}

View File

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

View File

@ -1,18 +1,13 @@
{{define "page-content"}}
<h2>Neuer Benutzer</h2>
<form>
<div>
<input required name="username" placeholder="Benutzername" type="text" value="{{.UserName}}" />
<input required name="password" placeholder="Passwort" 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="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}} />
<label for="author">Autor</label>
<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>
<input required id="admin" name="role" type="radio" value="0" {{if eq .Role 0 }}checked{{end}} />
<label for="admin">Admin</label>
</div>
<input type="submit" value="Anlegen" hx-post="/add-user/" hx-target="#page-content" />
</form>
<button hx-get="/hub/" hx-target="#page-content">Abbrechen</button>
<script>

View File

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

View File

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

View File

@ -1,57 +1,13 @@
{{define "page-content"}}
<h2>Editor</h2>
<form>
<div>
<input name="article-title" placeholder="Titel" type="text" />
<textarea name="article-description" placeholder="Beschreibung"></textarea>
<textarea name="article-content" placeholder="Artikel"></textarea>
</div>
<div>
{{range .}}
<div>
<input id="{{.Name}}" name="tags" type="checkbox" value="{{.ID}}" />
<label for="{{.Name}}">{{.Name}}</label>
</div>
{{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" />
</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}}

View File

@ -1,25 +1,17 @@
{{define "page-content"}}
<h2>Hub</h2>
<div>
<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="/rss/" hx-target="#page-content">RSS Feed</button>
<button hx-get="/edit-user/" hx-target="#page-content">Benutzer bearbeiten</button>
</div>
{{if lt . 3}}
<div>
<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>
</div>
{{end}}
{{if lt . 2}}
<div>
<button hx-get="/this-issue/" hx-target="#page-content">Diese Ausgabe</button>
</div>
{{end}}
{{if eq . 0}}
<div>
<button hx-get="/create-user/" hx-target="#page-content">Benutzer hinzufügen</button>
</div>
{{end}}
{{end}}

View File

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

View File

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

View File

@ -1,59 +1,16 @@
{{define "page-content"}}
<h2>Editor</h2>
<form>
<div>
<input name="article-title" placeholder="Titel" type="text" value="{{.Article.Title}}" />
<textarea name="article-description" placeholder="Beschreibung">{{.Article.Description}}</textarea>
<textarea name="article-content" placeholder="Artikel">{{.Article.Content}}</textarea>
<input name="article-id" type="hidden" value="{{.Article.ID}}" />
</div>
<div>
{{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>
</div>
{{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" />
</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}}

View File

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