From 3392e8e2ba2e50984c8693798cc8758fbc86585f Mon Sep 17 00:00:00 2001 From: Matt Baer Date: Fri, 22 Jan 2016 15:19:31 -0500 Subject: [PATCH 1/5] Make Browse item count configurable --- config.go | 1 + construction.go | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/config.go b/config.go index 659b2cc..f12a59b 100644 --- a/config.go +++ b/config.go @@ -20,6 +20,7 @@ type config struct { AutoApprove bool `env:"key=AUTO_APPROVE default=false"` AdminPass string `env:"key=ADMIN_PASS default=uhoh"` + BrowseItems int `env:"key=BROWSE_ITEMS default=10"` } func newConfig() (*config, error) { diff --git a/construction.go b/construction.go index 6e0e0f1..bd717f6 100644 --- a/construction.go +++ b/construction.go @@ -304,7 +304,7 @@ func viewHouses(app *app, w http.ResponseWriter, r *http.Request) error { func getPublicHouses(app *app) (*[]PublicHouse, error) { houses := []PublicHouse{} - rows, err := app.db.Query("SELECT house_id, title, thumb_url FROM publichouses WHERE approved = 1 ORDER BY updated DESC LIMIT 10") + rows, err := app.db.Query(fmt.Sprintf("SELECT house_id, title, thumb_url FROM publichouses WHERE approved = 1 ORDER BY updated DESC LIMIT %d", app.cfg.BrowseItems)) switch { case err == sql.ErrNoRows: return nil, impart.HTTPError{http.StatusNotFound, "Return to sender. Address unknown."} From 6d0a5d11e63dfacf2bfcf5352bccfabd46f2511a Mon Sep 17 00:00:00 2001 From: Matt Baer Date: Fri, 22 Jan 2016 15:19:52 -0500 Subject: [PATCH 2/5] Mention how to discover HTMLhouse pages --- static/about.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/static/about.html b/static/about.html index 39e4328..6b2d00f 100644 --- a/static/about.html +++ b/static/about.html @@ -47,7 +47,8 @@

Purpose. To provide a simple HTML testing ground with no cruft or fuss.

Editing. Pages can be edited again from the same computer / browser they were created on. If you clear your browser data (specifically local storage) you will lose this ability.

Limitations. There is currently no way to delete pages.

-

Discovery. See what others have created on our Twitter account, @HTMLhouse. Tweet us the URL of any page you create (and whether you want credit) and we'll share it!

+

Discovery. Browse what others have publicly created. Mark your page as Public when you publish it to be added!

+

Twitter. We announce updates and some published pages on @HTMLhouse.

Abuse. Please don't poop in the pool.

Credits

From 00a731b8ccba951ba5bca0c73257816fb4b6be22 Mon Sep 17 00:00:00 2001 From: Matt Baer Date: Fri, 22 Jan 2016 16:47:41 -0500 Subject: [PATCH 3/5] Support posting new public houses to Twitter --- README.md | 4 ++++ config.go | 6 ++++++ construction.go | 3 +++ init.sql | 6 ++++++ twitter.go | 38 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 57 insertions(+) create mode 100644 twitter.go diff --git a/README.md b/README.md index ced241d..3b2a351 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,10 @@ DB_USER=dbuser DB_PASSWORD=pass DB_DB=htmlhouse PRIVATE_KEY=keys/dev PUBLIC_KEY= | `PORT` | Port to run app on | `8080` | | `STATIC_DIR` | Relative dir where static files are stored | `static` | | `AUTO_APPROVE` | Automatically approves public posts | false | +| `TWITTER_KEY` | Twitter consumer key | `notreal` | +| `TWITTER_SECRET` | Twitter consumer secret | `notreal` | +| `TWITTER_TOKEN` | Twitter access token of the posting Twitter account | `notreal` | +| `TWITTER_TOKEN_SECRET` | Twitter access token secret of the posting Twitter account | `notreal` | ### Notes diff --git a/config.go b/config.go index f12a59b..0827736 100644 --- a/config.go +++ b/config.go @@ -21,6 +21,12 @@ type config struct { AutoApprove bool `env:"key=AUTO_APPROVE default=false"` AdminPass string `env:"key=ADMIN_PASS default=uhoh"` BrowseItems int `env:"key=BROWSE_ITEMS default=10"` + + // Twitter configuration + TwitterConsumerKey string `env:"key=TWITTER_KEY default=notreal"` + TwitterConsumerSecret string `env:"key=TWITTER_SECRET default=notreal"` + TwitterToken string `env:"key=TWITTER_TOKEN default=notreal"` + TwitterTokenSecret string `env:"key=TWITTER_TOKEN_SECRET default=notreal"` } func newConfig() (*config, error) { diff --git a/construction.go b/construction.go index bd717f6..008454d 100644 --- a/construction.go +++ b/construction.go @@ -125,6 +125,9 @@ func addPublicAccess(app *app, houseID, html string) error { return err } + // Tweet about it + tweet(app, houseID, fmt.Sprintf("\"%s\" on #HTMLhouse - %s/%s.html #html #website", title, app.cfg.HostName, houseID)) + return nil } diff --git a/init.sql b/init.sql index ff2dde3..e84f76d 100644 --- a/init.sql +++ b/init.sql @@ -18,3 +18,9 @@ CREATE TABLE `publichouses` ( `loves` int(4) NOT NULL, PRIMARY KEY (`house_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; + +CREATE TABLE IF NOT EXISTS `tweetedhouses` ( + `house_id` char(8) NOT NULL, + `tweet_id` bigint(20) unsigned NOT NULL, + PRIMARY KEY (`house_id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; diff --git a/twitter.go b/twitter.go new file mode 100644 index 0000000..4c988a0 --- /dev/null +++ b/twitter.go @@ -0,0 +1,38 @@ +package htmlhouse + +import ( + "database/sql" + "fmt" + "github.com/ChimeraCoder/anaconda" +) + +func tweet(app *app, houseID, text string) { + // Check if this has already been tweeted + var tweetID int64 + err := app.db.QueryRow("SELECT tweet_id FROM tweetedhouses WHERE house_id = ?", houseID).Scan(&tweetID) + switch { + case err != nil && err != sql.ErrNoRows: + fmt.Printf("Error selecting from tweetedhouses: %v", err) + return + } + if tweetID != 0 { + return + } + + // Post to Twitter + anaconda.SetConsumerKey(app.cfg.TwitterConsumerKey) + anaconda.SetConsumerSecret(app.cfg.TwitterConsumerSecret) + api := anaconda.NewTwitterApi(app.cfg.TwitterToken, app.cfg.TwitterTokenSecret) + + t, err := api.PostTweet(text, nil) + if err != nil { + fmt.Printf("Error posting tweet: %v", err) + } + + // Mark it as "tweeted" + _, err = app.db.Exec("INSERT INTO tweetedhouses (house_id, tweet_id) VALUES (?, ?)", houseID, t.Id) + if err != nil { + fmt.Printf("Error noting house tweet status: %v", err) + return + } +} From ded8e336779afc489b90c3c58b9107c2a6a0edf4 Mon Sep 17 00:00:00 2001 From: Matt Baer Date: Fri, 22 Jan 2016 17:25:10 -0500 Subject: [PATCH 4/5] Skip tweeting pages with "HTMLhouse" title Plus add #web hashtag --- construction.go | 2 +- twitter.go | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/construction.go b/construction.go index 008454d..bb4037b 100644 --- a/construction.go +++ b/construction.go @@ -126,7 +126,7 @@ func addPublicAccess(app *app, houseID, html string) error { } // Tweet about it - tweet(app, houseID, fmt.Sprintf("\"%s\" on #HTMLhouse - %s/%s.html #html #website", title, app.cfg.HostName, houseID)) + tweet(app, houseID, title) return nil } diff --git a/twitter.go b/twitter.go index 4c988a0..1887235 100644 --- a/twitter.go +++ b/twitter.go @@ -6,7 +6,12 @@ import ( "github.com/ChimeraCoder/anaconda" ) -func tweet(app *app, houseID, text string) { +func tweet(app *app, houseID, title string) { + // Check for blacklisted titles + if title == "HTMLhouse" { + return + } + // Check if this has already been tweeted var tweetID int64 err := app.db.QueryRow("SELECT tweet_id FROM tweetedhouses WHERE house_id = ?", houseID).Scan(&tweetID) @@ -20,6 +25,8 @@ func tweet(app *app, houseID, text string) { } // Post to Twitter + text := fmt.Sprintf("\"%s\" on #HTMLhouse - %s/%s.html #html #web #website", title, app.cfg.HostName, houseID) + anaconda.SetConsumerKey(app.cfg.TwitterConsumerKey) anaconda.SetConsumerSecret(app.cfg.TwitterConsumerSecret) api := anaconda.NewTwitterApi(app.cfg.TwitterToken, app.cfg.TwitterTokenSecret) From 32d52a63ca4b40ddc667a3b651445fb867a86df3 Mon Sep 17 00:00:00 2001 From: Matt Baer Date: Fri, 22 Jan 2016 17:36:46 -0500 Subject: [PATCH 5/5] Add helpful error message --- construction.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/construction.go b/construction.go index bb4037b..4981788 100644 --- a/construction.go +++ b/construction.go @@ -296,7 +296,7 @@ func viewHouseStats(app *app, w http.ResponseWriter, r *http.Request) error { func viewHouses(app *app, w http.ResponseWriter, r *http.Request) error { houses, err := getPublicHouses(app) if err != nil { - fmt.Fprintf(w, ":(") + fmt.Printf("Couln't load houses: %v", err) return err }