Progress
This commit is contained in:
		
							
								
								
									
										127
									
								
								assets.go
									
									
									
									
									
								
							
							
						
						
									
										127
									
								
								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": { | 	"/assets/vendor/css/grids-responsive-min.css": { | ||||||
| 		local:   "assets/vendor/css/grids-responsive-min.css", | 		local:   "assets/vendor/css/grids-responsive-min.css", | ||||||
| 		size:    8032, | 		size:    8032, | ||||||
| @@ -389,10 +477,38 @@ ZfY39XJelrPeb2dTP1e8O5VLPwIAAP//0xnP9ywDAAA= | |||||||
|  |  | ||||||
| 	"/templates/user_dashboard.html": { | 	"/templates/user_dashboard.html": { | ||||||
| 		local:   "templates/user_dashboard.html", | 		local:   "templates/user_dashboard.html", | ||||||
| 		size:    0, | 		size:    45, | ||||||
| 		modtime: 1547138339, | 		modtime: 1547160534, | ||||||
| 		compressed: ` | 		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", | 		local: "assets/css", | ||||||
| 	}, | 	}, | ||||||
|  |  | ||||||
|  | 	"/assets/img": { | ||||||
|  | 		isDir: true, | ||||||
|  | 		local: "assets/img", | ||||||
|  | 	}, | ||||||
|  |  | ||||||
| 	"/assets/vendor": { | 	"/assets/vendor": { | ||||||
| 		isDir: true, | 		isDir: true, | ||||||
| 		local: "assets/vendor", | 		local: "assets/vendor", | ||||||
|   | |||||||
							
								
								
									
										
											BIN
										
									
								
								assets/img/favicon.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								assets/img/favicon.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 4.6 KiB | 
| @@ -36,3 +36,7 @@ func handleRssFeed(w http.ResponseWriter, req *http.Request) { | |||||||
| 	} | 	} | ||||||
| 	fmt.Fprint(w, v) | 	fmt.Fprint(w, v) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func buildRssFeed(uid string) (string, error) { | ||||||
|  | 	return "", nil | ||||||
|  | } | ||||||
|   | |||||||
| @@ -21,16 +21,22 @@ func handleUserRequest(w http.ResponseWriter, req *http.Request) { | |||||||
|  |  | ||||||
| 	if !page.LoggedIn { | 	if !page.LoggedIn { | ||||||
| 		page.SubTitle = "ribbit login" | 		page.SubTitle = "ribbit login" | ||||||
| 		page.show("login.html", w) | 		page.show("login.html") | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	page.SubTitle = "dashboard" | 	switch f { | ||||||
| 	page.show("user_dashboard.html", w) | 	case "feeds": | ||||||
|  | 		handleUserFeeds(page) | ||||||
|  | 	case "updatesubscriptions": | ||||||
|  | 		handleUpdateUserSubs(page) | ||||||
|  | 	default: | ||||||
|  | 		handleUserDashboard(page) | ||||||
|  | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func handleUserLoginForm(page *pageData) { | func handleUserLoginForm(page *pageData) { | ||||||
| 	page.SubTitle = "ribbit login" | 	page.SubTitle = "ribbit login" | ||||||
| 	page.show("login.html", page.session.w) | 	page.show("login.html") | ||||||
| } | } | ||||||
|  |  | ||||||
| func handleUserLogin(page *pageData) { | func handleUserLogin(page *pageData) { | ||||||
| @@ -61,9 +67,59 @@ func handleUserLogin(page *pageData) { | |||||||
| // doLogin attempts to log in with the given email/password | // doLogin attempts to log in with the given email/password | ||||||
| // If it can't, it returns an error | // If it can't, it returns an error | ||||||
| func doLogin(uid, password string) error { | func doLogin(uid, password string) error { | ||||||
| 	fmt.Println("Doing Login", uid, password) |  | ||||||
| 	if strings.TrimSpace(uid) != "" && strings.TrimSpace(password) != "" { | 	if strings.TrimSpace(uid) != "" && strings.TrimSpace(password) != "" { | ||||||
| 		return m.checkCredentials(uid, password) | 		return m.checkCredentials(uid, password) | ||||||
| 	} | 	} | ||||||
| 	return errors.New("Invalid Credentials") | 	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) | ||||||
|  | } | ||||||
|   | |||||||
							
								
								
									
										61
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										61
									
								
								main.go
									
									
									
									
									
								
							| @@ -6,10 +6,12 @@ import ( | |||||||
| 	"bufio" | 	"bufio" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"html/template" | 	"html/template" | ||||||
|  | 	"io/ioutil" | ||||||
| 	"log" | 	"log" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"os" | 	"os" | ||||||
| 	"os/signal" | 	"os/signal" | ||||||
|  | 	"plugin" | ||||||
| 	"strconv" | 	"strconv" | ||||||
| 	"strings" | 	"strings" | ||||||
| 	"syscall" | 	"syscall" | ||||||
| @@ -24,25 +26,6 @@ import ( | |||||||
| const AppName = "ribbit" | const AppName = "ribbit" | ||||||
| const DbName = AppName + ".db" | 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 { | type menuItem struct { | ||||||
| 	Label    string | 	Label    string | ||||||
| 	Location string | 	Location string | ||||||
| @@ -130,10 +113,6 @@ func main() { | |||||||
| 	log.Fatal(http.ListenAndServe("127.0.0.1:"+strconv.Itoa(m.Site.Port), chain)) | 	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 { | func loggingHandler(h http.Handler) http.Handler { | ||||||
| 	return handlers.LoggingHandler(os.Stdout, h) | 	return handlers.LoggingHandler(os.Stdout, h) | ||||||
| } | } | ||||||
| @@ -193,22 +172,6 @@ func initPageData(w http.ResponseWriter, req *http.Request) *pageData { | |||||||
| 	return p | 	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 { | func outputTemplate(tmplName string, tmplData interface{}, w http.ResponseWriter) error { | ||||||
| 	n := "/templates/" + tmplName | 	n := "/templates/" + tmplName | ||||||
| 	l := template.Must(template.New("layout").Parse(FSMustString(m.Site.DevMode, n))) | 	l := template.Must(template.New("layout").Parse(FSMustString(m.Site.DevMode, n))) | ||||||
| @@ -272,4 +235,24 @@ func initialize() { | |||||||
| 		m.Site.sessionSecret = sessSc | 		m.Site.sessionSecret = sessSc | ||||||
| 		assertError(m.Site.SaveToDB()) | 		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)) | ||||||
|  | 	} | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										1
									
								
								model.go
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								model.go
									
									
									
									
									
								
							| @@ -14,6 +14,7 @@ type model struct { | |||||||
| 	dbFileName string | 	dbFileName string | ||||||
|  |  | ||||||
| 	Users       []User | 	Users       []User | ||||||
|  | 	FeedSources []FeedSource | ||||||
| 	Feeds       []Feed | 	Feeds       []Feed | ||||||
|  |  | ||||||
| 	Site *SiteData | 	Site *SiteData | ||||||
|   | |||||||
| @@ -1,9 +1,77 @@ | |||||||
| package main | package main | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
|  | 	"plugin" | ||||||
| 	"time" | 	"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 { | type Feed struct { | ||||||
| 	Name       string | 	Name       string | ||||||
| 	Author     string | 	Author     string | ||||||
|   | |||||||
							
								
								
									
										40
									
								
								page_data.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								page_data.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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 | ||||||
|  | } | ||||||
| @@ -2,8 +2,6 @@ package main | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"C" | 	"C" | ||||||
| ) |  | ||||||
| import ( |  | ||||||
| 	"errors" | 	"errors" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| @@ -12,43 +10,36 @@ import ( | |||||||
| 	"github.com/PuerkitoBio/goquery" | 	"github.com/PuerkitoBio/goquery" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func getFeedList() []Feed { | func GetSourceName() string { | ||||||
| 	var ret []Feed | 	return "dilbert" | ||||||
| 	ret = append(ret, *NewFeed("dilbert", "Dilbert", "Scott Adams", "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 | 	return ret | ||||||
| } | } | ||||||
|  |  | ||||||
| func getRssItem(slug string) (string, error) { | func GetFeedUrl(slug string, date time.Time) (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 = "<![CDATA[" + desc + "]]>" |  | ||||||
| 	ret := "    <item>\n" |  | ||||||
| 	ret += "      <title>" + feed.Name + "</title>\n" |  | ||||||
| 	ret += "      <pubDate>" + feed.LastUpdate.Format(time.RFC1123Z) + "</pubDate>\n" |  | ||||||
| 	ret += "      <guid>dilbert;" + slug + ";" + feed.LastUpdate.Format(time.RFC1123Z) + "</guid>\n" |  | ||||||
| 	ret += "      <link>" + getFeedUrl(time.Now()) + "</link>\n" |  | ||||||
| 	ret += "      <description>" + desc + "</description>\n" |  | ||||||
| 	ret += "    </item>\n" |  | ||||||
| 	return ret, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func getFeedUrl(date time.Time) string { |  | ||||||
| 	return fmt.Sprintf( | 	return fmt.Sprintf( | ||||||
| 		"http://dilbert.com/strip/%4d-%02d-%02d", | 		"http://dilbert.com/strip/%4d-%02d-%02d", | ||||||
| 		date.Year(), | 		date.Year(), | ||||||
| 		date.Month(), | 		date.Month(), | ||||||
| 		date.Day(), | 		date.Day(), | ||||||
| 	) | 	), nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func getFeedDesc(date time.Time) (string, error) { | func GetFeedDesc(slug string, date time.Time) (string, error) { | ||||||
| 	res, err := http.Get(getFeedUrl(date)) | 	url, err := GetFeedUrl(slug, date) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return "", err | ||||||
|  | 	} | ||||||
|  | 	res, err := http.Get(url) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return "", err | 		return "", err | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -11,8 +11,12 @@ import ( | |||||||
| 	"github.com/PuerkitoBio/goquery" | 	"github.com/PuerkitoBio/goquery" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func downloadList() { | func GetSourceName() string { | ||||||
| 	var ret []Feed | 	return "gocomics" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func GetFeedList() []map[string]string { | ||||||
|  | 	var ret []map[string]string | ||||||
| 	lstUrl := "http://www.gocomics.com/comics/a-to-z" | 	lstUrl := "http://www.gocomics.com/comics/a-to-z" | ||||||
| 	res, err := http.Get(lstUrl) | 	res, err := http.Get(lstUrl) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| @@ -48,44 +52,33 @@ func downloadList() { | |||||||
| 			} | 			} | ||||||
| 			author = strings.TrimPrefix(author, "By ") | 			author = strings.TrimPrefix(author, "By ") | ||||||
| 			author = strings.Replace(author, "\u0026", "&", -1) | 			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 | 	return ret | ||||||
| } | } | ||||||
|  |  | ||||||
| func getRssItem(slug string) (string, error) { | func GetFeedUrl(slug string, date time.Time) (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 = "<![CDATA[" + desc + "]]>" |  | ||||||
| 	ret := "    <item>\n" |  | ||||||
| 	ret += "      <title>" + comic.Name + "</title>\n" |  | ||||||
| 	ret += "      <pubDate>" + comic.LastUpdate.Format(time.RFC1123Z) + "</pubDate>\n" |  | ||||||
| 	ret += "      <guid>gocomics;" + slug + ";" + comic.LastUpdate.Format(time.RFC1123Z) + "</guid>\n" |  | ||||||
| 	ret += "      <link>" + getGoComicsComicUrl(slug, time.Now()) + "</link>\n" |  | ||||||
| 	ret += "      <description>" + desc + "</description>\n" |  | ||||||
| 	ret += "    </item>\n" |  | ||||||
| 	return ret, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func getFeedUrl(slug string, date time.Time) string { |  | ||||||
| 	return fmt.Sprintf( | 	return fmt.Sprintf( | ||||||
| 		"http://www.gocomics.com/%s/%04d/%02d/%02d", | 		"http://www.gocomics.com/%s/%04d/%02d/%02d", | ||||||
| 		slug, | 		slug, | ||||||
| 		date.Year(), | 		date.Year(), | ||||||
| 		date.Month(), | 		date.Month(), | ||||||
| 		date.Day(), | 		date.Day(), | ||||||
| 	) | 	), nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func getFeedDesc(slug string, date time.Time) (string, error) { | func GetFeedDesc(slug string, date time.Time) (string, error) { | ||||||
| 	res, err := http.Get(getFeedUrl(slug, date)) | 	url, err := GetFeedUrl(slug, date) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return "", err | ||||||
|  | 	} | ||||||
|  | 	res, err := http.Get(url) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return "", err | 		return "", err | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -10,12 +10,22 @@ import ( | |||||||
| 	"github.com/PuerkitoBio/goquery" | 	"github.com/PuerkitoBio/goquery" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func getFeedList() []Feed { | func GetSourceName() string { | ||||||
| 	var ret []Feed | 	return "xkcd" | ||||||
| 	ret = append(ret, *NewFeed("xkcd", "XKCD", "Randall Munroe", "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 | 	return ret | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /* | ||||||
| func getRssItem(slug string) (string, error) { | func getRssItem(slug string) (string, error) { | ||||||
| 	desc, err := getFeedDesc(time.Now()) | 	desc, err := getFeedDesc(time.Now()) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| @@ -35,8 +45,9 @@ func getRssItem(slug string) (string, error) { | |||||||
| 	ret += "    </item>\n" | 	ret += "    </item>\n" | ||||||
| 	return ret, nil | 	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 { | 	var isComicDay = func(dt time.Time) bool { | ||||||
| 		return dt.Weekday() == time.Monday || dt.Weekday() == time.Wednesday || dt.Weekday() == time.Friday | 		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 | 	return fmt.Sprintf("https://xkcd.com/%d", num), nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func getFeedDesc(date time.Time) (string, error) { | func GetFeedDesc(slug string, dt time.Time) (string, error) { | ||||||
| 	res, err := http.Get(getUrl(date)) | 	var url string | ||||||
|  | 	var err error | ||||||
|  | 	if url, err = GetFeedUrl(slug, dt); err != nil { | ||||||
|  | 		return "", err | ||||||
|  | 	} | ||||||
|  | 	res, err := http.Get(url) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return "", err | 		return "", err | ||||||
| 	} | 	} | ||||||
|   | |||||||
							
								
								
									
										
											BIN
										
									
								
								plugins/plugin_dilbert.so
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								plugins/plugin_dilbert.so
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								plugins/plugin_gocomics.so
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								plugins/plugin_gocomics.so
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								plugins/plugin_xkcd.so
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								plugins/plugin_xkcd.so
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | <a href="/user/feeds">Edit Subscriptions</a> | ||||||
|   | |||||||
							
								
								
									
										135
									
								
								templates/user_feeds.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								templates/user_feeds.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,135 @@ | |||||||
|  | <div id="all_sources_container"></div> | ||||||
|  | <form name="feed_subscriptions" action="/user/updatesubscriptions" onsubmit="updateSubscriptionValue()"> | ||||||
|  |   <input id="user_feeds" type="hidden" name="user_feeds" value="" /> | ||||||
|  |   <button type="submit">Save</button> | ||||||
|  | </form> | ||||||
|  | <script> | ||||||
|  | var user_feeds = [ | ||||||
|  | {{ range $i, $v := .TemplateData.User.SubSlugs }} | ||||||
|  |   "{{$v}}", | ||||||
|  | {{ end }} | ||||||
|  | ]; | ||||||
|  |  | ||||||
|  | var all_feeds = [ | ||||||
|  | {{ range $i, $v := .TemplateData.FeedSources }} | ||||||
|  |   {{ range $vi, $vf := $v.Feeds }} | ||||||
|  |     { | ||||||
|  |       "name": "{{$vf.Name}}", | ||||||
|  |       "author": "{{$vf.Author}}", | ||||||
|  |       "slug": "{{$vf.Slug}}", | ||||||
|  |       "source": "{{$vf.Source}}", | ||||||
|  |       "desc": "{{$vf.Desc}}", | ||||||
|  |       "last_update": "{{$vf.LastUpdate}}" | ||||||
|  |     }, | ||||||
|  |   {{ end }} | ||||||
|  | {{ end }} | ||||||
|  | ]; | ||||||
|  |  | ||||||
|  | function init() { | ||||||
|  |   var sourcesContainer = document.getElementById("all_sources_container"); | ||||||
|  |   var sources = []; | ||||||
|  |   for(var i = 0; i < all_feeds.length; i++) { | ||||||
|  |     if(sources.indexOf(all_feeds[i].source) < 0) { | ||||||
|  |       sources.push(all_feeds[i].source) | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   for(var i = 0; i < sources.length; i++) { | ||||||
|  |     sourcesContainer.appendChild(createFeedSourceTable(sources[i])); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function createFeedSourceTable(source) { | ||||||
|  |   var sourceContainer = document.createElement("div"); | ||||||
|  |   var sourceTitle = document.createElement("h1"); | ||||||
|  |   sourceTitle.innerText = source+"  "; | ||||||
|  |   sourceContainer.appendChild(sourceTitle); | ||||||
|  |   var table = document.createElement("table"); | ||||||
|  |   table.classList.add("pure-table","pure-table-bordered","center-all","hidden"); | ||||||
|  |   var thead = document.createElement("thead"); | ||||||
|  |   var thtr = document.createElement("tr"); | ||||||
|  |   var thChk = document.createElement("th"); | ||||||
|  |   var thn = document.createElement("th"); | ||||||
|  |   thn.innerText = "Name"; | ||||||
|  |   var tha = document.createElement("th"); | ||||||
|  |   tha.innerText = "Author"; | ||||||
|  |   var thl = document.createElement("th"); | ||||||
|  |   thl.innerText = "Last Update"; | ||||||
|  |   thtr.appendChild(document.createElement("th")); | ||||||
|  |   for(var i = 0; i < all_feeds.length; i++) { | ||||||
|  |     if(all_feeds[i].source == source) { | ||||||
|  |       table.appendChild(createFeedTableRow(all_feeds[i])); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   sourceContainer.appendChild(table); | ||||||
|  |   var sourceShow = document.createElement("a"); | ||||||
|  |   sourceShow.style["color"] = "blue"; | ||||||
|  |   sourceShow.style["cursor"] = "pointer"; | ||||||
|  |   sourceShow.innerText = "v"; | ||||||
|  |   sourceShow.onclick = function() { | ||||||
|  |     if(table.classList.contains("hidden")) { | ||||||
|  |       sourceShow.innerText = "^"; | ||||||
|  |     } else { | ||||||
|  |       sourceShow.innerText = "v"; | ||||||
|  |     } | ||||||
|  |     table.classList.toggle("hidden"); | ||||||
|  |   } | ||||||
|  |   sourceTitle.appendChild(sourceShow); | ||||||
|  |   sourceContainer.style["margin-bottom"] = "2em"; | ||||||
|  |  | ||||||
|  |   return sourceContainer; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function createFeedTableRow(feedItem) { | ||||||
|  |   var row = document.createElement("tr"); | ||||||
|  |   var chkCell = document.createElement("td"); | ||||||
|  |   var chkBox = document.createElement("input"); | ||||||
|  |   chkBox.setAttribute("type", "checkbox"); | ||||||
|  |   chkBox.setAttribute("data-slug", feedItem["source"]+";"+feedItem["slug"]); | ||||||
|  |   chkBox.onclick = function() { | ||||||
|  |     toggleSubscription(this.getAttribute("data-slug")); | ||||||
|  |   } | ||||||
|  |   if(user_feeds.indexOf(feedItem["source"]+";"+feedItem["slug"]) >= 0) { | ||||||
|  |     chkBox.checked = true; | ||||||
|  |   } | ||||||
|  |   chkCell.append(chkBox); | ||||||
|  |   row.append(chkCell); | ||||||
|  |   var nameCell = document.createElement("td"); | ||||||
|  |   nameCell.innerText = feedItem["name"]; | ||||||
|  |   row.append(nameCell); | ||||||
|  |   var authCell = document.createElement("td"); | ||||||
|  |   authCell.innerText = feedItem["author"]; | ||||||
|  |   row.append(authCell); | ||||||
|  |   var updCell = document.createElement("td"); | ||||||
|  |   updCell.innerText = feedItem["last_update"]; | ||||||
|  |   row.append(updCell); | ||||||
|  |   return row; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function toggleSubscription(slug) { | ||||||
|  |   if(user_feeds.indexOf(slug) >= 0) { | ||||||
|  |     user_feeds.splice(user_feeds.indexOf(slug), 1); | ||||||
|  |   } else { | ||||||
|  |     user_feeds.push(slug); | ||||||
|  |   } | ||||||
|  |   updateSubscriptionValue(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function getSubRow(slug) { | ||||||
|  |   return document.getElementById("row_"+slug.replace(";","_")); | ||||||
|  | } | ||||||
|  | function updateSubscriptionTable() { | ||||||
|  |   for(var i = 0; i < user_feeds.length; i++) { | ||||||
|  |     var row = getSubRow(user_feeds[i]); | ||||||
|  |     if(row) { | ||||||
|  |       row.getElementsByTagName("input")[0].checked = true; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function updateSubscriptionValue() { | ||||||
|  |   document.getElementById("user_feeds").value = user_feeds; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | init(); | ||||||
|  | updateSubscriptionTable(); | ||||||
|  | </script> | ||||||
		Reference in New Issue
	
	Block a user