Skip to content

Commit d3982f8

Browse files
committed
feat: DA provider (not tested)
1 parent 8264ead commit d3982f8

File tree

8 files changed

+138
-0
lines changed

8 files changed

+138
-0
lines changed

apis/settings_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ func TestSettingsList(t *testing.T) {
8585
`"patreonAuth":{`,
8686
`"mailcowAuth":{`,
8787
`"bitbucketAuth":{`,
88+
`"donationalertsAuth":{`,
8889
`"planningcenterAuth":{`,
8990
`"secret":"******"`,
9091
`"clientSecret":"******"`,
@@ -172,6 +173,7 @@ func TestSettingsSet(t *testing.T) {
172173
`"patreonAuth":{`,
173174
`"mailcowAuth":{`,
174175
`"bitbucketAuth":{`,
176+
`"donationalertsAuth":{`,
175177
`"planningcenterAuth":{`,
176178
`"secret":"******"`,
177179
`"clientSecret":"******"`,
@@ -246,6 +248,7 @@ func TestSettingsSet(t *testing.T) {
246248
`"patreonAuth":{`,
247249
`"mailcowAuth":{`,
248250
`"bitbucketAuth":{`,
251+
`"donationalertsAuth":{`,
249252
`"planningcenterAuth":{`,
250253
`"secret":"******"`,
251254
`"clientSecret":"******"`,

models/settings/settings.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ type Settings struct {
6767
MailcowAuth AuthProviderConfig `form:"mailcowAuth" json:"mailcowAuth"`
6868
BitbucketAuth AuthProviderConfig `form:"bitbucketAuth" json:"bitbucketAuth"`
6969
PlanningcenterAuth AuthProviderConfig `form:"planningcenterAuth" json:"planningcenterAuth"`
70+
DonationAlertsAuth AuthProviderConfig `form:"donationalertsAuth" json:"donationalertsAuth"`
7071
}
7172

7273
// New creates and returns a new default Settings instance.
@@ -204,6 +205,9 @@ func New() *Settings {
204205
PlanningcenterAuth: AuthProviderConfig{
205206
Enabled: false,
206207
},
208+
DonationAlertsAuth: AuthProviderConfig{
209+
Enabled: false,
210+
},
207211
}
208212
}
209213

@@ -251,6 +255,7 @@ func (s *Settings) Validate() error {
251255
validation.Field(&s.MailcowAuth),
252256
validation.Field(&s.BitbucketAuth),
253257
validation.Field(&s.PlanningcenterAuth),
258+
validation.Field(&s.DonationAlertsAuth),
254259
)
255260
}
256261

@@ -321,6 +326,7 @@ func (s *Settings) RedactClone() (*Settings, error) {
321326
&clone.MailcowAuth.ClientSecret,
322327
&clone.BitbucketAuth.ClientSecret,
323328
&clone.PlanningcenterAuth.ClientSecret,
329+
&clone.DonationAlertsAuth.ClientSecret,
324330
}
325331

326332
// mask all sensitive fields
@@ -365,6 +371,7 @@ func (s *Settings) NamedAuthProviderConfigs() map[string]AuthProviderConfig {
365371
auth.NameMailcow: s.MailcowAuth,
366372
auth.NameBitbucket: s.BitbucketAuth,
367373
auth.NamePlanningcenter: s.PlanningcenterAuth,
374+
auth.NameDonationAlerts: s.DonationAlertsAuth,
368375
}
369376
}
370377

models/settings/settings_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ func TestSettingsValidate(t *testing.T) {
8282
s.BitbucketAuth.ClientId = ""
8383
s.PlanningcenterAuth.Enabled = true
8484
s.PlanningcenterAuth.ClientId = ""
85+
s.DonationAlertsAuth.Enabled = true
86+
s.DonationAlertsAuth.ClientId = ""
8587

8688
// check if Validate() is triggering the members validate methods.
8789
err := s.Validate()
@@ -127,6 +129,7 @@ func TestSettingsValidate(t *testing.T) {
127129
`"mailcowAuth":{`,
128130
`"bitbucketAuth":{`,
129131
`"planningcenterAuth":{`,
132+
`"donationAlertsAuth":{`,
130133
}
131134

132135
errBytes, _ := json.Marshal(err)
@@ -208,6 +211,8 @@ func TestSettingsMerge(t *testing.T) {
208211
s2.BitbucketAuth.ClientId = "bitbucket_test"
209212
s2.PlanningcenterAuth.Enabled = true
210213
s2.PlanningcenterAuth.ClientId = "planningcenter_test"
214+
s2.DonationAlertsAuth.Enabled = true
215+
s2.DonationAlertsAuth.ClientId = "donationalerts_test"
211216

212217
if err := s1.Merge(s2); err != nil {
213218
t.Fatal(err)
@@ -302,6 +307,7 @@ func TestSettingsRedactClone(t *testing.T) {
302307
s1.MailcowAuth.ClientSecret = testSecret
303308
s1.BitbucketAuth.ClientSecret = testSecret
304309
s1.PlanningcenterAuth.ClientSecret = testSecret
310+
s1.DonationAlertsAuth.ClientSecret = testSecret
305311

306312
s1Bytes, err := json.Marshal(s1)
307313
if err != nil {
@@ -364,6 +370,7 @@ func TestNamedAuthProviderConfigs(t *testing.T) {
364370
s.MailcowAuth.ClientId = "mailcow_test"
365371
s.BitbucketAuth.ClientId = "bitbucket_test"
366372
s.PlanningcenterAuth.ClientId = "planningcenter_test"
373+
s.DonationAlertsAuth.ClientId = "donationalerts_test"
367374

368375
result := s.NamedAuthProviderConfigs()
369376

@@ -399,6 +406,7 @@ func TestNamedAuthProviderConfigs(t *testing.T) {
399406
`"mailcow":{"enabled":false,"clientId":"mailcow_test"`,
400407
`"bitbucket":{"enabled":false,"clientId":"bitbucket_test"`,
401408
`"planningcenter":{"enabled":false,"clientId":"planningcenter_test"`,
409+
`"donationalerts":{"enabled":false,"clientId":"donationalerts_test"`,
402410
}
403411
for _, p := range expectedParts {
404412
if !strings.Contains(encodedStr, p) {

tools/auth/auth.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,8 @@ func NewProviderByName(name string) (Provider, error) {
158158
return NewBitbucketProvider(), nil
159159
case NamePlanningcenter:
160160
return NewPlanningcenterProvider(), nil
161+
case NameDonationAlerts:
162+
return NewDonationAlertsProvider(), nil
161163
default:
162164
return nil, errors.New("Missing provider " + name)
163165
}

tools/auth/auth_test.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,4 +243,13 @@ func TestNewProviderByName(t *testing.T) {
243243
if _, ok := p.(*auth.Planningcenter); !ok {
244244
t.Error("Expected to be instance of *auth.Planningcenter")
245245
}
246+
247+
// donationalerts
248+
p, err = auth.NewProviderByName(auth.NameDonationAlerts)
249+
if err != nil {
250+
t.Errorf("Expected nil, got error %v", err)
251+
}
252+
if _, ok := p.(*auth.DonationAlerts); !ok {
253+
t.Error("Expected to be instance of *auth.DonationAlerts")
254+
}
246255
}

tools/auth/donationalerts.go

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package auth
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
"strconv"
7+
8+
"github.com/pocketbase/pocketbase/tools/types"
9+
"golang.org/x/oauth2"
10+
)
11+
12+
var _ Provider = (*DonationAlerts)(nil)
13+
14+
// NameDonationAlerts is the unique name of the Donation Alerts provider.
15+
const NameDonationAlerts string = "donationalerts"
16+
17+
// Donation Alerts allows authentication via Discord OAuth2.
18+
type DonationAlerts struct {
19+
*baseProvider
20+
}
21+
22+
// NewDiscordProvider creates a new Discord provider instance with some defaults.
23+
func NewDonationAlertsProvider() *DonationAlerts {
24+
// https://www.donationalerts.com/apidoc#authorization
25+
return &DonationAlerts{&baseProvider{
26+
ctx: context.Background(),
27+
displayName: "Donation Alerts",
28+
pkce: true,
29+
scopes: []string{"oauth-user-show"},
30+
authUrl: "https://www.donationalerts.com/oauth/authorize",
31+
tokenUrl: "https://www.donationalerts.com/oauth/token",
32+
userApiUrl: "https://www.donationalerts.com/api/v1/user/oauth",
33+
}}
34+
}
35+
36+
// FetchAuthUser returns an AuthUser instance from Discord's user api.
37+
//
38+
// API reference: https://discord.com/developers/docs/resources/user#user-object
39+
func (p *DonationAlerts) FetchAuthUser(token *oauth2.Token) (*AuthUser, error) {
40+
data, err := p.FetchRawUserData(token)
41+
if err != nil {
42+
return nil, err
43+
}
44+
45+
rawUser := map[string]any{}
46+
if err := json.Unmarshal(data, &rawUser); err != nil {
47+
return nil, err
48+
}
49+
50+
extracted := struct {
51+
Data struct {
52+
Id int `json:"id"`
53+
UniqueName string `json:"code"`
54+
Name string `json:"name"`
55+
Avatar string `json:"avatar"`
56+
Email string `json:"email"`
57+
SocketToken string `json:"socket_connection_token"`
58+
} `json:"data"`
59+
}{}
60+
if err := json.Unmarshal(data, &extracted); err != nil {
61+
return nil, err
62+
}
63+
64+
user := &AuthUser{
65+
Id: strconv.Itoa(extracted.Data.Id),
66+
Name: extracted.Data.UniqueName,
67+
Username: extracted.Data.Name,
68+
AvatarUrl: extracted.Data.Avatar,
69+
RawUser: rawUser,
70+
AccessToken: token.AccessToken,
71+
RefreshToken: token.RefreshToken,
72+
}
73+
74+
user.Expiry, _ = types.ParseDateTime(token.Expiry)
75+
76+
return user, nil
77+
}
Lines changed: 27 additions & 0 deletions
Loading

ui/src/providers.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,11 @@ export default [
133133
title: "Planning Center",
134134
logo: "planningcenter.svg",
135135
},
136+
{
137+
key: "donationalertsAuth",
138+
title: "Donation Alerts",
139+
logo: "donationalerts.svg",
140+
},
136141
{
137142
key: "oidcAuth",
138143
title: "OpenID Connect",

0 commit comments

Comments
 (0)