diff --git a/assets.go b/assets.go index d28486d..1879a8b 100644 --- a/assets.go +++ b/assets.go @@ -222,6 +222,94 @@ nC1WAvxNMB27f2/7AjTg5s54BOwNTttvIBe0ubuEzo83ocq/bONcqwz1BCL/BAAA///ACu/RdBMAAA== `, }, + "/assets/img/favicon.png": { + local: "assets/img/favicon.png", + size: 4752, + modtime: 1547232209, + compressed: ` +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 +`, + }, + "/assets/vendor/css/grids-responsive-min.css": { local: "assets/vendor/css/grids-responsive-min.css", size: 8032, @@ -389,10 +477,38 @@ ZfY39XJelrPeb2dTP1e8O5VLPwIAAP//0xnP9ywDAAA= "/templates/user_dashboard.html": { local: "templates/user_dashboard.html", - size: 0, - modtime: 1547138339, + size: 45, + modtime: 1547160534, compressed: ` -H4sIAAAAAAAC/wEAAP//AAAAAAAAAAA= +H4sIAAAAAAAC/7JJVMgoSk2zVdIvLU4t0k9LTU0pVrJzTcksUQguTSpOLsosKMnMzyu20U+04wIEAAD/ +/2HSavctAAAA +`, + }, + + "/templates/user_feeds.html": { + local: "templates/user_feeds.html", + size: 3588, + modtime: 1547234296, + compressed: ` +H4sIAAAAAAAC/5xXXY/aOBe+z6+wrLkIGia0t4UgtdP3lSpVu9JC92aEkIkPiTXGjmwHZjTiv69sJ9ih +IWL3ApT4POf7wycLyo6I0RwTzrdaNqoAvS2kMIQJUHi5mFF2XCaLvVQHJMgBcrwHoFvd7HShWG2YFBoj +UtiHHM8aDWrW1JQY6EOWCUILJurGOHUWt7WSNEbmvYYcV4xSELhVEtOPhDeQY4xmTsiuMUaKlks3uwMz +eLkiR1jMPGmZLGbW3mWy8AYskyNRKIhEOXpJPj6QIqIE9MCm6OGIvuQoW8Oh5sTAd2JI9kuDylbNbsWb +UqPzOUEIf3w8HM9nPLXcIKg93cwTJ94G8F9I/z8AXfl4e9mB4+hY9pbn4eiALQShD/ePELZRwl+8Qfvs +D3IAZ1ZLJY2ppAr0r+49RmjelIFuXexRnWER3b3HCAq6CPTvoIuYyok2W18FAfSTaPPLnZ3P2CHPU+93 +G8l+TPeNcEWFmGAmnTjXbZzbIn3uahTliMqiOYAwWQnmfxzs47f3HzS9UdSTeV+UTdjGnu2lSu05Qzn6 +NEcMLUJWMw6iNNUcscfHSZsHtk9bERkTFN7+3KcX/AvbZJ44QQv0aXJJXcdRN7oahPvQJP43YFInYMCg +69hkpK5B0OeKcZoWCoiBUHdrsuPQOfDCNhMXl3NyjmI/xnOdksGMeAFtUlJM2fE6/GtmOIywVJ89R4TO +mBCg1vBmUN6eB8Sw8xH3Rb+xzoxodnSv3D1mBSda/2TaZITSFNeNgicPmkYvTzupKCigeIoLEAbUE+E8 +uG0qIHRMraXHcDMWUaNi6HP1Oio5xoo7kKYSvWBjO2lwkEHukkH6Mvw0iqTwu6TwvhQ7TpCfJ9gDTD/l +YxIn/7HdB/oV5V0Nhh735TLcfK6F/pKnnixvUGj7sVJ2wh1egWmUuAbPb3TwRbFV+sPAITSwkqc7S6yo +Xp+BjyaM9tDf5NsI2C0EHu+xmQbz1RjFdo2BFNtLHk8RLiooXnfybQRKiSFP7lqbos7Dl+4m2zziOX6M +ji1uEwuTouCssN3ThS7t8mlkWXJYRetMaiqm7W0zqL8bpK5iwtZxuSPutQ4t83BxtGa6QIAdH0Y10Olp +s9KWSeqxvkTkKTq1oEty7ApxZy47aK8Dg71uGdlcqet4LvrsUnKnvg56Q1+73lxr7LguGpua3qmwRd7Q +F68z10pbzrgflTz1e3CggGyKfWoLKbTkkHFZpnhtkUyUCD86xM0a8vxxgUQgXXNWwE22KfrsKxQB1/A7 +u9tMHLKrL+977MDfdidPJ30/SzCrZmdHTHCvjcnNFU3J09Y7mymoOSkgxXM8xVvXRucg/Hcb/DLi1QzM +8sijgWEexl6wOnDYkTzvhr6SpzDabeqDD/rb+5qU9lK8zLKXT5uBLu1Gexyum1F1ym5GLPo0mmTu2wjl +kbMuJX5nnic3gzZPFrPu4+ifAAAA//9hEtQ2BA4AAA== `, }, @@ -411,6 +527,11 @@ H4sIAAAAAAAC/wEAAP//AAAAAAAAAAA= local: "assets/css", }, + "/assets/img": { + isDir: true, + local: "assets/img", + }, + "/assets/vendor": { isDir: true, local: "assets/vendor", diff --git a/assets/img/favicon.png b/assets/img/favicon.png new file mode 100644 index 0000000..6c2bd38 Binary files /dev/null and b/assets/img/favicon.png differ diff --git a/endpoints_public.go b/endpoints_public.go index 8b0bf6d..28b98cf 100644 --- a/endpoints_public.go +++ b/endpoints_public.go @@ -36,3 +36,7 @@ func handleRssFeed(w http.ResponseWriter, req *http.Request) { } fmt.Fprint(w, v) } + +func buildRssFeed(uid string) (string, error) { + return "", nil +} diff --git a/endpoints_user.go b/endpoints_user.go index 5e3f249..3e89756 100644 --- a/endpoints_user.go +++ b/endpoints_user.go @@ -21,16 +21,22 @@ func handleUserRequest(w http.ResponseWriter, req *http.Request) { if !page.LoggedIn { page.SubTitle = "ribbit login" - page.show("login.html", w) + page.show("login.html") return } - page.SubTitle = "dashboard" - page.show("user_dashboard.html", w) + switch f { + case "feeds": + handleUserFeeds(page) + case "updatesubscriptions": + handleUpdateUserSubs(page) + default: + handleUserDashboard(page) + } } func handleUserLoginForm(page *pageData) { page.SubTitle = "ribbit login" - page.show("login.html", page.session.w) + page.show("login.html") } func handleUserLogin(page *pageData) { @@ -61,9 +67,59 @@ func handleUserLogin(page *pageData) { // doLogin attempts to log in with the given email/password // If it can't, it returns an error func doLogin(uid, password string) error { - fmt.Println("Doing Login", uid, password) if strings.TrimSpace(uid) != "" && strings.TrimSpace(password) != "" { return m.checkCredentials(uid, password) } return errors.New("Invalid Credentials") } + +func handleUserDashboard(page *pageData) { + page.SubTitle = "dashboard" + page.show("user_dashboard.html") +} + +func handleUserFeeds(page *pageData) { + page.SubTitle = "feeds" + type feedsPageData struct { + User *User + FeedSources []FeedSource + } + fpd := new(feedsPageData) + fpd.FeedSources = m.FeedSources + id, err := page.session.getStringValue("id") + if err != nil { + userError(page.session.w) + return + } + fpd.User, err = m.GetUser(id) + if err != nil { + userError(page.session.w) + return + } + page.TemplateData = fpd + page.show("user_feeds.html") +} + +func handleUpdateUserSubs(page *pageData) { + subs := page.session.req.FormValue("user_feeds") + fmt.Println(subs) + subPts := strings.Split(subs, ",") + var userSubs []string + for i := range subPts { + subPts[i] = strings.TrimSpace(subPts[i]) + if subPts[i] != "" { + userSubs = append(userSubs, subPts[i]) + } + } + id, err := page.session.getStringValue("id") + if err != nil { + userError(page.session.w) + return + } + var u *User + u, err = m.GetUser(id) + u.SubSlugs = userSubs + m.SaveUser(u) + + redirect("/user/dashboard", page.session.w, page.session.req) +} diff --git a/main.go b/main.go index 9098cf1..efd0147 100644 --- a/main.go +++ b/main.go @@ -6,10 +6,12 @@ import ( "bufio" "fmt" "html/template" + "io/ioutil" "log" "net/http" "os" "os/signal" + "plugin" "strconv" "strings" "syscall" @@ -24,25 +26,6 @@ import ( const AppName = "ribbit" const DbName = AppName + ".db" -// pageData is stuff that changes per request -type pageData struct { - Site *SiteData - Title string - SubTitle string - Stylesheets []string - HeaderScripts []string - Scripts []string - FlashMessage string - FlashClass string - LoggedIn bool - IsAdmin bool - Menu []menuItem - BottomMenu []menuItem - session *pageSession - - TemplateData interface{} -} - type menuItem struct { Label string Location string @@ -130,10 +113,6 @@ func main() { log.Fatal(http.ListenAndServe("127.0.0.1:"+strconv.Itoa(m.Site.Port), chain)) } -func buildRssFeed(uid string) (string, error) { - return uid, nil -} - func loggingHandler(h http.Handler) http.Handler { return handlers.LoggingHandler(os.Stdout, h) } @@ -193,22 +172,6 @@ func initPageData(w http.ResponseWriter, req *http.Request) *pageData { return p } -func (p *pageData) show(tmplName string, w http.ResponseWriter) error { - for _, tmpl := range []string{ - "htmlheader.html", - "header.html", - tmplName, - "footer.html", - "htmlfooter.html", - } { - if err := outputTemplate(tmpl, p, w); err != nil { - fmt.Printf("%s\n", err) - return err - } - } - return nil -} - func outputTemplate(tmplName string, tmplData interface{}, w http.ResponseWriter) error { n := "/templates/" + tmplName l := template.Must(template.New("layout").Parse(FSMustString(m.Site.DevMode, n))) @@ -272,4 +235,24 @@ func initialize() { m.Site.sessionSecret = sessSc assertError(m.Site.SaveToDB()) } + + // Load Feed Sources from Plugins + files, err := ioutil.ReadDir("./plugins/") + if err != nil { + log.Fatal(err) + } + for _, f := range files { + fmt.Print("Loading plugin ", f.Name(), "...") + p, err := plugin.Open("./plugins/" + f.Name()) + if err != nil { + panic(err) + } + var feedSource *FeedSource + if feedSource, err = LoadFeedPlugin(p); err != nil { + fmt.Println(" ", err.Error()) + continue + } + m.FeedSources = append(m.FeedSources, *feedSource) + fmt.Printf("Done. (%d feeds)\n", len(feedSource.Feeds)) + } } diff --git a/model.go b/model.go index acce94a..e032645 100644 --- a/model.go +++ b/model.go @@ -13,8 +13,9 @@ type model struct { bolt *boltease.DB dbFileName string - Users []User - Feeds []Feed + Users []User + FeedSources []FeedSource + Feeds []Feed Site *SiteData } diff --git a/model_feeds.go b/model_feeds.go index 862c472..99b1e35 100644 --- a/model_feeds.go +++ b/model_feeds.go @@ -1,9 +1,77 @@ package main import ( + "plugin" "time" ) +type FeedSource struct { + Feeds []*Feed + + // Plugin Functions + getSourceName func() string + refreshFeedList func() []map[string]string + getFeedUrl func(string, time.Time) (string, error) + getFeedDesc func(string, time.Time) (string, error) +} + +func LoadFeedPlugin(p *plugin.Plugin) (*FeedSource, error) { + ret := new(FeedSource) + feedSourceSymbol, err := p.Lookup("GetSourceName") + if err != nil { + return nil, err + } + ret.getSourceName = feedSourceSymbol.(func() string) + + feedListSymbol, err := p.Lookup("GetFeedList") + if err != nil { + return nil, err + } + ret.refreshFeedList = feedListSymbol.(func() []map[string]string) + feeds := ret.refreshFeedList() + // `feeds` is a []map, each map should contain keys: `slug`, `name`, `author`, `source` + for _, f := range feeds { + var slug, name, author, source string + var ok bool + if slug, ok = f["slug"]; !ok { + continue + } + if name, ok = f["name"]; !ok { + continue + } + if author, ok = f["author"]; !ok { + continue + } + if source, ok = f["source"]; !ok { + continue + } + ret.Feeds = append(ret.Feeds, NewFeed(slug, name, author, source)) + } + + feedUrlSymbol, err := p.Lookup("GetFeedUrl") + if err != nil { + return nil, err + } + ret.getFeedUrl = feedUrlSymbol.(func(string, time.Time) (string, error)) + + feedDescSymbol, err := p.Lookup("GetFeedDesc") + if err != nil { + return nil, err + } + ret.getFeedDesc = feedDescSymbol.(func(string, time.Time) (string, error)) + + return ret, nil +} + +func (f *FeedSource) getFeed(slug string) *Feed { + for i := range f.Feeds { + if f.Feeds[i].Slug == slug { + return f.Feeds[i] + } + } + return nil +} + type Feed struct { Name string Author string diff --git a/page_data.go b/page_data.go new file mode 100644 index 0000000..41a9e02 --- /dev/null +++ b/page_data.go @@ -0,0 +1,40 @@ +package main + +import ( + "fmt" +) + +// pageData is stuff that changes per request +type pageData struct { + Site *SiteData + Title string + SubTitle string + Stylesheets []string + HeaderScripts []string + Scripts []string + FlashMessage string + FlashClass string + LoggedIn bool + IsAdmin bool + Menu []menuItem + BottomMenu []menuItem + session *pageSession + + TemplateData interface{} +} + +func (p *pageData) show(tmplName string) error { + for _, tmpl := range []string{ + "htmlheader.html", + "header.html", + tmplName, + "footer.html", + "htmlfooter.html", + } { + if err := outputTemplate(tmpl, p, p.session.w); err != nil { + fmt.Printf("%s\n", err) + return err + } + } + return nil +} diff --git a/plugin_src/plugin_dilbert.go b/plugin_src/plugin_dilbert.go index 1aba78d..82921eb 100644 --- a/plugin_src/plugin_dilbert.go +++ b/plugin_src/plugin_dilbert.go @@ -2,8 +2,6 @@ package main import ( "C" -) -import ( "errors" "fmt" "net/http" @@ -12,43 +10,36 @@ import ( "github.com/PuerkitoBio/goquery" ) -func getFeedList() []Feed { - var ret []Feed - ret = append(ret, *NewFeed("dilbert", "Dilbert", "Scott Adams", "dilbert")) +func GetSourceName() string { + return "dilbert" +} + +func GetFeedList() []map[string]string { + var ret []map[string]string + feedMap := make(map[string]string) + feedMap["slug"] = "dilbert" + feedMap["name"] = "Dilbert" + feedMap["author"] = "Scott Adams" + feedMap["source"] = GetSourceName() + ret = append(ret, feedMap) return ret } -func getRssItem(slug string) (string, error) { - desc, err := getFeedDesc(time.Now()) - if err != nil { - return "", err - } - feed, err := m.GetFeed(SRC_DILBERT, slug) - if err != nil { - return "", err - } - desc = "" - ret := " \n" - ret += " " + feed.Name + "\n" - ret += " " + feed.LastUpdate.Format(time.RFC1123Z) + "\n" - ret += " dilbert;" + slug + ";" + feed.LastUpdate.Format(time.RFC1123Z) + "\n" - ret += " " + getFeedUrl(time.Now()) + "\n" - ret += " " + desc + "\n" - ret += " \n" - return ret, nil -} - -func getFeedUrl(date time.Time) string { +func GetFeedUrl(slug string, date time.Time) (string, error) { return fmt.Sprintf( "http://dilbert.com/strip/%4d-%02d-%02d", date.Year(), date.Month(), date.Day(), - ) + ), nil } -func getFeedDesc(date time.Time) (string, error) { - res, err := http.Get(getFeedUrl(date)) +func GetFeedDesc(slug string, date time.Time) (string, error) { + url, err := GetFeedUrl(slug, date) + if err != nil { + return "", err + } + res, err := http.Get(url) if err != nil { return "", err } diff --git a/plugin_src/plugin_gocomics.go b/plugin_src/plugin_gocomics.go index 5675e42..b6af52c 100644 --- a/plugin_src/plugin_gocomics.go +++ b/plugin_src/plugin_gocomics.go @@ -11,8 +11,12 @@ import ( "github.com/PuerkitoBio/goquery" ) -func downloadList() { - var ret []Feed +func GetSourceName() string { + return "gocomics" +} + +func GetFeedList() []map[string]string { + var ret []map[string]string lstUrl := "http://www.gocomics.com/comics/a-to-z" res, err := http.Get(lstUrl) if err != nil { @@ -48,44 +52,33 @@ func downloadList() { } author = strings.TrimPrefix(author, "By ") author = strings.Replace(author, "\u0026", "&", -1) - ret = append(ret, *NewFeed(slug, name, author, "gocomics")) + feedMap := make(map[string]string) + feedMap["slug"] = slug + feedMap["name"] = name + feedMap["author"] = author + feedMap["source"] = GetSourceName() + ret = append(ret, feedMap) } }) return ret } -func getRssItem(slug string) (string, error) { - desc, err := getFeedDesc(slug, time.Now()) - if err != nil { - return "", err - } - comic, err := m.GetComic(SRC_GOCOMICS, slug) - if err != nil { - return "", err - } - desc = "" - ret := " \n" - ret += " " + comic.Name + "\n" - ret += " " + comic.LastUpdate.Format(time.RFC1123Z) + "\n" - ret += " gocomics;" + slug + ";" + comic.LastUpdate.Format(time.RFC1123Z) + "\n" - ret += " " + getGoComicsComicUrl(slug, time.Now()) + "\n" - ret += " " + desc + "\n" - ret += " \n" - return ret, nil -} - -func getFeedUrl(slug string, date time.Time) string { +func GetFeedUrl(slug string, date time.Time) (string, error) { return fmt.Sprintf( "http://www.gocomics.com/%s/%04d/%02d/%02d", slug, date.Year(), date.Month(), date.Day(), - ) + ), nil } -func getFeedDesc(slug string, date time.Time) (string, error) { - res, err := http.Get(getFeedUrl(slug, date)) +func GetFeedDesc(slug string, date time.Time) (string, error) { + url, err := GetFeedUrl(slug, date) + if err != nil { + return "", err + } + res, err := http.Get(url) if err != nil { return "", err } diff --git a/plugin_src/plugin_xkcd.go b/plugin_src/plugin_xkcd.go index d1f40cb..ec165ec 100644 --- a/plugin_src/plugin_xkcd.go +++ b/plugin_src/plugin_xkcd.go @@ -10,12 +10,22 @@ import ( "github.com/PuerkitoBio/goquery" ) -func getFeedList() []Feed { - var ret []Feed - ret = append(ret, *NewFeed("xkcd", "XKCD", "Randall Munroe", "xkcd")) +func GetSourceName() string { + return "xkcd" +} + +func GetFeedList() []map[string]string { + var ret []map[string]string + feedMap := make(map[string]string) + feedMap["slug"] = "xkcd" + feedMap["name"] = "XKCD" + feedMap["author"] = "Randall Munroe" + feedMap["source"] = GetSourceName() + ret = append(ret, feedMap) return ret } +/* func getRssItem(slug string) (string, error) { desc, err := getFeedDesc(time.Now()) if err != nil { @@ -35,8 +45,9 @@ func getRssItem(slug string) (string, error) { ret += " \n" return ret, nil } +*/ -func getFeedUrl(date time.Time) (string, error) { +func GetFeedUrl(slug string, dt time.Time) (string, error) { var isComicDay = func(dt time.Time) bool { return dt.Weekday() == time.Monday || dt.Weekday() == time.Wednesday || dt.Weekday() == time.Friday } @@ -54,8 +65,13 @@ func getFeedUrl(date time.Time) (string, error) { return fmt.Sprintf("https://xkcd.com/%d", num), nil } -func getFeedDesc(date time.Time) (string, error) { - res, err := http.Get(getUrl(date)) +func GetFeedDesc(slug string, dt time.Time) (string, error) { + var url string + var err error + if url, err = GetFeedUrl(slug, dt); err != nil { + return "", err + } + res, err := http.Get(url) if err != nil { return "", err } diff --git a/plugins/plugin_dilbert.so b/plugins/plugin_dilbert.so new file mode 100644 index 0000000..bd19a27 Binary files /dev/null and b/plugins/plugin_dilbert.so differ diff --git a/plugins/plugin_gocomics.so b/plugins/plugin_gocomics.so new file mode 100644 index 0000000..a995f22 Binary files /dev/null and b/plugins/plugin_gocomics.so differ diff --git a/plugins/plugin_xkcd.so b/plugins/plugin_xkcd.so new file mode 100644 index 0000000..2fa5f2d Binary files /dev/null and b/plugins/plugin_xkcd.so differ diff --git a/templates/user_dashboard.html b/templates/user_dashboard.html index e69de29..c1cb451 100644 --- a/templates/user_dashboard.html +++ b/templates/user_dashboard.html @@ -0,0 +1 @@ +Edit Subscriptions diff --git a/templates/user_feeds.html b/templates/user_feeds.html new file mode 100644 index 0000000..1536a0c --- /dev/null +++ b/templates/user_feeds.html @@ -0,0 +1,135 @@ +
+
+ + +
+