Added article list for written but non-published articles
This commit is contained in:
		
							
								
								
									
										58
									
								
								cmd/data/articles.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								cmd/data/articles.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,58 @@ | |||||||
|  | package data | ||||||
|  |  | ||||||
|  | import "time" | ||||||
|  |  | ||||||
|  | type Article struct { | ||||||
|  | 	Title   string | ||||||
|  | 	Created time.Time | ||||||
|  | 	Desc    string | ||||||
|  | 	Content string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | 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) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (l *ArticleList) Add(a Article) { | ||||||
|  | 	l.addChan <- a | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (l *ArticleList) Release(i int) (Article, bool) { | ||||||
|  | 	if i < 0 || i > len(l.List) { | ||||||
|  | 		return Article{}, false | ||||||
|  | 	} | ||||||
|  | 	l.releaseChan <- i | ||||||
|  | 	return <-l.returnChan, true | ||||||
|  | } | ||||||
| @@ -10,16 +10,30 @@ import ( | |||||||
|  |  | ||||||
| type Feed struct { | type Feed struct { | ||||||
| 	feeds.Feed | 	feeds.Feed | ||||||
|  | 	addChan chan *feeds.Item | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (f *Feed) start() { | ||||||
|  | 	for item := range f.addChan { | ||||||
|  | 		f.Items = append(f.Items, item) | ||||||
|  | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func NewFeed(title, link, desc string) *Feed { | func NewFeed(title, link, desc string) *Feed { | ||||||
| 	return &Feed{ | 	feed := &Feed{ | ||||||
| 		Feed: feeds.Feed{ | 		Feed: feeds.Feed{ | ||||||
| 			Title:       title, | 			Title:       title, | ||||||
| 			Link:        &feeds.Link{Href: link}, | 			Link:        &feeds.Link{Href: link}, | ||||||
| 			Description: desc, | 			Description: desc, | ||||||
| 		}, | 		}, | ||||||
|  | 		addChan: make(chan *feeds.Item), | ||||||
| 	} | 	} | ||||||
|  | 	feed.start() | ||||||
|  | 	return feed | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (f *Feed) Close() { | ||||||
|  | 	close(f.addChan) | ||||||
| } | } | ||||||
|  |  | ||||||
| func OpenFeed(filename string) (*Feed, error) { | func OpenFeed(filename string) (*Feed, error) { | ||||||
| @@ -29,17 +43,19 @@ func OpenFeed(filename string) (*Feed, error) { | |||||||
| 	} | 	} | ||||||
| 	defer file.Close() | 	defer file.Close() | ||||||
|  |  | ||||||
| 	feed := &Feed{} | 	feed := new(Feed) | ||||||
| 	decoder := gob.NewDecoder(file) | 	decoder := gob.NewDecoder(file) | ||||||
| 	err = decoder.Decode(feed) | 	err = decoder.Decode(&feed.Feed) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, fmt.Errorf("error decoding file %v: %v", filename, err) | 		return nil, fmt.Errorf("error decoding file %v: %v", filename, err) | ||||||
| 	} | 	} | ||||||
|  | 	feed.addChan = make(chan *feeds.Item) | ||||||
|  | 	feed.start() | ||||||
|  |  | ||||||
| 	return feed, nil | 	return feed, nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func (feed *Feed) Save(filename string) error { | func (f *Feed) Save(filename string) error { | ||||||
| 	file, err := os.Create(filename) | 	file, err := os.Create(filename) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return fmt.Errorf("error creating file %v: %v", filename, err) | 		return fmt.Errorf("error creating file %v: %v", filename, err) | ||||||
| @@ -47,10 +63,14 @@ func (feed *Feed) Save(filename string) error { | |||||||
| 	defer file.Close() | 	defer file.Close() | ||||||
|  |  | ||||||
| 	encoder := gob.NewEncoder(file) | 	encoder := gob.NewEncoder(file) | ||||||
| 	err = encoder.Encode(feed) | 	err = encoder.Encode(f.Feed) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return fmt.Errorf("error encoding file %v: %v", filename, err) | 		return fmt.Errorf("error encoding file %v: %v", filename, err) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func (f *Feed) Add(i *feeds.Item) { | ||||||
|  | 	f.addChan <- i | ||||||
|  | } | ||||||
|   | |||||||
							
								
								
									
										72
									
								
								cmd/ui/articles.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								cmd/ui/articles.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,72 @@ | |||||||
|  | package ui | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"html/template" | ||||||
|  | 	"log" | ||||||
|  | 	"net/http" | ||||||
|  | 	"time" | ||||||
|  |  | ||||||
|  | 	"github.com/gorilla/feeds" | ||||||
|  | 	"streifling.com/jason/cpolis/cmd/data" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | 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) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func FinishArticle(l *data.ArticleList) http.HandlerFunc { | ||||||
|  | 	return func(w http.ResponseWriter, r *http.Request) { | ||||||
|  | 		article := data.Article{} | ||||||
|  | 		var err error | ||||||
|  |  | ||||||
|  | 		article.Title, err = data.ConvertToPlain(r.PostFormValue("editor-title")) | ||||||
|  | 		if err != nil { | ||||||
|  | 			log.Println(err) | ||||||
|  | 			http.Error(w, err.Error(), http.StatusInternalServerError) | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		article.Desc, err = data.ConvertToPlain(r.PostFormValue("editor-desc")) | ||||||
|  | 		if err != nil { | ||||||
|  | 			log.Println(err) | ||||||
|  | 			http.Error(w, err.Error(), http.StatusInternalServerError) | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		article.Content, err = data.ConvertToHTML(r.PostFormValue("editor-text")) | ||||||
|  | 		if err != nil { | ||||||
|  | 			log.Println(err) | ||||||
|  | 			http.Error(w, err.Error(), http.StatusInternalServerError) | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		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 { | ||||||
|  | 	return func(w http.ResponseWriter, r *http.Request) { | ||||||
|  | 		article, ok := l.Release(i) | ||||||
|  | 		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) | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		f.Add(&feeds.Item{ | ||||||
|  | 			Title:       article.Title, | ||||||
|  | 			Created:     article.Created, | ||||||
|  | 			Description: article.Desc, | ||||||
|  | 			Content:     article.Content, | ||||||
|  | 		}) | ||||||
|  | 		f.Save("rss.gob") | ||||||
|  |  | ||||||
|  | 		template.Must(template.ParseFiles("web/templates/hub.html")).ExecuteTemplate(w, "page-content", nil) | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @@ -1,52 +0,0 @@ | |||||||
| package ui |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"html/template" |  | ||||||
| 	"log" |  | ||||||
| 	"net/http" |  | ||||||
| 	"time" |  | ||||||
|  |  | ||||||
| 	"github.com/gorilla/feeds" |  | ||||||
| 	"streifling.com/jason/cpolis/cmd/data" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| 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) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func FinishEdit(feed *data.Feed) http.HandlerFunc { |  | ||||||
| 	return func(w http.ResponseWriter, r *http.Request) { |  | ||||||
| 		title, err := data.ConvertToPlain(r.PostFormValue("editor-title")) |  | ||||||
| 		if err != nil { |  | ||||||
| 			log.Println(err) |  | ||||||
| 			http.Error(w, err.Error(), http.StatusInternalServerError) |  | ||||||
| 			return |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		desc, err := data.ConvertToPlain(r.PostFormValue("editor-desc")) |  | ||||||
| 		if err != nil { |  | ||||||
| 			log.Println(err) |  | ||||||
| 			http.Error(w, err.Error(), http.StatusInternalServerError) |  | ||||||
| 			return |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		content, err := data.ConvertToHTML(r.PostFormValue("editor-text")) |  | ||||||
| 		if err != nil { |  | ||||||
| 			log.Println(err) |  | ||||||
| 			http.Error(w, err.Error(), http.StatusInternalServerError) |  | ||||||
| 			return |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		feed.Add(&feeds.Item{ |  | ||||||
| 			Title:       title, |  | ||||||
| 			Created:     time.Now(), |  | ||||||
| 			Description: desc, |  | ||||||
| 			Content:     content, |  | ||||||
| 		}) |  | ||||||
| 		feed.Save("tmp/rss.gob") |  | ||||||
|  |  | ||||||
| 		template.Must(template.ParseFiles("web/templates/hub.html")).ExecuteTemplate(w, "page-content", nil) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
							
								
								
									
										8
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								main.go
									
									
									
									
									
								
							| @@ -31,6 +31,10 @@ func main() { | |||||||
| 			"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") | ||||||
| 	} | 	} | ||||||
|  | 	defer feed.Close() | ||||||
|  |  | ||||||
|  | 	articleList := data.NewArticleList() | ||||||
|  | 	defer articleList.Close() | ||||||
|  |  | ||||||
| 	mux := http.NewServeMux() | 	mux := http.NewServeMux() | ||||||
| 	mux.Handle("/web/static/", http.StripPrefix("/web/static/", http.FileServer(http.Dir("web/static/")))) | 	mux.Handle("/web/static/", http.StripPrefix("/web/static/", http.FileServer(http.Dir("web/static/")))) | ||||||
| @@ -51,9 +55,9 @@ func main() { | |||||||
|  |  | ||||||
| 	mux.HandleFunc("POST /add-user/", ui.AddUser(db)) | 	mux.HandleFunc("POST /add-user/", ui.AddUser(db)) | ||||||
| 	mux.HandleFunc("POST /create-user/", ui.CreateUser()) | 	mux.HandleFunc("POST /create-user/", ui.CreateUser()) | ||||||
| 	mux.HandleFunc("POST /write-article/", ui.WriteArticle()) | 	mux.HandleFunc("POST /finish-article/", ui.FinishArticle(articleList)) | ||||||
| 	mux.HandleFunc("POST /finish-edit/", ui.FinishEdit(feed)) |  | ||||||
| 	mux.HandleFunc("POST /login/", ui.Login(db)) | 	mux.HandleFunc("POST /login/", ui.Login(db)) | ||||||
|  | 	mux.HandleFunc("POST /write-article/", ui.WriteArticle()) | ||||||
| 	mux.HandleFunc("/rss/", ui.ShowRSS(feed)) | 	mux.HandleFunc("/rss/", ui.ShowRSS(feed)) | ||||||
|  |  | ||||||
| 	log.Fatalln(http.ListenAndServe(":8080", mux)) | 	log.Fatalln(http.ListenAndServe(":8080", mux)) | ||||||
|   | |||||||
| @@ -4,7 +4,7 @@ | |||||||
|     <input name="editor-title" placeholder="Titel" type="text" /> |     <input name="editor-title" placeholder="Titel" type="text" /> | ||||||
|     <textarea name="editor-desc" placeholder="Beschreibung"></textarea> |     <textarea name="editor-desc" placeholder="Beschreibung"></textarea> | ||||||
|     <textarea name="editor-text" placeholder="Artikel"></textarea> |     <textarea name="editor-text" placeholder="Artikel"></textarea> | ||||||
|     <input type="submit" value="Senden" hx-post="/finish-edit/" hx-target="#page-content" /> |     <input type="submit" value="Senden" hx-post="/finish-article/" hx-target="#page-content" /> | ||||||
| </form> | </form> | ||||||
| {{end}} | {{end}} | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user