Add Discord unlinking
This commit is contained in:
parent
d92bf9a9b8
commit
4c84bd2860
|
@ -273,7 +273,7 @@ func GetCurrentUserAsOAuth(ctx context.Context, accessToken string) (*User, erro
|
||||||
}
|
}
|
||||||
|
|
||||||
func AddGuildMemberRole(ctx context.Context, userID, roleID string) error {
|
func AddGuildMemberRole(ctx context.Context, userID, roleID string) error {
|
||||||
const name = "Delete Message"
|
const name = "Add Guild Member Role"
|
||||||
|
|
||||||
path := fmt.Sprintf("/guilds/%s/members/%s/roles/%s", config.Config.Discord.GuildID, userID, roleID)
|
path := fmt.Sprintf("/guilds/%s/members/%s/roles/%s", config.Config.Discord.GuildID, userID, roleID)
|
||||||
res, err := doWithRateLimiting(ctx, name, func(ctx context.Context) *http.Request {
|
res, err := doWithRateLimiting(ctx, name, func(ctx context.Context) *http.Request {
|
||||||
|
@ -292,6 +292,27 @@ func AddGuildMemberRole(ctx context.Context, userID, roleID string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func RemoveGuildMemberRole(ctx context.Context, userID, roleID string) error {
|
||||||
|
const name = "Remove Guild Member Role"
|
||||||
|
|
||||||
|
path := fmt.Sprintf("/guilds/%s/members/%s/roles/%s", config.Config.Discord.GuildID, userID, roleID)
|
||||||
|
logging.ExtractLogger(ctx).Warn().Str("path", path).Msg("I dunno")
|
||||||
|
res, err := doWithRateLimiting(ctx, name, func(ctx context.Context) *http.Request {
|
||||||
|
return makeRequest(ctx, http.MethodDelete, path, nil)
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
if res.StatusCode != http.StatusNoContent {
|
||||||
|
logErrorResponse(ctx, name, res, "")
|
||||||
|
return oops.New(nil, "got unexpected status code when removing role")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func logErrorResponse(ctx context.Context, name string, res *http.Response, msg string) {
|
func logErrorResponse(ctx context.Context, name string, res *http.Response, msg string) {
|
||||||
dump, err := httputil.DumpResponse(res, true)
|
dump, err := httputil.DumpResponse(res, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -561,6 +561,12 @@ func BuildDiscordOAuthCallback() string {
|
||||||
return Url("/_discord_callback", nil)
|
return Url("/_discord_callback", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var RegexDiscordUnlink = regexp.MustCompile("^/_discord_unlink$")
|
||||||
|
|
||||||
|
func BuildDiscordUnlink() string {
|
||||||
|
return Url("/_discord_unlink", nil)
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Assets
|
* Assets
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -5,8 +5,13 @@ Wow a discord
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
{{ with .DiscordUser }}
|
{{ with .DiscordUser }}
|
||||||
<img src="{{ .Avatar }}">
|
<div>
|
||||||
{{ .Username }}#{{ .Discriminator }}
|
<img src="{{ .Avatar }}">
|
||||||
|
{{ .Username }}#{{ .Discriminator }}
|
||||||
|
</div>
|
||||||
|
<form action="{{ $.UnlinkURL }}" method="POST">
|
||||||
|
<button>Unlink Account</button>
|
||||||
|
</form>
|
||||||
{{ else }}
|
{{ else }}
|
||||||
<a href="{{ $.AuthorizeURL }}">Link your account</a>
|
<a href="{{ $.AuthorizeURL }}">Link your account</a>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
|
@ -41,6 +41,7 @@ func DiscordTest(c *RequestContext) ResponseData {
|
||||||
templates.BaseData
|
templates.BaseData
|
||||||
DiscordUser *templates.DiscordUser
|
DiscordUser *templates.DiscordUser
|
||||||
AuthorizeURL string
|
AuthorizeURL string
|
||||||
|
UnlinkURL string
|
||||||
}
|
}
|
||||||
|
|
||||||
baseData := getBaseData(c)
|
baseData := getBaseData(c)
|
||||||
|
@ -56,6 +57,7 @@ func DiscordTest(c *RequestContext) ResponseData {
|
||||||
td := templateData{
|
td := templateData{
|
||||||
BaseData: baseData,
|
BaseData: baseData,
|
||||||
AuthorizeURL: fmt.Sprintf("https://discord.com/api/oauth2/authorize?%s", params.Encode()),
|
AuthorizeURL: fmt.Sprintf("https://discord.com/api/oauth2/authorize?%s", params.Encode()),
|
||||||
|
UnlinkURL: hmnurl.BuildDiscordUnlink(),
|
||||||
}
|
}
|
||||||
|
|
||||||
if userDiscord != nil {
|
if userDiscord != nil {
|
||||||
|
@ -111,12 +113,13 @@ func DiscordOAuthCallback(c *RequestContext) ResponseData {
|
||||||
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch Discord user info"))
|
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch Discord user info"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Add the role on Discord
|
// Add the role on Discord
|
||||||
err = discord.AddGuildMemberRole(c.Context(), user.ID, config.Config.Discord.MemberRoleID)
|
err = discord.AddGuildMemberRole(c.Context(), user.ID, config.Config.Discord.MemberRoleID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to add member role"))
|
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to add member role"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add the user to our database
|
||||||
_, err = c.Conn.Exec(c.Context(),
|
_, err = c.Conn.Exec(c.Context(),
|
||||||
`
|
`
|
||||||
INSERT INTO handmade_discorduser (username, discriminator, access_token, refresh_token, avatar, locale, userid, expiry, hmn_user_id)
|
INSERT INTO handmade_discorduser (username, discriminator, access_token, refresh_token, avatar, locale, userid, expiry, hmn_user_id)
|
||||||
|
@ -138,3 +141,51 @@ func DiscordOAuthCallback(c *RequestContext) ResponseData {
|
||||||
|
|
||||||
return c.Redirect(hmnurl.BuildDiscordTest(), http.StatusSeeOther)
|
return c.Redirect(hmnurl.BuildDiscordTest(), http.StatusSeeOther)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func DiscordUnlink(c *RequestContext) ResponseData {
|
||||||
|
tx, err := c.Conn.Begin(c.Context())
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer tx.Rollback(c.Context())
|
||||||
|
|
||||||
|
iDiscordUser, err := db.QueryOne(c.Context(), tx, models.DiscordUser{},
|
||||||
|
`
|
||||||
|
SELECT $columns
|
||||||
|
FROM handmade_discorduser
|
||||||
|
WHERE hmn_user_id = $1
|
||||||
|
`,
|
||||||
|
c.CurrentUser.ID,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, db.ErrNoMatchingRows) {
|
||||||
|
return c.Redirect(hmnurl.BuildDiscordTest(), http.StatusSeeOther)
|
||||||
|
} else {
|
||||||
|
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to get Discord user for unlink"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
discordUser := iDiscordUser.(*models.DiscordUser)
|
||||||
|
|
||||||
|
_, err = tx.Exec(c.Context(),
|
||||||
|
`
|
||||||
|
DELETE FROM handmade_discorduser
|
||||||
|
WHERE id = $1
|
||||||
|
`,
|
||||||
|
discordUser.ID,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to delete Discord user"))
|
||||||
|
}
|
||||||
|
|
||||||
|
err = tx.Commit(c.Context())
|
||||||
|
if err != nil {
|
||||||
|
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to commit Discord user delete"))
|
||||||
|
}
|
||||||
|
|
||||||
|
err = discord.RemoveGuildMemberRole(c.Context(), discordUser.UserID, config.Config.Discord.MemberRoleID)
|
||||||
|
if err != nil {
|
||||||
|
c.Logger.Warn().Err(err).Msg("failed to remove member role on unlink")
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Redirect(hmnurl.BuildDiscordTest(), http.StatusSeeOther)
|
||||||
|
}
|
||||||
|
|
|
@ -199,6 +199,7 @@ func NewWebsiteRoutes(conn *pgxpool.Pool, perfCollector *perf.PerfCollector) htt
|
||||||
|
|
||||||
mainRoutes.GET(hmnurl.RegexDiscordTest, authMiddleware(DiscordTest)) // TODO: Delete this route
|
mainRoutes.GET(hmnurl.RegexDiscordTest, authMiddleware(DiscordTest)) // TODO: Delete this route
|
||||||
mainRoutes.GET(hmnurl.RegexDiscordOAuthCallback, authMiddleware(DiscordOAuthCallback))
|
mainRoutes.GET(hmnurl.RegexDiscordOAuthCallback, authMiddleware(DiscordOAuthCallback))
|
||||||
|
mainRoutes.POST(hmnurl.RegexDiscordUnlink, authMiddleware(DiscordUnlink))
|
||||||
|
|
||||||
mainRoutes.GET(hmnurl.RegexProjectCSS, ProjectCSS)
|
mainRoutes.GET(hmnurl.RegexProjectCSS, ProjectCSS)
|
||||||
mainRoutes.GET(hmnurl.RegexEditorPreviewsJS, func(c *RequestContext) ResponseData {
|
mainRoutes.GET(hmnurl.RegexEditorPreviewsJS, func(c *RequestContext) ResponseData {
|
||||||
|
|
Loading…
Reference in New Issue