hmn/src/hmndata/twitch.go

138 lines
3.2 KiB
Go
Raw Normal View History

2022-03-22 18:07:43 +00:00
package hmndata
import (
"context"
"regexp"
"strings"
"git.handmade.network/hmn/hmn/src/db"
"git.handmade.network/hmn/hmn/src/models"
"git.handmade.network/hmn/hmn/src/oops"
2024-05-22 16:07:41 +00:00
"git.handmade.network/hmn/hmn/src/perf"
2022-03-22 18:07:43 +00:00
)
const InvalidUserTwitchID = "INVALID_USER"
type TwitchStreamer struct {
TwitchID string
TwitchLogin string
UserID *int
ProjectID *int
}
var twitchRegex = regexp.MustCompile(`twitch\.tv/(?P<login>[^/]+)$`)
2024-05-22 16:07:41 +00:00
type TwitchStreamersQuery struct {
UserIDs []int
ProjectIDs []int
}
func FetchTwitchStreamers(ctx context.Context, dbConn db.ConnOrTx, q TwitchStreamersQuery) ([]TwitchStreamer, error) {
perf := perf.ExtractPerf(ctx)
perf.StartBlock("SQL", "Fetch twitch streamers")
defer perf.EndBlock()
var qb db.QueryBuilder
qb.Add(
2022-03-22 18:07:43 +00:00
`
SELECT $columns{link}
2022-03-22 18:07:43 +00:00
FROM
2022-05-07 13:11:05 +00:00
link
LEFT JOIN hmn_user AS link_owner ON link_owner.id = link.user_id
2022-03-22 18:07:43 +00:00
WHERE
2024-05-22 16:07:41 +00:00
TRUE
`,
)
if len(q.UserIDs) > 0 && len(q.ProjectIDs) > 0 {
qb.Add(
`AND (link.user_id = ANY ($?) OR link.project_id = ANY ($?))`,
q.UserIDs,
q.ProjectIDs,
)
} else {
if len(q.UserIDs) > 0 {
qb.Add(`AND link.user_id = ANY ($?)`, q.UserIDs)
}
if len(q.ProjectIDs) > 0 {
qb.Add(`AND link.project_id = ANY ($?)`, q.ProjectIDs)
}
}
qb.Add(
`
AND url ~* 'twitch\.tv/([^/]+)$'
AND ((link.user_id IS NOT NULL AND link_owner.status = $?) OR (link.project_id IS NOT NULL AND
2022-03-27 16:13:47 +00:00
(SELECT COUNT(*)
FROM
2022-05-07 13:11:05 +00:00
user_project AS hup
JOIN hmn_user AS project_owner ON project_owner.id = hup.user_id
2022-03-27 16:13:47 +00:00
WHERE
hup.project_id = link.project_id AND
2024-05-22 16:07:41 +00:00
project_owner.status != $?
2022-03-27 16:13:47 +00:00
) = 0))
2022-03-22 18:07:43 +00:00
`,
2022-03-27 16:13:47 +00:00
models.UserStatusApproved,
2024-05-22 16:07:41 +00:00
models.UserStatusApproved,
2022-03-22 18:07:43 +00:00
)
2024-05-22 16:07:41 +00:00
dbStreamers, err := db.Query[models.Link](ctx, dbConn, qb.String(), qb.Args()...)
2022-03-22 18:07:43 +00:00
if err != nil {
return nil, oops.New(err, "failed to fetch twitch links")
}
result := make([]TwitchStreamer, 0, len(dbStreamers))
for _, dbStreamer := range dbStreamers {
2022-03-22 18:07:43 +00:00
streamer := TwitchStreamer{
UserID: dbStreamer.UserID,
ProjectID: dbStreamer.ProjectID,
}
match := twitchRegex.FindStringSubmatch(dbStreamer.URL)
if match != nil {
login := strings.ToLower(match[twitchRegex.SubexpIndex("login")])
streamer.TwitchLogin = login
}
if len(streamer.TwitchLogin) > 0 {
duplicate := false
for _, r := range result {
if r.TwitchLogin == streamer.TwitchLogin {
duplicate = true
break
}
}
if !duplicate {
result = append(result, streamer)
}
}
}
return result, nil
}
func FetchTwitchLoginsForUserOrProject(ctx context.Context, dbConn db.ConnOrTx, userId *int, projectId *int) ([]string, error) {
links, err := db.Query[models.Link](ctx, dbConn,
2022-03-22 18:07:43 +00:00
`
SELECT $columns
FROM
2022-05-07 13:11:05 +00:00
link
2022-03-22 18:07:43 +00:00
WHERE
url ~* 'twitch\.tv/([^/]+)$'
AND ((user_id = $1 AND project_id IS NULL) OR (user_id IS NULL AND project_id = $2))
ORDER BY url ASC
`,
userId,
projectId,
)
if err != nil {
return nil, oops.New(err, "failed to fetch twitch links")
}
result := make([]string, 0, len(links))
for _, l := range links {
match := twitchRegex.FindStringSubmatch(l.URL)
2022-03-22 18:07:43 +00:00
if match != nil {
login := strings.ToLower(match[twitchRegex.SubexpIndex("login")])
result = append(result, login)
}
}
return result, nil
}