diff --git a/cmd/data/articles.go b/cmd/data/articles.go index 42b4eca..ef7ab3e 100644 --- a/cmd/data/articles.go +++ b/cmd/data/articles.go @@ -1,58 +1,41 @@ package data -import "time" +import ( + "sync" + "time" + + "github.com/google/uuid" +) type Article struct { Title string Created time.Time Desc string Content string + UUID uuid.UUID } type ArticleList struct { - addChan chan Article - releaseChan chan int - returnChan chan Article - List []Article -} - -func (l *ArticleList) start() { - for { - select { - case article := <-l.addChan: - l.List = append(l.List, article) - case i := <-l.releaseChan: - l.returnChan <- l.List[i] - l.List = append(l.List[:i], l.List[i+1:]...) - } - } -} - -func NewArticleList() *ArticleList { - list := &ArticleList{ - List: []Article{}, - addChan: make(chan Article), - releaseChan: make(chan int), - returnChan: make(chan Article), - } - list.start() - return list -} - -func (l *ArticleList) Close() { - close(l.addChan) - close(l.releaseChan) - close(l.returnChan) + List []Article + sync.Mutex } func (l *ArticleList) Add(a Article) { - l.addChan <- a + l.Lock() + l.List = append(l.List, a) + l.Unlock() } -func (l *ArticleList) Release(i int) (Article, bool) { - if i < 0 || i > len(l.List) { - return Article{}, false +func (l *ArticleList) Release(uuid uuid.UUID) (Article, bool) { + l.Lock() + for i, article := range l.List { + if article.UUID == uuid { + foo := l.List[i] + l.List = append(l.List[:i], l.List[i+1:]...) + l.Unlock() + return foo, true + } } - l.releaseChan <- i - return <-l.returnChan, true + l.Unlock() + return Article{}, false } diff --git a/cmd/data/rss.go b/cmd/data/rss.go index 78d7509..3d92223 100644 --- a/cmd/data/rss.go +++ b/cmd/data/rss.go @@ -4,36 +4,24 @@ import ( "encoding/gob" "fmt" "os" + "sync" "github.com/gorilla/feeds" ) type Feed struct { feeds.Feed - addChan chan *feeds.Item -} - -func (f *Feed) start() { - for item := range f.addChan { - f.Items = append(f.Items, item) - } + sync.Mutex } func NewFeed(title, link, desc string) *Feed { - feed := &Feed{ + return &Feed{ Feed: feeds.Feed{ Title: title, Link: &feeds.Link{Href: link}, Description: desc, }, - addChan: make(chan *feeds.Item), } - feed.start() - return feed -} - -func (f *Feed) Close() { - close(f.addChan) } func OpenFeed(filename string) (*Feed, error) { @@ -49,8 +37,6 @@ func OpenFeed(filename string) (*Feed, error) { if err != nil { return nil, fmt.Errorf("error decoding file %v: %v", filename, err) } - feed.addChan = make(chan *feeds.Item) - feed.start() return feed, nil } @@ -63,7 +49,9 @@ func (f *Feed) Save(filename string) error { defer file.Close() encoder := gob.NewEncoder(file) + f.Lock() err = encoder.Encode(f.Feed) + f.Unlock() if err != nil { return fmt.Errorf("error encoding file %v: %v", filename, err) } @@ -72,5 +60,7 @@ func (f *Feed) Save(filename string) error { } func (f *Feed) Add(i *feeds.Item) { - f.addChan <- i + f.Lock() + f.Items = append(f.Items, i) + f.Unlock() } diff --git a/cmd/ui/admin.go b/cmd/ui/admin.go index bb5bbb8..9c8d1bd 100644 --- a/cmd/ui/admin.go +++ b/cmd/ui/admin.go @@ -51,7 +51,7 @@ func AddUser(db *data.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var writer, editor, admin bool - data := AddUserData{ + htmlData := AddUserData{ User: r.PostFormValue("username"), First: r.PostFormValue("first-name"), Last: r.PostFormValue("last-name"), @@ -60,29 +60,29 @@ func AddUser(db *data.DB) http.HandlerFunc { pass := r.PostFormValue("password") pass2 := r.PostFormValue("password2") - if inputsEmpty(data.User, pass, pass2, data.First, data.Last, data.Role) { - data.Msg = "Alle Felder müssen ausgefüllt werden." - template.Must(template.ParseFiles("web/templates/add-user.html")).ExecuteTemplate(w, "page-content", data) + if inputsEmpty(htmlData.User, pass, pass2, htmlData.First, htmlData.Last, htmlData.Role) { + htmlData.Msg = "Alle Felder müssen ausgefüllt werden." + template.Must(template.ParseFiles("web/templates/add-user.html")).ExecuteTemplate(w, "page-content", htmlData) return } - userString, stringLen, ok := checkUserStrings(data.User, data.First, data.Last) + userString, stringLen, ok := checkUserStrings(htmlData.User, htmlData.First, htmlData.Last) if !ok { - data.Msg = fmt.Sprint(userString, " ist zu lang. Maximal ", stringLen, " Zeichen erlaubt.") - template.Must(template.ParseFiles("web/templates/add-user.html")).ExecuteTemplate(w, "page-content", data) + htmlData.Msg = fmt.Sprint(userString, " ist zu lang. Maximal ", stringLen, " Zeichen erlaubt.") + template.Must(template.ParseFiles("web/templates/add-user.html")).ExecuteTemplate(w, "page-content", htmlData) return } - id, _ := db.GetID(data.User) + id, _ := db.GetID(htmlData.User) if id != 0 { - data.Msg = fmt.Sprint(data.User, " ist bereits vergeben. Bitte anderen Benutzernamen wählen.") - template.Must(template.ParseFiles("web/templates/add-user.html")).ExecuteTemplate(w, "page-content", data) + htmlData.Msg = fmt.Sprint(htmlData.User, " ist bereits vergeben. Bitte anderen Benutzernamen wählen.") + template.Must(template.ParseFiles("web/templates/add-user.html")).ExecuteTemplate(w, "page-content", htmlData) return } if pass != pass2 { - data.Msg = "Die Passwörter stimmen nicht überein." - template.Must(template.ParseFiles("web/templates/add-user.html")).ExecuteTemplate(w, "page-content", data) + htmlData.Msg = "Die Passwörter stimmen nicht überein." + template.Must(template.ParseFiles("web/templates/add-user.html")).ExecuteTemplate(w, "page-content", htmlData) return } - switch data.Role { + switch htmlData.Role { case "writer": writer = true editor = false @@ -96,13 +96,13 @@ func AddUser(db *data.DB) http.HandlerFunc { editor = false admin = true default: - log.Println("When setting up", data.User, "the HTML was altered.") - data.Msg = "Das HTML der Seite zu verändern ist unzulässig. Dieser Vorfall wurde gespeichert." - template.Must(template.ParseFiles("web/templates/add-user.html")).ExecuteTemplate(w, "page-content", data) + log.Println("When setting up", htmlData.User, "the HTML was altered.") + htmlData.Msg = "Das HTML der Seite zu verändern ist unzulässig. Dieser Vorfall wurde gespeichert." + template.Must(template.ParseFiles("web/templates/add-user.html")).ExecuteTemplate(w, "page-content", htmlData) return } - if err := db.AddUser(data.User, pass, data.First, data.Last, writer, editor, admin); err != nil { + if err := db.AddUser(htmlData.User, pass, htmlData.First, htmlData.Last, writer, editor, admin); err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) return diff --git a/cmd/ui/articles.go b/cmd/ui/articles.go index 95f65ee..2c1bd4a 100644 --- a/cmd/ui/articles.go +++ b/cmd/ui/articles.go @@ -6,10 +6,17 @@ import ( "net/http" "time" + "github.com/google/uuid" "github.com/gorilla/feeds" "streifling.com/jason/cpolis/cmd/data" ) +func ShowHub() http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + template.Must(template.ParseFiles("web/templates/hub.html")).ExecuteTemplate(w, "page-content", nil) + } +} + func WriteArticle() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { template.Must(template.ParseFiles("web/templates/editor.html")).ExecuteTemplate(w, "page-content", nil) @@ -42,20 +49,54 @@ func FinishArticle(l *data.ArticleList) http.HandlerFunc { return } + article.UUID = uuid.New() article.Created = time.Now() + l.Add(article) template.Must(template.ParseFiles("web/templates/hub.html")).ExecuteTemplate(w, "page-content", nil) } } -func PublishArticle(f *data.Feed, l *data.ArticleList, i int) http.HandlerFunc { +func ShowUnpublishedArticles(l *data.ArticleList) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - article, ok := l.Release(i) + template.Must(template.ParseFiles("web/templates/unpublished-articles.html")).ExecuteTemplate(w, "page-content", l.List) + } +} + +func ReviewArticle(l *data.ArticleList) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + uuid, err := uuid.Parse(r.PostFormValue("uuid")) + if err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + for _, article := range l.List { + if article.UUID == uuid { + template.Must(template.ParseFiles("web/templates/to-be-published.html")).ExecuteTemplate(w, "page-content", article) + return + } + } + template.Must(template.ParseFiles("web/templates/hub.html")).ExecuteTemplate(w, "page-content", nil) + } +} + +func PublishArticle(f *data.Feed, l *data.ArticleList) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + uuid, err := uuid.Parse(r.PostFormValue("uuid")) + if err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + article, ok := l.Release(uuid) if !ok { // TODO: Warnung anzeigen - // data.Msg = "Alle Felder müssen ausgefüllt werden." - // template.Must(template.ParseFiles("web/templates/add-user.html")).ExecuteTemplate(w, "page-content", data) + // msg = "Alle Felder müssen ausgefüllt werden." + // template.Must(template.ParseFiles("web/templates/add-user.html")).ExecuteTemplate(w, "page-content", msg) return } @@ -65,7 +106,7 @@ func PublishArticle(f *data.Feed, l *data.ArticleList, i int) http.HandlerFunc { Description: article.Desc, Content: article.Content, }) - f.Save("rss.gob") + f.Save("tmp/rss.gob") template.Must(template.ParseFiles("web/templates/hub.html")).ExecuteTemplate(w, "page-content", nil) } diff --git a/go.mod b/go.mod index 9e7649a..cecb8dc 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.22.0 require ( github.com/go-sql-driver/mysql v1.7.1 + github.com/google/uuid v1.6.0 github.com/gorilla/feeds v1.1.2 github.com/microcosm-cc/bluemonday v1.0.26 github.com/yuin/goldmark v1.7.0 diff --git a/go.sum b/go.sum index 234adb6..57cb739 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,8 @@ github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuP github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= github.com/gorilla/feeds v1.1.2 h1:pxzZ5PD3RJdhFH2FsJJ4x6PqMqbgFk1+Vez4XWBW8Iw= diff --git a/main.go b/main.go index 9faa660..ba7e69f 100644 --- a/main.go +++ b/main.go @@ -31,10 +31,8 @@ func main() { "https://distrikt-ni-st.de", "Freiheit, Gleichheit, Brüderlichkeit, Toleranz und Humanität") } - defer feed.Close() - articleList := data.NewArticleList() - defer articleList.Close() + articleList := new(data.ArticleList) mux := http.NewServeMux() mux.Handle("/web/static/", http.StripPrefix("/web/static/", http.FileServer(http.Dir("web/static/")))) @@ -53,12 +51,18 @@ func main() { }) } + mux.HandleFunc("/rss/", ui.ShowRSS(feed)) + + mux.HandleFunc("GET /hub/", ui.ShowHub()) + mux.HandleFunc("POST /add-user/", ui.AddUser(db)) mux.HandleFunc("POST /create-user/", ui.CreateUser()) mux.HandleFunc("POST /finish-article/", ui.FinishArticle(articleList)) mux.HandleFunc("POST /login/", ui.Login(db)) + mux.HandleFunc("POST /review-article/", ui.ReviewArticle(articleList)) + mux.HandleFunc("POST /publish-article/", ui.PublishArticle(feed, articleList)) + mux.HandleFunc("POST /unpublished-articles/", ui.ShowUnpublishedArticles(articleList)) mux.HandleFunc("POST /write-article/", ui.WriteArticle()) - mux.HandleFunc("/rss/", ui.ShowRSS(feed)) log.Fatalln(http.ListenAndServe(":8080", mux)) } diff --git a/web/templates/hub.html b/web/templates/hub.html index 5103d6b..2161767 100644 --- a/web/templates/hub.html +++ b/web/templates/hub.html @@ -3,4 +3,5 @@ + {{end}} diff --git a/web/templates/to-be-published.html b/web/templates/to-be-published.html new file mode 100644 index 0000000..a36f9bf --- /dev/null +++ b/web/templates/to-be-published.html @@ -0,0 +1,11 @@ +{{define "page-content"}} +
+ +{{end}} diff --git a/web/templates/unpublished-articles.html b/web/templates/unpublished-articles.html new file mode 100644 index 0000000..ae9b144 --- /dev/null +++ b/web/templates/unpublished-articles.html @@ -0,0 +1,10 @@ +{{define "page-content"}} + + +{{end}}