Compare commits
	
		
			4 Commits
		
	
	
		
			sessions
			...
			streifling
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 4aa4fff5e8 | |||
| a9c61c5a11 | |||
| dd50c4f385 | |||
| b74036343f | 
| @@ -1,6 +1,9 @@ | |||||||
| package data | package data | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
|  | 	"encoding/gob" | ||||||
|  | 	"fmt" | ||||||
|  | 	"os" | ||||||
| 	"sync" | 	"sync" | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
| @@ -18,40 +21,56 @@ type Article struct { | |||||||
| 	AuthorID int64 | 	AuthorID int64 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // TODO: setCh | ||||||
| type ArticleList struct { | type ArticleList struct { | ||||||
| 	addCh chan *Article | 	addCh    chan *Article | ||||||
| 	delCh chan uuid.UUID | 	delCh    chan uuid.UUID | ||||||
| 	retCh chan *Article | 	getCh    chan []Article | ||||||
| 	getCh chan []Article | 	retCh    chan *Article | ||||||
| 	list  []*Article | 	articles []*Article | ||||||
|  | 	wg       sync.WaitGroup | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // TODO: setCh | ||||||
|  | type TagList struct { | ||||||
|  | 	addCh chan string | ||||||
|  | 	getCh chan []string | ||||||
|  | 	tags  []string | ||||||
| 	wg    sync.WaitGroup | 	wg    sync.WaitGroup | ||||||
| } | } | ||||||
|  |  | ||||||
| func minArticleList() *ArticleList { | func initArticleList() *ArticleList { | ||||||
| 	return &ArticleList{ | 	return &ArticleList{ | ||||||
| 		addCh: make(chan *Article), | 		addCh: make(chan *Article), | ||||||
| 		delCh: make(chan uuid.UUID), | 		delCh: make(chan uuid.UUID), | ||||||
| 		retCh: make(chan *Article), |  | ||||||
| 		getCh: make(chan []Article), | 		getCh: make(chan []Article), | ||||||
|  | 		retCh: make(chan *Article), | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func (l *ArticleList) start() { | func initTagList() *TagList { | ||||||
| 	l.wg.Done() | 	return &TagList{ | ||||||
|  | 		addCh: make(chan string), | ||||||
|  | 		getCh: make(chan []string), | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (al *ArticleList) start() { | ||||||
|  | 	al.wg.Done() | ||||||
| 	for { | 	for { | ||||||
| 		select { | 		select { | ||||||
| 		case article := <-l.addCh: | 		case article := <-al.addCh: | ||||||
| 			l.list = append(l.list, article) | 			al.articles = append(al.articles, article) | ||||||
| 		case uuid := <-l.delCh: | 		case uuid := <-al.delCh: | ||||||
| 			for i, article := range l.list { | 			for i, article := range al.articles { | ||||||
| 				if article.UUID == uuid { | 				if article.UUID == uuid { | ||||||
| 					l.list = append(l.list[:i], l.list[i+1:]...) | 					al.articles = append(al.articles[:i], al.articles[i+1:]...) | ||||||
| 					l.retCh <- article | 					al.retCh <- article | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		case l.getCh <- func() []Article { | 		case al.getCh <- func() []Article { | ||||||
| 			var list []Article | 			var list []Article | ||||||
| 			for _, article := range l.list { | 			for _, article := range al.articles { | ||||||
| 				list = append(list, *article) | 				list = append(list, *article) | ||||||
| 			} | 			} | ||||||
| 			return list | 			return list | ||||||
| @@ -60,9 +79,20 @@ func (l *ArticleList) start() { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func (tl *TagList) start() { | ||||||
|  | 	tl.wg.Done() | ||||||
|  | 	for { | ||||||
|  | 		select { | ||||||
|  | 		case tag := <-tl.addCh: | ||||||
|  | 			tl.tags = append(tl.tags, tag) | ||||||
|  | 		case tl.getCh <- tl.tags: | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
| func NewArticleList() *ArticleList { | func NewArticleList() *ArticleList { | ||||||
| 	list := minArticleList() | 	list := initArticleList() | ||||||
| 	list.list = []*Article{} | 	list.articles = make([]*Article, 0) | ||||||
|  |  | ||||||
| 	list.wg.Add(1) | 	list.wg.Add(1) | ||||||
| 	go list.start() | 	go list.start() | ||||||
| @@ -71,19 +101,98 @@ func NewArticleList() *ArticleList { | |||||||
| 	return list | 	return list | ||||||
| } | } | ||||||
|  |  | ||||||
| func (l *ArticleList) Add(a *Article) { | func (al *ArticleList) Add(a *Article) { | ||||||
| 	l.addCh <- a | 	al.addCh <- a | ||||||
| } | } | ||||||
|  |  | ||||||
| func (l *ArticleList) Release(uuid uuid.UUID) (*Article, bool) { | func (al *ArticleList) Release(uuid uuid.UUID) (*Article, bool) { | ||||||
| 	l.delCh <- uuid | 	al.delCh <- uuid | ||||||
| 	article := <-l.retCh | 	article := <-al.retCh | ||||||
|  |  | ||||||
| 	if article == nil { | 	if article == nil { | ||||||
| 		return nil, false | 		return nil, false | ||||||
| 	} | 	} | ||||||
| 	return article, true | 	return article, true | ||||||
| } | } | ||||||
|  |  | ||||||
| func (l *ArticleList) Get() []Article { | func (al *ArticleList) Get() []Article { | ||||||
| 	return <-l.getCh | 	return <-al.getCh | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (al *ArticleList) Save(filename string) error { | ||||||
|  | 	file, err := os.Create(filename) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return fmt.Errorf("error creating key file: %v", err) | ||||||
|  | 	} | ||||||
|  | 	defer file.Close() | ||||||
|  |  | ||||||
|  | 	articles := al.Get() | ||||||
|  | 	if err = gob.NewEncoder(file).Encode(articles); err != nil { | ||||||
|  | 		return fmt.Errorf("error ecoding key: %v", err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func LoadArticleList(filename string) (*ArticleList, error) { | ||||||
|  | 	file, err := os.Open(filename) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, fmt.Errorf("error opening key file: %v", err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	articleList := NewArticleList() | ||||||
|  | 	if err = gob.NewDecoder(file).Decode(&articleList.articles); err != nil { | ||||||
|  | 		return nil, fmt.Errorf("error decoding key: %v", err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return articleList, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func NewTagList() *TagList { | ||||||
|  | 	list := initTagList() | ||||||
|  | 	list.tags = make([]string, 0) | ||||||
|  |  | ||||||
|  | 	list.wg.Add(1) | ||||||
|  | 	go list.start() | ||||||
|  | 	list.wg.Wait() | ||||||
|  |  | ||||||
|  | 	return list | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (tl *TagList) Add(tag string) { | ||||||
|  | 	tl.addCh <- tag | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (tl *TagList) Get() []string { | ||||||
|  | 	return <-tl.getCh | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (tl *TagList) Save(filename string) error { | ||||||
|  | 	file, err := os.Create(filename) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return fmt.Errorf("error creating key file: %v", err) | ||||||
|  | 	} | ||||||
|  | 	defer file.Close() | ||||||
|  |  | ||||||
|  | 	tags := tl.Get() | ||||||
|  | 	if err = gob.NewEncoder(file).Encode(tags); err != nil { | ||||||
|  | 		return fmt.Errorf("error ecoding key: %v", err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func LoadTagList(filename string) (*TagList, error) { | ||||||
|  | 	file, err := os.Open(filename) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, fmt.Errorf("error opening key file: %v", err) | ||||||
|  | 	} | ||||||
|  | 	defer file.Close() | ||||||
|  |  | ||||||
|  | 	tagList := NewTagList() | ||||||
|  | 	if err = gob.NewDecoder(file).Decode(&tagList.tags); err != nil { | ||||||
|  | 		return nil, fmt.Errorf("error decoding key: %v", err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return tagList, nil | ||||||
| } | } | ||||||
|   | |||||||
| @@ -34,7 +34,7 @@ func OpenDB(dbName string) (*DB, error) { | |||||||
| 	return &db, nil | 	return &db, nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func (db *DB) AddUser(user User, pass string) error { | func (db *DB) AddUser(user *User, pass string) error { | ||||||
| 	hashedPass, err := bcrypt.GenerateFromPassword([]byte(pass), bcrypt.DefaultCost) | 	hashedPass, err := bcrypt.GenerateFromPassword([]byte(pass), bcrypt.DefaultCost) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return fmt.Errorf("error creating password hash: %v", err) | 		return fmt.Errorf("error creating password hash: %v", err) | ||||||
| @@ -45,8 +45,7 @@ func (db *DB) AddUser(user User, pass string) error { | |||||||
|         (username, password, first_name, last_name, role) |         (username, password, first_name, last_name, role) | ||||||
|     VALUES (?, ?, ?, ?, ?) |     VALUES (?, ?, ?, ?, ?) | ||||||
|     ` |     ` | ||||||
| 	_, err = db.Exec(query, user.UserName, string(hashedPass), user.FirstName, user.LastName, user.Role) | 	if _, err = db.Exec(query, user.UserName, string(hashedPass), user.FirstName, user.LastName, user.Role); err != nil { | ||||||
| 	if err != nil { |  | ||||||
| 		return fmt.Errorf("error inserting user into DB: %v", err) | 		return fmt.Errorf("error inserting user into DB: %v", err) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -104,8 +103,7 @@ func (db *DB) ChangePassword(id int64, oldPass, newPass string) error { | |||||||
|     SET password = ? |     SET password = ? | ||||||
|     WHERE id = ? |     WHERE id = ? | ||||||
|     ` |     ` | ||||||
| 	_, err = db.Exec(query, string(newHashedPass), id) | 	if _, err = db.Exec(query, string(newHashedPass), id); err != nil { | ||||||
| 	if err != nil { |  | ||||||
| 		return fmt.Errorf("error updating password in DB: %v", err) | 		return fmt.Errorf("error updating password in DB: %v", err) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -134,8 +132,7 @@ func (db *DB) GetUser(id int64) (*User, error) { | |||||||
|     ` |     ` | ||||||
|  |  | ||||||
| 	row := db.QueryRow(query, id) | 	row := db.QueryRow(query, id) | ||||||
| 	if err := row.Scan(&user.ID, &user.UserName, &user.FirstName, | 	if err := row.Scan(&user.ID, &user.UserName, &user.FirstName, &user.LastName, &user.Role); err != nil { | ||||||
| 		&user.LastName, &user.Role); err != nil { |  | ||||||
| 		return nil, fmt.Errorf("error reading user information: %v", err) | 		return nil, fmt.Errorf("error reading user information: %v", err) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|   | |||||||
| @@ -6,101 +6,99 @@ import ( | |||||||
| 	"os" | 	"os" | ||||||
| 	"sync" | 	"sync" | ||||||
|  |  | ||||||
| 	"github.com/gorilla/feeds" | 	"git.streifling.com/jason/rss" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type Feed struct { | type Channel struct { | ||||||
| 	addCh chan *feeds.Item | 	addCh   chan *rss.Item | ||||||
| 	setCh chan feeds.Feed | 	setCh   chan rss.Channel | ||||||
| 	getCh chan feeds.Feed | 	getCh   chan rss.Channel | ||||||
| 	feed  feeds.Feed | 	channel rss.Channel | ||||||
| 	wg    sync.WaitGroup | 	wg      sync.WaitGroup | ||||||
| } | } | ||||||
|  |  | ||||||
| func minFeed() *Feed { | func initChannel() *Channel { | ||||||
| 	return &Feed{ | 	return &Channel{ | ||||||
| 		addCh: make(chan *feeds.Item), | 		addCh: make(chan *rss.Item), | ||||||
| 		setCh: make(chan feeds.Feed), | 		setCh: make(chan rss.Channel), | ||||||
| 		getCh: make(chan feeds.Feed), | 		getCh: make(chan rss.Channel), | ||||||
|  | 		channel: rss.Channel{ | ||||||
|  | 			Items: make([]*rss.Item, 0), | ||||||
|  | 		}, | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func (f *Feed) start() { | func (c *Channel) start() { | ||||||
| 	f.wg.Done() | 	c.wg.Done() | ||||||
| 	for { | 	for { | ||||||
| 		select { | 		select { | ||||||
| 		case item := <-f.addCh: | 		case item := <-c.addCh: | ||||||
| 			f.feed.Items = append(f.feed.Items, item) | 			c.channel.Items = append(c.channel.Items, item) | ||||||
| 		case f.getCh <- f.feed: | 		case c.getCh <- c.channel: | ||||||
| 		case f.feed = <-f.setCh: | 		case c.channel = <-c.setCh: | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func NewFeed(title, link, desc string) *Feed { | func NewChannel(title, link, desc string) *Channel { | ||||||
| 	feed := minFeed() | 	channel := initChannel() | ||||||
| 	feed.feed = feeds.Feed{ | 	channel.channel = rss.Channel{ | ||||||
| 		Title:       title, | 		Title:       title, | ||||||
| 		Link:        &feeds.Link{Href: link}, | 		Link:        link, | ||||||
| 		Description: desc, | 		Description: desc, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	feed.wg.Add(1) | 	channel.wg.Add(1) | ||||||
| 	go feed.start() | 	go channel.start() | ||||||
| 	feed.wg.Wait() | 	channel.wg.Wait() | ||||||
|  |  | ||||||
| 	return feed | 	return channel | ||||||
| } | } | ||||||
|  |  | ||||||
| func (f *Feed) Get() feeds.Feed { | func (c *Channel) Get() rss.Channel { | ||||||
| 	return <-f.getCh | 	return <-c.getCh | ||||||
| } | } | ||||||
|  |  | ||||||
| func (f *Feed) Set(feed feeds.Feed) { | func (f *Channel) Set(channel rss.Channel) { | ||||||
| 	f.setCh <- feed | 	f.setCh <- channel | ||||||
| } | } | ||||||
|  |  | ||||||
| func OpenFeed(filename string) (*Feed, error) { | func LoadChannel(filename string) (*Channel, error) { | ||||||
| 	file, err := os.Open(filename) | 	file, err := os.Open(filename) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, fmt.Errorf("error opening file %v: %v", filename, err) | 		return nil, fmt.Errorf("error opening file %v: %v", filename, err) | ||||||
| 	} | 	} | ||||||
| 	defer file.Close() | 	defer file.Close() | ||||||
|  |  | ||||||
| 	feed := minFeed() | 	channel := initChannel() | ||||||
| 	feed.wg.Add(1) | 	channel.wg.Add(1) | ||||||
| 	go feed.start() | 	go channel.start() | ||||||
| 	feed.wg.Wait() | 	channel.wg.Wait() | ||||||
|  |  | ||||||
| 	decoder := gob.NewDecoder(file) | 	tmpChannel := new(rss.Channel) | ||||||
| 	tmpFeed := new(feeds.Feed) | 	if err = gob.NewDecoder(file).Decode(tmpChannel); err != nil { | ||||||
| 	err = decoder.Decode(tmpFeed) | 		return nil, fmt.Errorf("error decoding channel from file %v: %v", filename, err) | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, fmt.Errorf("error decoding file %v: %v", filename, err) |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	feed.Set(*tmpFeed) | 	channel.Set(*tmpChannel) | ||||||
|  | 	return channel, nil | ||||||
| 	return feed, nil |  | ||||||
| } | } | ||||||
|  |  | ||||||
| func (f *Feed) Save(filename string) error { | func (c *Channel) 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) | ||||||
| 	} | 	} | ||||||
| 	defer file.Close() | 	defer file.Close() | ||||||
|  |  | ||||||
| 	encoder := gob.NewEncoder(file) | 	channel := c.Get() | ||||||
| 	feed := f.Get() | 	if err = gob.NewEncoder(file).Encode(channel); err != nil { | ||||||
| 	err = encoder.Encode(feed) |  | ||||||
| 	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) { | func (c *Channel) Add(i *rss.Item) { | ||||||
| 	f.addCh <- i | 	c.addCh <- i | ||||||
| } | } | ||||||
|   | |||||||
| @@ -17,8 +17,7 @@ type CookieStore struct { | |||||||
| func NewKey() ([]byte, error) { | func NewKey() ([]byte, error) { | ||||||
| 	key := make([]byte, 32) | 	key := make([]byte, 32) | ||||||
|  |  | ||||||
| 	_, err := io.ReadFull(rand.Reader, key) | 	if _, err := io.ReadFull(rand.Reader, key); err != nil { | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, fmt.Errorf("error generating key: %v", err) | 		return nil, fmt.Errorf("error generating key: %v", err) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -33,9 +32,7 @@ func SaveKey(key []byte, filename string) error { | |||||||
| 	defer file.Close() | 	defer file.Close() | ||||||
| 	file.Chmod(0600) | 	file.Chmod(0600) | ||||||
|  |  | ||||||
| 	encoder := gob.NewEncoder(file) | 	if err = gob.NewEncoder(file).Encode(key); err != nil { | ||||||
| 	err = encoder.Encode(key) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return fmt.Errorf("error ecoding key: %v", err) | 		return fmt.Errorf("error ecoding key: %v", err) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -49,9 +46,7 @@ func LoadKey(filename string) ([]byte, error) { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	key := make([]byte, 32) | 	key := make([]byte, 32) | ||||||
| 	decoder := gob.NewDecoder(file) | 	if err = gob.NewDecoder(file).Decode(&key); err != nil { | ||||||
| 	err = decoder.Decode(&key) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, fmt.Errorf("error decoding key: %v", err) | 		return nil, fmt.Errorf("error decoding key: %v", err) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|   | |||||||
| @@ -11,11 +11,11 @@ import ( | |||||||
| ) | ) | ||||||
|  |  | ||||||
| type AddUserData struct { | type AddUserData struct { | ||||||
|  | 	*data.User | ||||||
| 	Msg string | 	Msg string | ||||||
| 	data.User |  | ||||||
| } | } | ||||||
|  |  | ||||||
| func inputsEmpty(user data.User, pass, pass2 string) bool { | func inputsEmpty(user *data.User, pass, pass2 string) bool { | ||||||
| 	return len(user.UserName) == 0 || | 	return len(user.UserName) == 0 || | ||||||
| 		len(user.FirstName) == 0 || | 		len(user.FirstName) == 0 || | ||||||
| 		len(user.LastName) == 0 || | 		len(user.LastName) == 0 || | ||||||
| @@ -23,7 +23,7 @@ func inputsEmpty(user data.User, pass, pass2 string) bool { | |||||||
| 		len(pass2) == 0 | 		len(pass2) == 0 | ||||||
| } | } | ||||||
|  |  | ||||||
| func checkUserStrings(user data.User) (string, int, bool) { | func checkUserStrings(user *data.User) (string, int, bool) { | ||||||
| 	userLen := 15 | 	userLen := 15 | ||||||
| 	nameLen := 50 | 	nameLen := 50 | ||||||
|  |  | ||||||
| @@ -38,14 +38,12 @@ func checkUserStrings(user data.User) (string, int, bool) { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func CreateUser() 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("web/templates/add-user.html") | 	template.Must(tmpl, err).ExecuteTemplate(w, "page-content", nil) | ||||||
| 		template.Must(tmpl, err).ExecuteTemplate(w, "page-content", nil) |  | ||||||
| 	} |  | ||||||
| } | } | ||||||
|  |  | ||||||
| func AddUser(db *data.DB) http.HandlerFunc { | func AddUser(db *data.DB, s *data.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 { | ||||||
| @@ -55,7 +53,7 @@ func AddUser(db *data.DB) http.HandlerFunc { | |||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		htmlData := AddUserData{ | 		htmlData := AddUserData{ | ||||||
| 			User: data.User{ | 			User: &data.User{ | ||||||
| 				UserName:  r.PostFormValue("username"), | 				UserName:  r.PostFormValue("username"), | ||||||
| 				FirstName: r.PostFormValue("first-name"), | 				FirstName: r.PostFormValue("first-name"), | ||||||
| 				LastName:  r.PostFormValue("last-name"), | 				LastName:  r.PostFormValue("last-name"), | ||||||
| @@ -94,12 +92,36 @@ func AddUser(db *data.DB) http.HandlerFunc { | |||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | 		num, err := db.CountEntries() | ||||||
|  | 		if err != nil { | ||||||
|  | 			log.Println(err) | ||||||
|  | 			http.Error(w, err.Error(), http.StatusInternalServerError) | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 		if num == 0 { | ||||||
|  | 			if htmlData.Role != data.Admin { | ||||||
|  | 				htmlData.Msg = "Der erste Benutzer muss ein Administrator sein." | ||||||
|  | 				htmlData.Role = data.Admin | ||||||
|  | 				tmpl, err := template.ParseFiles("web/templates/add-user.html") | ||||||
|  | 				tmpl = template.Must(tmpl, err) | ||||||
|  | 				tmpl.ExecuteTemplate(w, "page-content", htmlData) | ||||||
|  | 				return | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			if err := saveSession(w, r, s, htmlData.User); err != nil { | ||||||
|  | 				log.Println(err) | ||||||
|  | 				http.Error(w, err.Error(), http.StatusInternalServerError) | ||||||
|  | 				return | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		if err := db.AddUser(htmlData.User, pass); err != nil { | 		if err := db.AddUser(htmlData.User, pass); 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("web/templates/hub.html") | 		tmpl, err := template.ParseFiles("web/templates/hub.html") | ||||||
| 		template.Must(tmpl, err).ExecuteTemplate(w, "page-content", nil) | 		template.Must(tmpl, err).ExecuteTemplate(w, "page-content", 0) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|   | |||||||
| @@ -6,8 +6,8 @@ import ( | |||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
|  | 	"git.streifling.com/jason/rss" | ||||||
| 	"github.com/google/uuid" | 	"github.com/google/uuid" | ||||||
| 	"github.com/gorilla/feeds" |  | ||||||
| 	"streifling.com/jason/cpolis/cmd/data" | 	"streifling.com/jason/cpolis/cmd/data" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -25,12 +25,14 @@ func ShowHub(s *data.CookieStore) http.HandlerFunc { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func WriteArticle(w http.ResponseWriter, r *http.Request) { | func WriteArticle(tl *data.TagList) http.HandlerFunc { | ||||||
| 	tmpl, err := template.ParseFiles("web/templates/editor.html") | 	return func(w http.ResponseWriter, r *http.Request) { | ||||||
| 	template.Must(tmpl, err).ExecuteTemplate(w, "page-content", nil) | 		tmpl, err := template.ParseFiles("web/templates/editor.html") | ||||||
|  | 		template.Must(tmpl, err).ExecuteTemplate(w, "page-content", tl.Get()) | ||||||
|  | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func FinishArticle(l *data.ArticleList, s *data.CookieStore) http.HandlerFunc { | func FinishArticle(al *data.ArticleList, s *data.CookieStore) http.HandlerFunc { | ||||||
| 	return func(w http.ResponseWriter, r *http.Request) { | 	return func(w http.ResponseWriter, r *http.Request) { | ||||||
| 		article := new(data.Article) | 		article := new(data.Article) | ||||||
| 		var err error | 		var err error | ||||||
| @@ -56,6 +58,9 @@ func FinishArticle(l *data.ArticleList, s *data.CookieStore) http.HandlerFunc { | |||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | 		r.ParseForm() | ||||||
|  | 		article.Tags = append(article.Tags, r.Form["tags"]...) | ||||||
|  |  | ||||||
| 		session, err := s.Get(r, "cookie") | 		session, err := s.Get(r, "cookie") | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			tmpl, err := template.ParseFiles("web/templates/login.html") | 			tmpl, err := template.ParseFiles("web/templates/login.html") | ||||||
| @@ -68,7 +73,8 @@ func FinishArticle(l *data.ArticleList, s *data.CookieStore) http.HandlerFunc { | |||||||
| 		article.Created = time.Now() | 		article.Created = time.Now() | ||||||
| 		article.AuthorID = session.Values["id"].(int64) | 		article.AuthorID = session.Values["id"].(int64) | ||||||
|  |  | ||||||
| 		l.Add(article) | 		al.Add(article) | ||||||
|  | 		al.Save("tmp/unpublished-articles.gob") | ||||||
|  |  | ||||||
| 		tmpl, err := template.ParseFiles("web/templates/hub.html") | 		tmpl, err := template.ParseFiles("web/templates/hub.html") | ||||||
| 		tmpl = template.Must(tmpl, err) | 		tmpl = template.Must(tmpl, err) | ||||||
| @@ -76,14 +82,14 @@ func FinishArticle(l *data.ArticleList, s *data.CookieStore) http.HandlerFunc { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func ShowUnpublishedArticles(l *data.ArticleList) http.HandlerFunc { | func ShowUnpublishedArticles(al *data.ArticleList) http.HandlerFunc { | ||||||
| 	return func(w http.ResponseWriter, r *http.Request) { | 	return func(w http.ResponseWriter, r *http.Request) { | ||||||
| 		tmpl, err := template.ParseFiles("web/templates/unpublished-articles.html") | 		tmpl, err := template.ParseFiles("web/templates/unpublished-articles.html") | ||||||
| 		template.Must(tmpl, err).ExecuteTemplate(w, "page-content", l.Get()) | 		template.Must(tmpl, err).ExecuteTemplate(w, "page-content", al.Get()) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func ReviewArticle(l *data.ArticleList, s *data.CookieStore) http.HandlerFunc { | func ReviewArticle(al *data.ArticleList, s *data.CookieStore) http.HandlerFunc { | ||||||
| 	return func(w http.ResponseWriter, r *http.Request) { | 	return func(w http.ResponseWriter, r *http.Request) { | ||||||
| 		uuid, err := uuid.Parse(r.PostFormValue("uuid")) | 		uuid, err := uuid.Parse(r.PostFormValue("uuid")) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| @@ -92,7 +98,7 @@ func ReviewArticle(l *data.ArticleList, s *data.CookieStore) http.HandlerFunc { | |||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		for _, article := range l.Get() { | 		for _, article := range al.Get() { | ||||||
| 			if article.UUID == uuid { | 			if article.UUID == uuid { | ||||||
| 				tmpl, err := template.ParseFiles("web/templates/to-be-published.html") | 				tmpl, err := template.ParseFiles("web/templates/to-be-published.html") | ||||||
| 				template.Must(tmpl, err).ExecuteTemplate(w, "page-content", article) | 				template.Must(tmpl, err).ExecuteTemplate(w, "page-content", article) | ||||||
| @@ -113,7 +119,7 @@ func ReviewArticle(l *data.ArticleList, s *data.CookieStore) http.HandlerFunc { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func PublishArticle(f *data.Feed, l *data.ArticleList, s *data.CookieStore) http.HandlerFunc { | func PublishArticle(c *data.Channel, al *data.ArticleList, s *data.CookieStore) http.HandlerFunc { | ||||||
| 	return func(w http.ResponseWriter, r *http.Request) { | 	return func(w http.ResponseWriter, r *http.Request) { | ||||||
| 		uuid, err := uuid.Parse(r.PostFormValue("uuid")) | 		uuid, err := uuid.Parse(r.PostFormValue("uuid")) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| @@ -122,7 +128,7 @@ func PublishArticle(f *data.Feed, l *data.ArticleList, s *data.CookieStore) http | |||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		article, ok := l.Release(uuid) | 		article, ok := al.Release(uuid) | ||||||
| 		if !ok { | 		if !ok { | ||||||
| 			// TODO: Warnung anzeigen | 			// TODO: Warnung anzeigen | ||||||
| 			// msg = "Alle Felder müssen ausgefüllt werden." | 			// msg = "Alle Felder müssen ausgefüllt werden." | ||||||
| @@ -131,14 +137,6 @@ func PublishArticle(f *data.Feed, l *data.ArticleList, s *data.CookieStore) http | |||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		f.Add(&feeds.Item{ |  | ||||||
| 			Title:       article.Title, |  | ||||||
| 			Created:     article.Created, |  | ||||||
| 			Description: article.Desc, |  | ||||||
| 			Content:     article.Content, |  | ||||||
| 		}) |  | ||||||
| 		f.Save("tmp/rss.gob") |  | ||||||
|  |  | ||||||
| 		session, err := s.Get(r, "cookie") | 		session, err := s.Get(r, "cookie") | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			tmpl, err := template.ParseFiles("web/templates/login.html") | 			tmpl, err := template.ParseFiles("web/templates/login.html") | ||||||
| @@ -146,6 +144,16 @@ func PublishArticle(f *data.Feed, l *data.ArticleList, s *data.CookieStore) http | |||||||
| 			template.Must(tmpl, err).ExecuteTemplate(w, "page-content", msg) | 			template.Must(tmpl, err).ExecuteTemplate(w, "page-content", msg) | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | 		c.Add(&rss.Item{ | ||||||
|  | 			Title:       article.Title, | ||||||
|  | 			Author:      session.Values["name"].(string), | ||||||
|  | 			PubDate:     article.Created.Format(time.RFC1123Z), | ||||||
|  | 			Description: article.Desc, | ||||||
|  | 			Content:     &rss.Content{Value: article.Content}, | ||||||
|  | 			Categories:  article.Tags, | ||||||
|  | 		}) | ||||||
|  | 		c.Save("tmp/rss.gob") | ||||||
|  |  | ||||||
| 		tmpl, err := template.ParseFiles("web/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"]) | ||||||
|   | |||||||
							
								
								
									
										31
									
								
								cmd/ui/editor.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								cmd/ui/editor.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | |||||||
|  | package ui | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"html/template" | ||||||
|  | 	"net/http" | ||||||
|  |  | ||||||
|  | 	"streifling.com/jason/cpolis/cmd/data" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | 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(tl *data.TagList, s *data.CookieStore) http.HandlerFunc { | ||||||
|  | 	return func(w http.ResponseWriter, r *http.Request) { | ||||||
|  | 		tl.Add(r.PostFormValue("tag")) | ||||||
|  | 		tl.Save("tmp/tags.gob") | ||||||
|  |  | ||||||
|  | 		session, err := s.Get(r, "cookie") | ||||||
|  | 		if err != nil { | ||||||
|  | 			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("web/templates/hub.html") | ||||||
|  | 		tmpl = template.Must(tmpl, err) | ||||||
|  | 		tmpl.ExecuteTemplate(w, "page-content", session.Values["role"]) | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @@ -5,13 +5,16 @@ import ( | |||||||
| 	"log" | 	"log" | ||||||
| 	"net/http" | 	"net/http" | ||||||
|  |  | ||||||
|  | 	"git.streifling.com/jason/rss" | ||||||
| 	"streifling.com/jason/cpolis/cmd/data" | 	"streifling.com/jason/cpolis/cmd/data" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func ShowRSS(f *data.Feed) http.HandlerFunc { | func ShowRSS(c *data.Channel) http.HandlerFunc { | ||||||
| 	return func(w http.ResponseWriter, r *http.Request) { | 	return func(w http.ResponseWriter, r *http.Request) { | ||||||
| 		feed := f.Get() | 		channel := c.Get() | ||||||
| 		rss, err := feed.ToRss() | 		feed := rss.NewFeed() | ||||||
|  | 		feed.Channels = append(feed.Channels, &channel) | ||||||
|  | 		rss, err := feed.ToXML() | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			log.Println(err) | 			log.Println(err) | ||||||
| 			http.Error(w, err.Error(), http.StatusInternalServerError) | 			http.Error(w, err.Error(), http.StatusInternalServerError) | ||||||
|   | |||||||
| @@ -1,6 +1,7 @@ | |||||||
| package ui | package ui | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
|  | 	"fmt" | ||||||
| 	"html/template" | 	"html/template" | ||||||
| 	"log" | 	"log" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| @@ -8,6 +9,23 @@ import ( | |||||||
| 	"streifling.com/jason/cpolis/cmd/data" | 	"streifling.com/jason/cpolis/cmd/data" | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  | func saveSession(w http.ResponseWriter, r *http.Request, s *data.CookieStore, u *data.User) error { | ||||||
|  | 	session, err := s.Get(r, "cookie") | ||||||
|  | 	if err != nil { | ||||||
|  | 		return fmt.Errorf("error getting session: %v", err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	session.Values["authenticated"] = true | ||||||
|  | 	session.Values["id"] = u.ID | ||||||
|  | 	session.Values["name"] = u.FirstName + u.LastName | ||||||
|  | 	session.Values["role"] = u.Role | ||||||
|  | 	if err := session.Save(r, w); err != nil { | ||||||
|  | 		return fmt.Errorf("error saving session: %v", err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
| func HomePage(db *data.DB, s *data.CookieStore) http.HandlerFunc { | func HomePage(db *data.DB, s *data.CookieStore) http.HandlerFunc { | ||||||
| 	return func(w http.ResponseWriter, r *http.Request) { | 	return func(w http.ResponseWriter, r *http.Request) { | ||||||
| 		numRows, err := db.CountEntries() | 		numRows, err := db.CountEntries() | ||||||
| @@ -60,18 +78,7 @@ func Login(db *data.DB, s *data.CookieStore) http.HandlerFunc { | |||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		session, err := s.Get(r, "cookie") | 		if err := saveSession(w, r, s, user); err != nil { | ||||||
| 		if err != nil { |  | ||||||
| 			log.Println(err) |  | ||||||
| 			http.Error(w, err.Error(), http.StatusBadRequest) |  | ||||||
| 			return |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		session.Values["authenticated"] = true |  | ||||||
| 		session.Values["id"] = user.ID |  | ||||||
| 		session.Values["name"] = user.FirstName + user.LastName |  | ||||||
| 		session.Values["role"] = user.Role |  | ||||||
| 		if err := session.Save(r, w); err != nil { |  | ||||||
| 			log.Println(err) | 			log.Println(err) | ||||||
| 			http.Error(w, err.Error(), http.StatusInternalServerError) | 			http.Error(w, err.Error(), http.StatusInternalServerError) | ||||||
| 			return | 			return | ||||||
|   | |||||||
							
								
								
									
										1
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								go.mod
									
									
									
									
									
								
							| @@ -3,6 +3,7 @@ module streifling.com/jason/cpolis | |||||||
| go 1.22.0 | go 1.22.0 | ||||||
|  |  | ||||||
| require ( | require ( | ||||||
|  | 	git.streifling.com/jason/rss v0.0.0-20240305164907-524bf9676188 | ||||||
| 	github.com/go-sql-driver/mysql v1.7.1 | 	github.com/go-sql-driver/mysql v1.7.1 | ||||||
| 	github.com/google/uuid v1.6.0 | 	github.com/google/uuid v1.6.0 | ||||||
| 	github.com/gorilla/feeds v1.1.2 | 	github.com/gorilla/feeds v1.1.2 | ||||||
|   | |||||||
							
								
								
									
										8
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								go.sum
									
									
									
									
									
								
							| @@ -1,3 +1,11 @@ | |||||||
|  | git.streifling.com/jason/rss v0.0.0-20240305152729-9d8cc6464565 h1:/eO9NTksh+9yLz3HiYNR7BJo/iMTxxW5/d9h8I6vR6E= | ||||||
|  | git.streifling.com/jason/rss v0.0.0-20240305152729-9d8cc6464565/go.mod h1:gpZF0nZbQSstMpyHD9DTAvlQEG7v4pjO5c7aIMWM4Jg= | ||||||
|  | git.streifling.com/jason/rss v0.0.0-20240305160544-c8551159fe32 h1:G25NZzsD73rOkGYgV2vPUDviB0JXk5qi+dXOwB6J56U= | ||||||
|  | git.streifling.com/jason/rss v0.0.0-20240305160544-c8551159fe32/go.mod h1:gpZF0nZbQSstMpyHD9DTAvlQEG7v4pjO5c7aIMWM4Jg= | ||||||
|  | git.streifling.com/jason/rss v0.0.0-20240305160829-6cd08bb65d2a h1:TWQ9gwe7eWjaLUrZ0CJSc+sUUOw3VoGHlR3F8mH6vqs= | ||||||
|  | git.streifling.com/jason/rss v0.0.0-20240305160829-6cd08bb65d2a/go.mod h1:gpZF0nZbQSstMpyHD9DTAvlQEG7v4pjO5c7aIMWM4Jg= | ||||||
|  | git.streifling.com/jason/rss v0.0.0-20240305164907-524bf9676188 h1:C8M/j3f+cl5Y7YfGpU/ynb/SC/4tTYMDsyGFt3rswM8= | ||||||
|  | git.streifling.com/jason/rss v0.0.0-20240305164907-524bf9676188/go.mod h1:gpZF0nZbQSstMpyHD9DTAvlQEG7v4pjO5c7aIMWM4Jg= | ||||||
| github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= | github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= | ||||||
| github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= | 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 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= | ||||||
|   | |||||||
							
								
								
									
										27
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										27
									
								
								main.go
									
									
									
									
									
								
							| @@ -15,7 +15,8 @@ func init() { | |||||||
| } | } | ||||||
|  |  | ||||||
| func main() { | func main() { | ||||||
| 	logFile, err := os.Create("tmp/cpolis.log") | 	logFile, err := os.OpenFile("tmp/cpolis.log", | ||||||
|  | 		os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		log.Fatalln(err) | 		log.Fatalln(err) | ||||||
| 	} | 	} | ||||||
| @@ -28,10 +29,10 @@ func main() { | |||||||
| 	} | 	} | ||||||
| 	defer db.Close() | 	defer db.Close() | ||||||
|  |  | ||||||
| 	feed, err := data.OpenFeed("tmp/rss.gob") | 	feed, err := data.LoadChannel("tmp/rss.gob") | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		log.Println(err) | 		log.Println(err) | ||||||
| 		feed = data.NewFeed("Freimaurer Distrikt Niedersachsen und Sachsen-Anhalt", | 		feed = data.NewChannel("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") | ||||||
| 	} | 	} | ||||||
| @@ -46,23 +47,33 @@ func main() { | |||||||
| 	} | 	} | ||||||
| 	store := data.NewCookieStore(key) | 	store := data.NewCookieStore(key) | ||||||
|  |  | ||||||
| 	articleList := data.NewArticleList() | 	articleList, err := data.LoadArticleList("tmp/unpublished-articles.gob") | ||||||
|  | 	if err != nil { | ||||||
|  | 		articleList = data.NewArticleList() | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	tagList, err := data.LoadTagList("tmp/tags.gob") | ||||||
|  | 	if err != nil { | ||||||
|  | 		tagList = data.NewTagList() | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	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/")))) | ||||||
| 	mux.HandleFunc("/", ui.HomePage(db, store)) | 	mux.HandleFunc("/", ui.HomePage(db, store)) | ||||||
|  |  | ||||||
|  | 	mux.HandleFunc("GET /create-tag/", ui.CreateTag) | ||||||
|  | 	mux.HandleFunc("GET /create-user/", ui.CreateUser) | ||||||
| 	mux.HandleFunc("GET /hub/", ui.ShowHub(store)) | 	mux.HandleFunc("GET /hub/", ui.ShowHub(store)) | ||||||
| 	mux.HandleFunc("GET /rss/", ui.ShowRSS(feed)) | 	mux.HandleFunc("GET /rss/", ui.ShowRSS(feed)) | ||||||
|  | 	mux.HandleFunc("GET /unpublished-articles/", ui.ShowUnpublishedArticles(articleList)) | ||||||
|  | 	mux.HandleFunc("GET /write-article/", ui.WriteArticle(tagList)) | ||||||
|  |  | ||||||
| 	mux.HandleFunc("POST /add-user/", ui.AddUser(db)) | 	mux.HandleFunc("POST /add-tag/", ui.AddTag(tagList, store)) | ||||||
| 	mux.HandleFunc("POST /create-user/", ui.CreateUser()) | 	mux.HandleFunc("POST /add-user/", ui.AddUser(db, store)) | ||||||
| 	mux.HandleFunc("POST /finish-article/", ui.FinishArticle(articleList, store)) | 	mux.HandleFunc("POST /finish-article/", ui.FinishArticle(articleList, store)) | ||||||
| 	mux.HandleFunc("POST /login/", ui.Login(db, store)) | 	mux.HandleFunc("POST /login/", ui.Login(db, store)) | ||||||
| 	mux.HandleFunc("POST /review-article/", ui.ReviewArticle(articleList, store)) | 	mux.HandleFunc("POST /review-article/", ui.ReviewArticle(articleList, store)) | ||||||
| 	mux.HandleFunc("POST /publish-article/", ui.PublishArticle(feed, articleList, store)) | 	mux.HandleFunc("POST /publish-article/", ui.PublishArticle(feed, articleList, store)) | ||||||
| 	mux.HandleFunc("POST /unpublished-articles/", ui.ShowUnpublishedArticles(articleList)) |  | ||||||
| 	mux.HandleFunc("POST /write-article/", ui.WriteArticle) |  | ||||||
|  |  | ||||||
| 	log.Fatalln(http.ListenAndServe(":8080", mux)) | 	log.Fatalln(http.ListenAndServe(":8080", mux)) | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										8
									
								
								web/templates/add-tag.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								web/templates/add-tag.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +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}} | ||||||
| @@ -8,15 +8,16 @@ | |||||||
|     <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}}" /> | ||||||
|  |  | ||||||
|  |     <input required id="writer" name="role" type="radio" value="2" {{if eq .Role 2 }}checked{{end}} /> | ||||||
|     <label for="writer">Schreiber</label> |     <label for="writer">Schreiber</label> | ||||||
|     <input required id="writer" name="role" type="radio" value="2" {{if eq .Role "2" }}checked{{end}} /> |     <input required id="editor" name="role" type="radio" value="1" {{if eq .Role 1 }}checked{{end}} /> | ||||||
|     <label for="editor">Redakteur</label> |     <label for="editor">Redakteur</label> | ||||||
|     <input required id="editor" name="role" type="radio" value="1" {{if eq .Role "1" }}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> | ||||||
|     <input required id="admin" name="role" type="radio" value="0" {{if eq .Role "0" }}checked{{end}} /> |  | ||||||
|  |  | ||||||
|     <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> | ||||||
|  |  | ||||||
| <script> | <script> | ||||||
|     var msg = "{{.Msg}}"; |     var msg = "{{.Msg}}"; | ||||||
|   | |||||||
| @@ -4,6 +4,10 @@ | |||||||
|     <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> | ||||||
|  |     {{range .}} | ||||||
|  |     <input id="{{.}}" name="tags" type="checkbox" value="{{.}}" /> | ||||||
|  |     <label for="{{.}}">{{.}}</label> | ||||||
|  |     {{end}} | ||||||
|     <input type="submit" value="Senden" hx-post="/finish-article/" hx-target="#page-content" /> |     <input type="submit" value="Senden" hx-post="/finish-article/" hx-target="#page-content" /> | ||||||
| </form> | </form> | ||||||
| {{end}} | {{end}} | ||||||
|   | |||||||
| @@ -1,11 +1,12 @@ | |||||||
| {{define "page-content"}} | {{define "page-content"}} | ||||||
| <h2>Hub</h2> | <h2>Hub</h2> | ||||||
| <button hx-post="/write-article/" hx-target="#page-content">Artikel schreiben</button> | <button hx-get="/write-article/" hx-target="#page-content">Artikel schreiben</button> | ||||||
| <button hx-post="/rss/" hx-target="#page-content">RSS Feed</button> | <button hx-get="/rss/" hx-target="#page-content">RSS Feed</button> | ||||||
| {{if eq . 0}} |  | ||||||
| <button hx-post="/create-user/" hx-target="#page-content">Benutzer hinzufügen</button> |  | ||||||
| {{end}} |  | ||||||
| {{if lt . 2}} | {{if lt . 2}} | ||||||
| <button hx-post="/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> | ||||||
|  | {{end}} | ||||||
|  | {{if eq . 0}} | ||||||
|  | <button hx-get="/create-user/" hx-target="#page-content">Benutzer hinzufügen</button> | ||||||
| {{end}} | {{end}} | ||||||
| {{end}} | {{end}} | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user