Last active
August 8, 2024 18:11
-
-
Save alexellis/6212c988189323dbb2806d1c7f7699ab to your computer and use it in GitHub Desktop.
sponsors.go - query whether a GitHub user is your sponsor at a given tier (dollar amount)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// LICENSE for this file: MIT | |
// Copyright: Alex Ellis, OpenFaaS Ltd 2020 | |
// Do not remove this notice | |
package handlers | |
import ( | |
"context" | |
"encoding/json" | |
"os" | |
"github.com/shurcooL/githubv4" | |
"golang.org/x/oauth2" | |
) | |
const minDollars = 25 | |
type SponsorTier struct { | |
MonthlyPriceInDollars int | |
} | |
// SponsorEntity is the User sponsoring | |
type SponsorEntity struct { | |
// SponsorUser with an annotation that expands the Union for the User type | |
SponsorUser SponsorUser `graphql:"... on User"` | |
} | |
// Sponsorable is the User receiving the sponsorshop | |
type Sponsorable struct { | |
// SponsorUser with an annotation that expands the Union for the User type | |
SponsorUser SponsorUser `graphql:"... on User"` | |
// SponsorOrganization was not strictly required, during debug the SponsorUser | |
// was populated with the org name anyway. | |
SponsorOrganization SponsorUser `graphql:"... on Organization"` | |
} | |
// SponsorUser is a User associated with either side of a | |
// sponsorship | |
type SponsorUser struct { | |
// Login name of the sponsor. | |
Login string | |
} | |
// sponsorships is the query for graphql and it limits | |
// the search to 100, since most people will not be | |
// sponsoring more than a few other developers. | |
type sponsorships struct { | |
Viewer struct { | |
Login string | |
SponsorshipsAsSponsor struct { | |
Nodes []struct { | |
SponsorEntity SponsorEntity | |
Sponsorable Sponsorable | |
Tier SponsorTier | |
} | |
} `graphql:"sponsorshipsAsSponsor(first: 100)"` | |
} | |
} | |
// IsSponsoring returns true if the login for the associated | |
// accessToken has an active sponsorship for the target login of | |
// the hard-coded dollar amount. | |
// The accessToken requires the whole "user" scope to read the | |
// dollar amount. | |
func IsSponsoring(login string, targets []string, accessToken string) (bool, error) { | |
// it's not possible to sponsor oneself | |
for _, target := range targets { | |
if target == login { | |
return true, nil | |
} | |
} | |
src := oauth2.StaticTokenSource( | |
&oauth2.Token{AccessToken: accessToken}, | |
) | |
httpClient := oauth2.NewClient(context.Background(), src) | |
client := githubv4.NewClient(httpClient) | |
var q sponsorships | |
ctx := context.Background() | |
err := client.Query(ctx, &q, map[string]interface{}{}) | |
if err != nil { | |
return false, err | |
} | |
// log.Printf("Checking %s, for: %v", login, targets) | |
// printJSON(q.Viewer.SponsorshipsAsSponsor.Nodes) | |
var users []SponsorUser | |
for _, node := range q.Viewer.SponsorshipsAsSponsor.Nodes { | |
sponsor := node.SponsorEntity.SponsorUser | |
sponsored := node.Sponsorable.SponsorUser.Login | |
for _, target := range targets { | |
if sponsored == target && | |
node.Tier.MonthlyPriceInDollars >= minDollars { | |
users = append(users, sponsor) | |
} | |
} | |
} | |
for _, s := range users { | |
if s.Login == login { | |
return true, nil | |
} | |
} | |
return false, nil | |
} | |
// printJSON is from the github.com/shurcooL/githubv4 library | |
// and prints the response for debugging. | |
func printJSON(v interface{}) { | |
w := json.NewEncoder(os.Stdout) | |
w.SetIndent("", "\t") | |
err := w.Encode(v) | |
if err != nil { | |
panic(err) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi there! You can now pass a
maintainerLogins
argument tosponsorshipsAsSponsor
to filter the returned sponsorships. For example:-- https://docs.github.com/en/graphql/overview/explorer