Compare commits

..

29 Commits

Author SHA1 Message Date
93bc38db67 Try out different rss package 2024-03-05 16:04:49 +01:00
b74036343f Added partial support for tags 2024-03-03 13:56:49 +01:00
45036fe286 Initial sessions implementation 2024-03-03 09:16:49 +01:00
8f7ac979a3 Just a bit of cleaning up 2024-03-02 09:09:55 +01:00
2da17014e4 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
4e2cae74bb Changed articles and rss to channels 2024-03-01 21:01:38 +01:00
4b5929911e Implemented proper User struct 2024-03-01 12:25:53 +01:00
f59321b9c6 Added ability to publish articles 2024-03-01 11:30:31 +01:00
cba3c663c9 Added article list for written but non-published articles 2024-02-27 14:10:27 +01:00
59029c86a9 Convert title and description to plain text 2024-02-27 09:03:21 +01:00
8f5739fb68 Implemented hub 2024-02-24 15:31:33 +01:00
49988edd82 Add ability to display feed 2024-02-24 14:49:29 +01:00
36f7a92a06 Added messages and field memory for adding user 2024-02-24 13:25:32 +01:00
f716e9f0b5 Require all fields to be filled out when creating a new user 2024-02-24 12:10:34 +01:00
f3c8cd6fa5 Implemented logging to file 2024-02-24 11:41:01 +01:00
280e88a526 Check if user already exists and bug fix 2024-02-24 10:56:12 +01:00
8ef6b6472d Added ability to add user 2024-02-24 10:28:12 +01:00
2e08600814 Added ability to login 2024-02-24 09:54:25 +01:00
068bf045a7 Check user credentials before adding user 2024-02-22 20:12:09 +01:00
96fe38726c Added ability to update Passwords 2024-02-22 19:27:41 +01:00
75a21eeb9f Added ability to add user 2024-02-22 18:49:51 +01:00
6020b24e44 Changed error messages 2024-02-22 15:23:29 +01:00
ebfe01069c Added HTML sanitizer 2024-02-22 15:22:45 +01:00
5d41543543 Added initial support for MySQL databases 2024-02-18 16:37:13 +01:00
2ccc9c7397 Handle misssed errors for encoding and decoding feeds 2024-02-18 14:31:28 +01:00
c5623fe4fd Added description and a way to save and restore the RSS feed. 2024-02-18 14:01:06 +01:00
ee04a2a351 Create RSS from HTML 2024-02-18 12:41:49 +01:00
aa034701df Show HTML on website 2024-02-18 10:48:37 +01:00
ad9bfb2439 First implementation of web based editor to HTML pipeline 2024-02-18 10:07:49 +01:00
8 changed files with 47 additions and 140 deletions

View File

@ -11,12 +11,12 @@ import (
) )
type Article struct { type Article struct {
Tags *TagList
Title string Title string
Author string Author string
Created time.Time Created time.Time
Desc string Desc string
Content string Content string
Tags []string
UUID uuid.UUID UUID uuid.UUID
AuthorID int64 AuthorID int64
} }
@ -37,7 +37,7 @@ type TagList struct {
wg sync.WaitGroup wg sync.WaitGroup
} }
func initArticleList() *ArticleList { func minArticleList() *ArticleList {
return &ArticleList{ return &ArticleList{
addCh: make(chan *Article), addCh: make(chan *Article),
delCh: make(chan uuid.UUID), delCh: make(chan uuid.UUID),
@ -46,7 +46,7 @@ func initArticleList() *ArticleList {
} }
} }
func initTagList() *TagList { func minTagList() *TagList {
return &TagList{ return &TagList{
addCh: make(chan string), addCh: make(chan string),
getCh: make(chan []string), getCh: make(chan []string),
@ -89,7 +89,7 @@ func (tl *TagList) start() {
} }
func NewArticleList() *ArticleList { func NewArticleList() *ArticleList {
list := initArticleList() list := minArticleList()
list.articles = []*Article{} list.articles = []*Article{}
list.wg.Add(1) list.wg.Add(1)
@ -106,7 +106,6 @@ func (al *ArticleList) Add(a *Article) {
func (al *ArticleList) Release(uuid uuid.UUID) (*Article, bool) { func (al *ArticleList) Release(uuid uuid.UUID) (*Article, bool) {
al.delCh <- uuid al.delCh <- uuid
article := <-al.retCh article := <-al.retCh
if article == nil { if article == nil {
return nil, false return nil, false
} }
@ -124,8 +123,10 @@ func (al *ArticleList) Save(filename string) error {
} }
defer file.Close() defer file.Close()
encoder := gob.NewEncoder(file)
articles := al.Get() articles := al.Get()
if err = gob.NewEncoder(file).Encode(articles); err != nil { err = encoder.Encode(articles)
if err != nil {
return fmt.Errorf("error ecoding key: %v", err) return fmt.Errorf("error ecoding key: %v", err)
} }
@ -138,8 +139,10 @@ func LoadArticleList(filename string) (*ArticleList, error) {
return nil, fmt.Errorf("error opening key file: %v", err) return nil, fmt.Errorf("error opening key file: %v", err)
} }
decoder := gob.NewDecoder(file)
articleList := NewArticleList() articleList := NewArticleList()
if err = gob.NewDecoder(file).Decode(&articleList.articles); err != nil { err = decoder.Decode(&articleList.articles)
if err != nil {
return nil, fmt.Errorf("error decoding key: %v", err) return nil, fmt.Errorf("error decoding key: %v", err)
} }
@ -147,7 +150,7 @@ func LoadArticleList(filename string) (*ArticleList, error) {
} }
func NewTagList() *TagList { func NewTagList() *TagList {
list := initTagList() list := minTagList()
list.tags = []string{} list.tags = []string{}
list.wg.Add(1) list.wg.Add(1)
@ -172,8 +175,10 @@ func (tl *TagList) Save(filename string) error {
} }
defer file.Close() defer file.Close()
encoder := gob.NewEncoder(file)
tags := tl.Get() tags := tl.Get()
if err = gob.NewEncoder(file).Encode(tags); err != nil { err = encoder.Encode(tags)
if err != nil {
return fmt.Errorf("error ecoding key: %v", err) return fmt.Errorf("error ecoding key: %v", err)
} }
@ -185,10 +190,11 @@ func LoadTagList(filename string) (*TagList, error) {
if err != nil { if err != nil {
return nil, fmt.Errorf("error opening key file: %v", err) return nil, fmt.Errorf("error opening key file: %v", err)
} }
defer file.Close()
decoder := gob.NewDecoder(file)
tagList := NewTagList() tagList := NewTagList()
if err = gob.NewDecoder(file).Decode(&tagList.tags); err != nil { err = decoder.Decode(&tagList.tags)
if err != nil {
return nil, fmt.Errorf("error decoding key: %v", err) return nil, fmt.Errorf("error decoding key: %v", err)
} }

View File

@ -45,7 +45,8 @@ 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 (?, ?, ?, ?, ?)
` `
if _, err = db.Exec(query, user.UserName, string(hashedPass), user.FirstName, user.LastName, user.Role); err != nil { _, err = db.Exec(query, user.UserName, string(hashedPass), user.FirstName, user.LastName, user.Role)
if err != nil {
return fmt.Errorf("error inserting user into DB: %v", err) return fmt.Errorf("error inserting user into DB: %v", err)
} }
@ -103,7 +104,8 @@ func (db *DB) ChangePassword(id int64, oldPass, newPass string) error {
SET password = ? SET password = ?
WHERE id = ? WHERE id = ?
` `
if _, err = db.Exec(query, string(newHashedPass), id); err != nil { _, err = db.Exec(query, string(newHashedPass), id)
if err != nil {
return fmt.Errorf("error updating password in DB: %v", err) return fmt.Errorf("error updating password in DB: %v", err)
} }
@ -132,7 +134,8 @@ 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, &user.LastName, &user.Role); err != nil { if err := row.Scan(&user.ID, &user.UserName, &user.FirstName,
&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)
} }

View File

@ -1,101 +0,0 @@
package data
import (
"encoding/gob"
"fmt"
"os"
"sync"
"github.com/gorilla/feeds"
)
type Feed struct {
addCh chan *feeds.Item
setCh chan feeds.Feed
getCh chan feeds.Feed
feed feeds.Feed
wg sync.WaitGroup
}
func initFeed() *Feed {
return &Feed{
addCh: make(chan *feeds.Item),
setCh: make(chan feeds.Feed),
getCh: make(chan feeds.Feed),
}
}
func (f *Feed) start() {
f.wg.Done()
for {
select {
case item := <-f.addCh:
f.feed.Items = append(f.feed.Items, item)
case f.getCh <- f.feed:
case f.feed = <-f.setCh:
}
}
}
func NewFeed(title, link, desc string) *Feed {
feed := initFeed()
feed.feed = feeds.Feed{
Title: title,
Link: &feeds.Link{Href: link},
Description: desc,
}
feed.wg.Add(1)
go feed.start()
feed.wg.Wait()
return feed
}
func (f *Feed) Get() feeds.Feed {
return <-f.getCh
}
func (f *Feed) Set(feed feeds.Feed) {
f.setCh <- feed
}
func OpenFeed(filename string) (*Feed, error) {
file, err := os.Open(filename)
if err != nil {
return nil, fmt.Errorf("error opening file %v: %v", filename, err)
}
defer file.Close()
feed := initFeed()
feed.wg.Add(1)
go feed.start()
feed.wg.Wait()
tmpFeed := new(feeds.Feed)
if err = gob.NewDecoder(file).Decode(tmpFeed); err != nil {
return nil, fmt.Errorf("error decoding file %v: %v", filename, err)
}
feed.Set(*tmpFeed)
return feed, nil
}
func (f *Feed) Save(filename string) error {
file, err := os.Create(filename)
if err != nil {
return fmt.Errorf("error creating file %v: %v", filename, err)
}
defer file.Close()
feed := f.Get()
if err = gob.NewEncoder(file).Encode(feed); err != nil {
return fmt.Errorf("error encoding file %v: %v", filename, err)
}
return nil
}
func (f *Feed) Add(i *feeds.Item) {
f.addCh <- i
}

View File

@ -17,7 +17,8 @@ type CookieStore struct {
func NewKey() ([]byte, error) { func NewKey() ([]byte, error) {
key := make([]byte, 32) key := make([]byte, 32)
if _, err := io.ReadFull(rand.Reader, key); err != nil { _, err := io.ReadFull(rand.Reader, key)
if err != nil {
return nil, fmt.Errorf("error generating key: %v", err) return nil, fmt.Errorf("error generating key: %v", err)
} }
@ -32,7 +33,9 @@ func SaveKey(key []byte, filename string) error {
defer file.Close() defer file.Close()
file.Chmod(0600) file.Chmod(0600)
if err = gob.NewEncoder(file).Encode(key); err != nil { encoder := gob.NewEncoder(file)
err = encoder.Encode(key)
if err != nil {
return fmt.Errorf("error ecoding key: %v", err) return fmt.Errorf("error ecoding key: %v", err)
} }
@ -46,7 +49,9 @@ func LoadKey(filename string) ([]byte, error) {
} }
key := make([]byte, 32) key := make([]byte, 32)
if err = gob.NewDecoder(file).Decode(&key); err != nil { decoder := gob.NewDecoder(file)
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)
} }

View File

@ -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"
) )
@ -116,7 +116,7 @@ func ReviewArticle(al *data.ArticleList, s *data.CookieStore) http.HandlerFunc {
} }
} }
func PublishArticle(f *data.Feed, al *data.ArticleList, s *data.CookieStore) http.HandlerFunc { func PublishArticle(f *rss.Feed, 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 {
@ -141,13 +141,12 @@ func PublishArticle(f *data.Feed, al *data.ArticleList, s *data.CookieStore) htt
template.Must(tmpl, err).ExecuteTemplate(w, "page-content", msg) template.Must(tmpl, err).ExecuteTemplate(w, "page-content", msg)
} }
f.Add(&feeds.Item{ item := rss.NewItem()
Title: article.Title, item.Title = article.Title
Author: &feeds.Author{Name: session.Values["name"].(string)}, item.Author = article.Author
Created: article.Created, item.Description = article.Desc
Description: article.Desc, item.Content = &rss.Content{Value: article.Content}
Content: article.Content, f.Channels[0].AddItem(item)
})
f.Save("tmp/rss.gob") f.Save("tmp/rss.gob")
tmpl, err := template.ParseFiles("web/templates/hub.html") tmpl, err := template.ParseFiles("web/templates/hub.html")

View File

@ -5,13 +5,12 @@ import (
"log" "log"
"net/http" "net/http"
"streifling.com/jason/cpolis/cmd/data" "git.streifling.com/jason/rss"
) )
func ShowRSS(f *data.Feed) http.HandlerFunc { func ShowRSS(f *rss.Feed) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
feed := f.Get() rss, err := f.ToXML()
rss, err := feed.ToRss()
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)

2
go.mod
View File

@ -3,9 +3,9 @@ module streifling.com/jason/cpolis
go 1.22.0 go 1.22.0
require ( require (
git.streifling.com/jason/rss v0.0.0-20240305145359-7d49b2cb25fc
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/sessions v1.2.2 github.com/gorilla/sessions v1.2.2
github.com/microcosm-cc/bluemonday v1.0.26 github.com/microcosm-cc/bluemonday v1.0.26
github.com/yuin/goldmark v1.7.0 github.com/yuin/goldmark v1.7.0

12
go.sum
View File

@ -1,3 +1,7 @@
git.streifling.com/jason/rss v0.0.0-20240305140009-a59d3f112892 h1:miU3U9H8zSoYprEaG7xaGLMb4CcGLjGt7McC8Wrf+Vs=
git.streifling.com/jason/rss v0.0.0-20240305140009-a59d3f112892/go.mod h1:gpZF0nZbQSstMpyHD9DTAvlQEG7v4pjO5c7aIMWM4Jg=
git.streifling.com/jason/rss v0.0.0-20240305145359-7d49b2cb25fc h1:vJ36ouI2wTK+jFktnqyAfFHoYnoznAgAo1nUzvMzCvQ=
git.streifling.com/jason/rss v0.0.0-20240305145359-7d49b2cb25fc/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=
@ -8,20 +12,12 @@ 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/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 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=
github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c=
github.com/gorilla/feeds v1.1.2 h1:pxzZ5PD3RJdhFH2FsJJ4x6PqMqbgFk1+Vez4XWBW8Iw=
github.com/gorilla/feeds v1.1.2/go.mod h1:WMib8uJP3BbY+X8Szd1rA5Pzhdfh+HCCAYT2z7Fza6Y=
github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA= github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA=
github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo=
github.com/gorilla/sessions v1.2.2 h1:lqzMYz6bOfvn2WriPUjNByzeXIlVzURcPmgMczkmTjY= github.com/gorilla/sessions v1.2.2 h1:lqzMYz6bOfvn2WriPUjNByzeXIlVzURcPmgMczkmTjY=
github.com/gorilla/sessions v1.2.2/go.mod h1:ePLdVu+jbEgHH+KWw8I1z2wqd0BAdAQh/8LRvBeoNcQ= github.com/gorilla/sessions v1.2.2/go.mod h1:ePLdVu+jbEgHH+KWw8I1z2wqd0BAdAQh/8LRvBeoNcQ=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/microcosm-cc/bluemonday v1.0.26 h1:xbqSvqzQMeEHCqMi64VAs4d8uy6Mequs3rQ0k/Khz58= github.com/microcosm-cc/bluemonday v1.0.26 h1:xbqSvqzQMeEHCqMi64VAs4d8uy6Mequs3rQ0k/Khz58=
github.com/microcosm-cc/bluemonday v1.0.26/go.mod h1:JyzOCs9gkyQyjs+6h10UEVSe02CGwkhd72Xdqh78TWs= github.com/microcosm-cc/bluemonday v1.0.26/go.mod h1:JyzOCs9gkyQyjs+6h10UEVSe02CGwkhd72Xdqh78TWs=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/yuin/goldmark v1.7.0 h1:EfOIvIMZIzHdB/R/zVrikYLPPwJlfMcNczJFMs1m6sA= github.com/yuin/goldmark v1.7.0 h1:EfOIvIMZIzHdB/R/zVrikYLPPwJlfMcNczJFMs1m6sA=
github.com/yuin/goldmark v1.7.0/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= github.com/yuin/goldmark v1.7.0/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=