Patron page (#122)
* implement /patrons * bump go to 1.14 * go mod tidy * bump go in github actions
This commit is contained in:
parent
6adc88b1ff
commit
1da6129332
|
@ -0,0 +1,2 @@
|
||||||
|
nix/deps.nix linguist-vendored
|
||||||
|
nix/sources.nix linguist-vendored
|
|
@ -5,10 +5,10 @@ jobs:
|
||||||
name: Build
|
name: Build
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Set up Go 1.12
|
- name: Set up Go 1.14
|
||||||
uses: actions/setup-go@v1
|
uses: actions/setup-go@v1
|
||||||
with:
|
with:
|
||||||
go-version: 1.12
|
go-version: 1.14
|
||||||
id: go
|
id: go
|
||||||
- name: Check out code into the Go module directory
|
- name: Check out code into the Go module directory
|
||||||
uses: actions/checkout@v1
|
uses: actions/checkout@v1
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
FROM xena/go:1.13.6 AS build
|
FROM xena/go:1.14 AS build
|
||||||
ENV GOPROXY https://cache.greedo.xeserv.us
|
ENV GOPROXY https://cache.greedo.xeserv.us
|
||||||
COPY . /site
|
COPY . /site
|
||||||
WORKDIR /site
|
WORKDIR /site
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
---
|
||||||
|
title: "New Site Feature: Patron Thanks Page"
|
||||||
|
date: 2020-02-29
|
||||||
|
---
|
||||||
|
|
||||||
|
# New Site Feature: Patron Thanks Page
|
||||||
|
|
||||||
|
I've added a [patron thanks page](/patrons) to my site. I've been getting a
|
||||||
|
significant amount of money per month from my patrons and I feel this is a good
|
||||||
|
way to acknowledge them and thank them for their patronage. I wanted to have it
|
||||||
|
be _as simple as possible_, so I made it fetch a list of dollar amounts.
|
||||||
|
|
||||||
|
Here are some things I learned while writing this:
|
||||||
|
|
||||||
|
- If you are going to interact with the patreon API in go, use
|
||||||
|
[`github.com/mxpv/patreon-go`][patreongo], not `gopkg.in/mxpv/patreon-go.v1`
|
||||||
|
or `gopkg.in/mxpv/patreon-go.v2`. The packages on gopkg.in are NOT compatible
|
||||||
|
with Go modules in very bizarre ways.
|
||||||
|
- When using refresh tokens in OAuth2, do not set the expiry date to be
|
||||||
|
_negative_ like the patreon-go examples show. This will brick your token and
|
||||||
|
make you have to reprovision it.
|
||||||
|
- Patreon clients can either be for API version 1 or API version 2. There is no
|
||||||
|
way to have a Patreon token that works for both API versions.
|
||||||
|
- The patreon-go package only supports API version 1 and doesn't document this
|
||||||
|
anywhere.
|
||||||
|
- Patreon's error messages are vague and not helpful when trying to figure out
|
||||||
|
that you broke your token with a negative expiry date.
|
||||||
|
- I may need to set the Patreon information every month for the rest of the time
|
||||||
|
I maintain this site code. This could get odd. I made a guide for myself in
|
||||||
|
the [docs folder of the site repo][docsfolder].
|
||||||
|
- The Patreon API doesn't let you submit new posts. I wanted to add Patreon to
|
||||||
|
my syndication server, but apparently that's impossible. My [RSS
|
||||||
|
feed](/blog.rss), [Atom feed](/blog.atom) and [JSON feed](/blog.json) should
|
||||||
|
let you keep up to date in the meantime.
|
||||||
|
|
||||||
|
Let me know how you like this. I went back and forth on displaying monetary
|
||||||
|
amounts on that page, but ultimately decided not to show them there for
|
||||||
|
confidentiality reasons. If this is a bad idea, please let me know and I can put
|
||||||
|
the money amounts back.
|
||||||
|
|
||||||
|
I'm working on a more detailed post about [pa'i][pahi] that includes benchmarks
|
||||||
|
for some artificial and realistic workloads. I'm also working on integrating it
|
||||||
|
into the [wamscloud][wasmcloud] prototype, but it's fairly slow going at the
|
||||||
|
moment.
|
||||||
|
|
||||||
|
Be well.
|
||||||
|
|
||||||
|
[patreongo]: https://github.com/mxpv/patreon-go
|
||||||
|
[docsfolder]: https://github.com/Xe/site/tree/master/docs
|
||||||
|
[pahi]: https://github.com/Xe/pahi
|
||||||
|
[wasmcloud]: https://tulpa.dev/within/wasmcloud
|
||||||
|
|
|
@ -13,6 +13,7 @@ import (
|
||||||
"christine.website/cmd/site/internal/middleware"
|
"christine.website/cmd/site/internal/middleware"
|
||||||
"christine.website/jsonfeed"
|
"christine.website/jsonfeed"
|
||||||
"github.com/gorilla/feeds"
|
"github.com/gorilla/feeds"
|
||||||
|
_ "github.com/joho/godotenv/autoload"
|
||||||
"github.com/povilasv/prommod"
|
"github.com/povilasv/prommod"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||||
|
@ -60,6 +61,7 @@ type Site struct {
|
||||||
Gallery blog.Posts
|
Gallery blog.Posts
|
||||||
Resume template.HTML
|
Resume template.HTML
|
||||||
Series []string
|
Series []string
|
||||||
|
patrons []string
|
||||||
|
|
||||||
rssFeed *feeds.Feed
|
rssFeed *feeds.Feed
|
||||||
jsonFeed *jsonfeed.Feed
|
jsonFeed *jsonfeed.Feed
|
||||||
|
@ -84,10 +86,20 @@ func (s *Site) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
middleware.RequestID(s.xffmw.Handler(ex.HTTPLog(s.mux))).ServeHTTP(w, r)
|
middleware.RequestID(s.xffmw.Handler(ex.HTTPLog(s.mux))).ServeHTTP(w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
var arbDate = time.Date(2020, time.January, 9, 0, 0, 0, 0, time.UTC)
|
var arbDate = time.Date(2020, time.February, 29, 0, 0, 0, 0, time.UTC)
|
||||||
|
|
||||||
// Build creates a new Site instance or fails.
|
// Build creates a new Site instance or fails.
|
||||||
func Build() (*Site, error) {
|
func Build() (*Site, error) {
|
||||||
|
pc, err := NewPatreonClient()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
pledges, err := GetPledges(pc)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
smi := sitemap.New()
|
smi := sitemap.New()
|
||||||
smi.Add(&sitemap.URL{
|
smi.Add(&sitemap.URL{
|
||||||
Loc: "https://christine.website/resume",
|
Loc: "https://christine.website/resume",
|
||||||
|
@ -107,6 +119,12 @@ func Build() (*Site, error) {
|
||||||
ChangeFreq: sitemap.Monthly,
|
ChangeFreq: sitemap.Monthly,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
smi.Add(&sitemap.URL{
|
||||||
|
Loc: "https://christine.website/patrons",
|
||||||
|
LastMod: &arbDate,
|
||||||
|
ChangeFreq: sitemap.Weekly,
|
||||||
|
})
|
||||||
|
|
||||||
smi.Add(&sitemap.URL{
|
smi.Add(&sitemap.URL{
|
||||||
Loc: "https://christine.website/blog",
|
Loc: "https://christine.website/blog",
|
||||||
LastMod: &arbDate,
|
LastMod: &arbDate,
|
||||||
|
@ -143,6 +161,8 @@ func Build() (*Site, error) {
|
||||||
},
|
},
|
||||||
mux: http.NewServeMux(),
|
mux: http.NewServeMux(),
|
||||||
xffmw: xffmw,
|
xffmw: xffmw,
|
||||||
|
|
||||||
|
patrons: pledges,
|
||||||
}
|
}
|
||||||
|
|
||||||
posts, err := blog.LoadPosts("./blog/", "blog")
|
posts, err := blog.LoadPosts("./blog/", "blog")
|
||||||
|
@ -215,6 +235,7 @@ func Build() (*Site, error) {
|
||||||
s.renderTemplatePage("index.html", nil).ServeHTTP(w, r)
|
s.renderTemplatePage("index.html", nil).ServeHTTP(w, r)
|
||||||
})
|
})
|
||||||
s.mux.Handle("/metrics", promhttp.Handler())
|
s.mux.Handle("/metrics", promhttp.Handler())
|
||||||
|
s.mux.Handle("/patrons", middleware.Metrics("patrons", s.renderTemplatePage("patrons.html", s.patrons)))
|
||||||
s.mux.Handle("/resume", middleware.Metrics("resume", s.renderTemplatePage("resume.html", s.Resume)))
|
s.mux.Handle("/resume", middleware.Metrics("resume", s.renderTemplatePage("resume.html", s.Resume)))
|
||||||
s.mux.Handle("/blog", middleware.Metrics("blog", s.renderTemplatePage("blogindex.html", s.Posts)))
|
s.mux.Handle("/blog", middleware.Metrics("blog", s.renderTemplatePage("blogindex.html", s.Posts)))
|
||||||
s.mux.Handle("/talks", middleware.Metrics("talks", s.renderTemplatePage("talkindex.html", s.Talks)))
|
s.mux.Handle("/talks", middleware.Metrics("talks", s.renderTemplatePage("talkindex.html", s.Talks)))
|
||||||
|
|
|
@ -0,0 +1,112 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"sort"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/mxpv/patreon-go"
|
||||||
|
"golang.org/x/oauth2"
|
||||||
|
"within.website/ln"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewPatreonClient() (*patreon.Client, error) {
|
||||||
|
for _, name := range []string{"CLIENT_ID", "CLIENT_SECRET", "ACCESS_TOKEN", "REFRESH_TOKEN"} {
|
||||||
|
if os.Getenv("PATREON_"+name) == "" {
|
||||||
|
return nil, fmt.Errorf("wanted envvar PATREON_%s", name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
config := oauth2.Config{
|
||||||
|
ClientID: os.Getenv("PATREON_CLIENT_ID"),
|
||||||
|
ClientSecret: os.Getenv("PATREON_CLIENT_SECRET"),
|
||||||
|
Endpoint: oauth2.Endpoint{
|
||||||
|
AuthURL: patreon.AuthorizationURL,
|
||||||
|
TokenURL: patreon.AccessTokenURL,
|
||||||
|
},
|
||||||
|
Scopes: []string{"users", "campaigns", "pledges", "pledges-to-me", "my-campaign"},
|
||||||
|
}
|
||||||
|
|
||||||
|
token := oauth2.Token{
|
||||||
|
AccessToken: os.Getenv("PATREON_ACCESS_TOKEN"),
|
||||||
|
RefreshToken: os.Getenv("PATREON_REFRESH_TOKEN"),
|
||||||
|
// Must be non-nil, otherwise token will not be expired
|
||||||
|
Expiry: time.Now().Add(90 * 24 * time.Hour),
|
||||||
|
}
|
||||||
|
|
||||||
|
tc := config.Client(context.Background(), &token)
|
||||||
|
|
||||||
|
trans := tc.Transport
|
||||||
|
tc.Transport = lnLoggingTransport{next: trans}
|
||||||
|
client := patreon.NewClient(tc)
|
||||||
|
|
||||||
|
return client, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetPledges(pc *patreon.Client) ([]string, error) {
|
||||||
|
campaign, err := pc.FetchCampaign()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("campaign fetch error: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
campaignID := campaign.Data[0].ID
|
||||||
|
|
||||||
|
cursor := ""
|
||||||
|
var result []string
|
||||||
|
|
||||||
|
for {
|
||||||
|
pledgesResponse, err := pc.FetchPledges(campaignID, patreon.WithPageSize(25), patreon.WithCursor(cursor))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
users := make(map[string]*patreon.User)
|
||||||
|
for _, item := range pledgesResponse.Included.Items {
|
||||||
|
u, ok := item.(*patreon.User)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
users[u.ID] = u
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, pledge := range pledgesResponse.Data {
|
||||||
|
pid := pledge.Relationships.Patron.Data.ID
|
||||||
|
patronFullName := users[pid].Attributes.FullName
|
||||||
|
|
||||||
|
result = append(result, patronFullName)
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor = pledgesResponse.Links.Next
|
||||||
|
if cursor == "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Strings(result)
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type lnLoggingTransport struct{ next http.RoundTripper }
|
||||||
|
|
||||||
|
func (l lnLoggingTransport) RoundTrip(r *http.Request) (*http.Response, error) {
|
||||||
|
ctx := r.Context()
|
||||||
|
f := ln.F{
|
||||||
|
"url": r.URL.String(),
|
||||||
|
"has_token": r.Header.Get("Authorization") != "",
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := l.next.RoundTrip(r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
f["status"] = resp.Status
|
||||||
|
|
||||||
|
ln.Log(ctx, f)
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
|
@ -0,0 +1,77 @@
|
||||||
|
#+TITLE: Patron Page
|
||||||
|
|
||||||
|
#+BEGIN: clocktable :maxlevel 2 :emphasize nil :scope file
|
||||||
|
#+CAPTION: Clock summary at [2020-02-29 Sat 20:47]
|
||||||
|
| Headline | Time | |
|
||||||
|
|------------------------------------------+--------+------|
|
||||||
|
| *Total time* | *1:36* | |
|
||||||
|
|------------------------------------------+--------+------|
|
||||||
|
| figure out how to get list of patrons | 1:05 | |
|
||||||
|
| \_ get patreon credentials into site | | 0:08 |
|
||||||
|
| \_ figure out patreon id of my campaign | | 0:25 |
|
||||||
|
| \_ get list of patrons | | 0:25 |
|
||||||
|
| \_ show in HTML | | 0:07 |
|
||||||
|
| figure out how to handle the secrets... | 0:03 | |
|
||||||
|
| Links | 0:28 | |
|
||||||
|
| \_ Announcement blogpost | | 0:28 |
|
||||||
|
#+END: clocktable
|
||||||
|
|
||||||
|
* DONE figure out how to get list of patrons
|
||||||
|
CLOSED: [2020-02-29 Sat 20:18]
|
||||||
|
** DONE get patreon credentials into site
|
||||||
|
CLOSED: [2020-02-29 Sat 19:14]
|
||||||
|
:LOGBOOK:
|
||||||
|
CLOCK: [2020-02-29 Sat 19:06]--[2020-02-29 Sat 19:14] => 0:08
|
||||||
|
:END:
|
||||||
|
|
||||||
|
Added envvars
|
||||||
|
|
||||||
|
+ =PATREON_CLIENT_ID=
|
||||||
|
+ =PATREON_CLIENT_SECRET=
|
||||||
|
+ =PATREON_ACCESS_TOKEN=
|
||||||
|
+ =PATREON_REFRESH_TOKEN=
|
||||||
|
** DONE figure out patreon id of my campaign
|
||||||
|
CLOSED: [2020-02-29 Sat 19:39]
|
||||||
|
:LOGBOOK:
|
||||||
|
CLOCK: [2020-02-29 Sat 19:14]--[2020-02-29 Sat 19:39] => 0:25
|
||||||
|
:END:
|
||||||
|
** DONE get list of patrons
|
||||||
|
CLOSED: [2020-02-29 Sat 20:05]
|
||||||
|
:LOGBOOK:
|
||||||
|
CLOCK: [2020-02-29 Sat 19:40]--[2020-02-29 Sat 20:05] => 0:25
|
||||||
|
:END:
|
||||||
|
** DONE show in HTML
|
||||||
|
CLOSED: [2020-02-29 Sat 20:12]
|
||||||
|
:LOGBOOK:
|
||||||
|
CLOCK: [2020-02-29 Sat 20:05]--[2020-02-29 Sat 20:12] => 0:07
|
||||||
|
:END:
|
||||||
|
* DONE figure out how to handle the secrets for patreon
|
||||||
|
CLOSED: [2020-02-29 Sat 20:18]
|
||||||
|
:LOGBOOK:
|
||||||
|
CLOCK: [2020-02-29 Sat 20:15]--[2020-02-29 Sat 20:18] => 0:03
|
||||||
|
:END:
|
||||||
|
Currently putting them in the dyson secret store, will need to figure out
|
||||||
|
something else for dhall.
|
||||||
|
* DONE Links
|
||||||
|
CLOSED: [2020-02-29 Sat 20:47]
|
||||||
|
** DONE Add link in footer
|
||||||
|
CLOSED: [2020-02-29 Sat 20:13]
|
||||||
|
** DONE Add into sitemap
|
||||||
|
CLOSED: [2020-02-29 Sat 20:13]
|
||||||
|
** DONE Announcement blogpost
|
||||||
|
CLOSED: [2020-02-29 Sat 20:47]
|
||||||
|
:LOGBOOK:
|
||||||
|
CLOCK: [2020-02-29 Sat 20:37]--[2020-02-29 Sat 20:47] => 0:10
|
||||||
|
CLOCK: [2020-02-29 Sat 20:19]--[2020-02-29 Sat 20:37] => 0:18
|
||||||
|
:END:
|
||||||
|
|
||||||
|
* How to refresh credentials
|
||||||
|
|
||||||
|
1. Go to https://www.patreon.com/portal/registration/register-clients
|
||||||
|
2. Open Mi (API v1)
|
||||||
|
3. Hit "Refresh Token"
|
||||||
|
4. Copy access token and refresh token to
|
||||||
|
~/code/within-terraform-secret/christinewebsite.env as =PATREON_ACCESS_TOKEN=
|
||||||
|
and =PATREON_REFRESH_TOKEN=
|
||||||
|
5. Commit file to repo and push
|
||||||
|
6. Retry deployment of the site
|
3
go.mod
3
go.mod
|
@ -3,6 +3,8 @@ module christine.website
|
||||||
require (
|
require (
|
||||||
github.com/celrenheit/sandflake v0.0.0-20190410195419-50a943690bc2
|
github.com/celrenheit/sandflake v0.0.0-20190410195419-50a943690bc2
|
||||||
github.com/gorilla/feeds v1.1.1
|
github.com/gorilla/feeds v1.1.1
|
||||||
|
github.com/joho/godotenv v1.3.0
|
||||||
|
github.com/mxpv/patreon-go v0.0.0-20190917022727-646111f1d983
|
||||||
github.com/povilasv/prommod v0.0.12
|
github.com/povilasv/prommod v0.0.12
|
||||||
github.com/prometheus/client_golang v1.4.1
|
github.com/prometheus/client_golang v1.4.1
|
||||||
github.com/russross/blackfriday v2.0.0+incompatible
|
github.com/russross/blackfriday v2.0.0+incompatible
|
||||||
|
@ -10,6 +12,7 @@ require (
|
||||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
|
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
|
||||||
github.com/snabb/sitemap v1.0.0
|
github.com/snabb/sitemap v1.0.0
|
||||||
github.com/stretchr/testify v1.4.0
|
github.com/stretchr/testify v1.4.0
|
||||||
|
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
|
||||||
gopkg.in/yaml.v2 v2.2.8
|
gopkg.in/yaml.v2 v2.2.8
|
||||||
within.website/ln v0.8.0
|
within.website/ln v0.8.0
|
||||||
)
|
)
|
||||||
|
|
13
go.sum
13
go.sum
|
@ -1,3 +1,4 @@
|
||||||
|
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
|
@ -32,6 +33,8 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/gorilla/feeds v1.1.1 h1:HwKXxqzcRNg9to+BbvJog4+f3s/xzvtZXICcQGutYfY=
|
github.com/gorilla/feeds v1.1.1 h1:HwKXxqzcRNg9to+BbvJog4+f3s/xzvtZXICcQGutYfY=
|
||||||
github.com/gorilla/feeds v1.1.1/go.mod h1:Nk0jZrvPFZX1OBe5NPiddPw7CfwF6Q9eqzaBbaightA=
|
github.com/gorilla/feeds v1.1.1/go.mod h1:Nk0jZrvPFZX1OBe5NPiddPw7CfwF6Q9eqzaBbaightA=
|
||||||
|
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
|
||||||
|
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
|
||||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
|
@ -49,6 +52,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ
|
||||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||||
|
github.com/mxpv/patreon-go v0.0.0-20190917022727-646111f1d983 h1:r32TFg+FHLnoF8PCqCQNp+R9EjMBuP62FXkD/Eqp9Us=
|
||||||
|
github.com/mxpv/patreon-go v0.0.0-20190917022727-646111f1d983/go.mod h1:ksYjm2GAbGlgIP7jO9Q5/AdyE4MwwEbgQ+lFMx3hyiM=
|
||||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
@ -59,8 +64,6 @@ github.com/povilasv/prommod v0.0.12/go.mod h1:GnuK7wLoVBwZXj8bhbJNx/xFSldy7Q49A4
|
||||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||||
github.com/prometheus/client_golang v1.0.0 h1:vrDKnkGzuGvhNAL56c7DBz29ZL+KxnoR0x7enabFceM=
|
github.com/prometheus/client_golang v1.0.0 h1:vrDKnkGzuGvhNAL56c7DBz29ZL+KxnoR0x7enabFceM=
|
||||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||||
github.com/prometheus/client_golang v1.4.0 h1:YVIb/fVcOTMSqtqZWSKnHpSLBxu8DKgxq8z6RuBZwqI=
|
|
||||||
github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
|
|
||||||
github.com/prometheus/client_golang v1.4.1 h1:FFSuS004yOQEtDdTq+TAOLP5xUq63KqAFYyOi8zA+Y8=
|
github.com/prometheus/client_golang v1.4.1 h1:FFSuS004yOQEtDdTq+TAOLP5xUq63KqAFYyOi8zA+Y8=
|
||||||
github.com/prometheus/client_golang v1.4.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
|
github.com/prometheus/client_golang v1.4.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
|
||||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||||
|
@ -99,10 +102,14 @@ github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJy
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980 h1:dfGZHvZk057jK2MCeWus/TowKpJ8y4AmooUzdBSR9GU=
|
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980 h1:dfGZHvZk057jK2MCeWus/TowKpJ8y4AmooUzdBSR9GU=
|
||||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
@ -116,6 +123,8 @@ golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508=
|
||||||
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||||
|
|
|
@ -1,5 +1,14 @@
|
||||||
# file generated from go.mod using vgo2nix (https://github.com/adisbladis/vgo2nix)
|
# file generated from go.mod using vgo2nix (https://github.com/adisbladis/vgo2nix)
|
||||||
[
|
[
|
||||||
|
{
|
||||||
|
goPackagePath = "cloud.google.com/go";
|
||||||
|
fetch = {
|
||||||
|
type = "git";
|
||||||
|
url = "https://code.googlesource.com/gocloud";
|
||||||
|
rev = "v0.34.0";
|
||||||
|
sha256 = "1kclgclwar3r37zbvb9gg3qxbgzkb50zk3s9778zlh2773qikmai";
|
||||||
|
};
|
||||||
|
}
|
||||||
{
|
{
|
||||||
goPackagePath = "github.com/alecthomas/template";
|
goPackagePath = "github.com/alecthomas/template";
|
||||||
fetch = {
|
fetch = {
|
||||||
|
@ -126,6 +135,15 @@
|
||||||
sha256 = "1lwqibra4hyzx0jhaz12rfhfnw73bmdf8cn9r51nqidk8k7zf7sg";
|
sha256 = "1lwqibra4hyzx0jhaz12rfhfnw73bmdf8cn9r51nqidk8k7zf7sg";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
goPackagePath = "github.com/joho/godotenv";
|
||||||
|
fetch = {
|
||||||
|
type = "git";
|
||||||
|
url = "https://github.com/joho/godotenv";
|
||||||
|
rev = "v1.3.0";
|
||||||
|
sha256 = "0ri8if0pc3x6jg4c3i8wr58xyfpxkwmcjk3rp8gb398a1aa3gpjm";
|
||||||
|
};
|
||||||
|
}
|
||||||
{
|
{
|
||||||
goPackagePath = "github.com/json-iterator/go";
|
goPackagePath = "github.com/json-iterator/go";
|
||||||
fetch = {
|
fetch = {
|
||||||
|
@ -225,6 +243,15 @@
|
||||||
sha256 = "0nbrnpk7bkmqg9mzwsxlm0y8m7s9qd9phr1q30qlx2qmdmz7c1mf";
|
sha256 = "0nbrnpk7bkmqg9mzwsxlm0y8m7s9qd9phr1q30qlx2qmdmz7c1mf";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
goPackagePath = "github.com/mxpv/patreon-go";
|
||||||
|
fetch = {
|
||||||
|
type = "git";
|
||||||
|
url = "https://github.com/mxpv/patreon-go";
|
||||||
|
rev = "646111f1d983";
|
||||||
|
sha256 = "0cksf3andl8z04lychay2j0l8wrpdq7j5pdb6zy5yr4990iab6aa";
|
||||||
|
};
|
||||||
|
}
|
||||||
{
|
{
|
||||||
goPackagePath = "github.com/pkg/errors";
|
goPackagePath = "github.com/pkg/errors";
|
||||||
fetch = {
|
fetch = {
|
||||||
|
@ -378,6 +405,15 @@
|
||||||
sha256 = "18xj31h70m7xxb7gc86n9i21w6d7djbjz67zfaljm4jqskz6hxkf";
|
sha256 = "18xj31h70m7xxb7gc86n9i21w6d7djbjz67zfaljm4jqskz6hxkf";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
goPackagePath = "golang.org/x/oauth2";
|
||||||
|
fetch = {
|
||||||
|
type = "git";
|
||||||
|
url = "https://go.googlesource.com/oauth2";
|
||||||
|
rev = "bf48bf16ab8d";
|
||||||
|
sha256 = "1sirdib60zwmh93kf9qrx51r8544k1p9rs5mk0797wibz3m4mrdg";
|
||||||
|
};
|
||||||
|
}
|
||||||
{
|
{
|
||||||
goPackagePath = "golang.org/x/sync";
|
goPackagePath = "golang.org/x/sync";
|
||||||
fetch = {
|
fetch = {
|
||||||
|
@ -414,6 +450,15 @@
|
||||||
sha256 = "1yjfi1bk9xb81lqn85nnm13zz725wazvrx3b50hx19qmwg7a4b0c";
|
sha256 = "1yjfi1bk9xb81lqn85nnm13zz725wazvrx3b50hx19qmwg7a4b0c";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
goPackagePath = "google.golang.org/appengine";
|
||||||
|
fetch = {
|
||||||
|
type = "git";
|
||||||
|
url = "https://github.com/golang/appengine";
|
||||||
|
rev = "v1.4.0";
|
||||||
|
sha256 = "06zl7w4sxgdq2pl94wy9ncii6h0z3szl4xpqds0sv3b3wbdlhbnn";
|
||||||
|
};
|
||||||
|
}
|
||||||
{
|
{
|
||||||
goPackagePath = "gopkg.in/alecthomas/kingpin.v2";
|
goPackagePath = "gopkg.in/alecthomas/kingpin.v2";
|
||||||
fetch = {
|
fetch = {
|
24
shell.nix
24
shell.nix
|
@ -2,10 +2,26 @@ let
|
||||||
sources = import ./nix/sources.nix;
|
sources = import ./nix/sources.nix;
|
||||||
pkgs = import sources.nixpkgs { };
|
pkgs = import sources.nixpkgs { };
|
||||||
niv = (import sources.niv { }).niv;
|
niv = (import sources.niv { }).niv;
|
||||||
dhall-yaml =
|
dhallpkgs = import sources.easy-dhall-nix { inherit pkgs; };
|
||||||
(import sources.easy-dhall-nix { inherit pkgs; }).dhall-yaml-simple;
|
dhall-yaml = dhallpkgs.dhall-yaml-simple;
|
||||||
|
dhall = dhallpkgs.dhall-simple;
|
||||||
xepkgs = import sources.xepkgs { inherit pkgs; };
|
xepkgs = import sources.xepkgs { inherit pkgs; };
|
||||||
vgo2nix = import sources.vgo2nix { inherit pkgs; };
|
vgo2nix = import sources.vgo2nix { inherit pkgs; };
|
||||||
in pkgs.mkShell {
|
in with pkgs;
|
||||||
buildInputs = [ pkgs.go xepkgs.gopls dhall-yaml niv vgo2nix ];
|
with xepkgs;
|
||||||
|
mkShell {
|
||||||
|
buildInputs = [
|
||||||
|
# Go tools
|
||||||
|
go
|
||||||
|
goimports
|
||||||
|
gopls
|
||||||
|
vgo2nix
|
||||||
|
|
||||||
|
# kubernetes deployment
|
||||||
|
dhall
|
||||||
|
dhall-yaml
|
||||||
|
|
||||||
|
# dependency manager
|
||||||
|
niv
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
2
site.nix
2
site.nix
|
@ -8,7 +8,7 @@ buildGoPackage rec {
|
||||||
version = "latest";
|
version = "latest";
|
||||||
goPackagePath = "christine.website";
|
goPackagePath = "christine.website";
|
||||||
src = ./.;
|
src = ./.;
|
||||||
goDeps = ./deps.nix;
|
goDeps = ./nix/deps.nix;
|
||||||
allowGoReference = false;
|
allowGoReference = false;
|
||||||
|
|
||||||
preBuild = ''
|
preBuild = ''
|
||||||
|
|
|
@ -68,7 +68,7 @@
|
||||||
<footer>
|
<footer>
|
||||||
<blockquote>Copyright 2020 Christine Dodrill. Any and all opinions listed here are my own and not representative of my employers; future, past and present.</blockquote>
|
<blockquote>Copyright 2020 Christine Dodrill. Any and all opinions listed here are my own and not representative of my employers; future, past and present.</blockquote>
|
||||||
<br />
|
<br />
|
||||||
<p>Like what you see? Donate on <a href="https://www.patreon.com/cadey">Patreon</a>!</p>
|
<p>Like what you see? Donate on <a href="https://www.patreon.com/cadey">Patreon</a> like <a href="/patrons">these awesome people</a>!</p>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
{{ define "title" }}
|
||||||
|
<title>Patrons - Christine Dodrill</title>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{ define "content" }}
|
||||||
|
<h1>Patrons</h1>
|
||||||
|
|
||||||
|
<p>These awesome people donate to me on <a href="https://patreon.com/cadey">Patreon</a>. If you would like to show up in this list, please donate to me on Patreon. This is refreshed every time the site is deployed.</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<ul>
|
||||||
|
{{- range . }}
|
||||||
|
<li>{{ . }}</li>
|
||||||
|
{{- end }}
|
||||||
|
</ul>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>Thank you so much! Your support helps make my projects possible.</p>
|
||||||
|
|
||||||
|
{{ end }}
|
Loading…
Reference in New Issue