1
0
mirror of https://github.com/hrfee/jfa-go.git synced 2024-11-09 20:00:12 +00:00
jfa-go/api-jellyseerr.go
Harvey Tindall 54e4a51a7f
users: huge cleanup/dedupe, interface-based third-party services
shared "newUser" method is now "NewUserPostVerification", and is shared
between all routes which create a jellyfin account. The new
"NewUserFromInvite", "NewUserFromAdmin" and "NewUserFromConfirmationKey"
are smaller as a result. Discord, Telegram, and Matrix now implement the
"ContactMethodLinker" and "ContactMethodUser" interfaces, meaning code
is shared a lot between them in the NewUser methods, and the specifics
are now in their own files. Ombi/Jellyseerr similarly implement a
simpler interface "ThirdPartyService", which simply has ImportUser and
AddContactMethod routes. Note these new interface methods are only used
for user creation as of yet, but could likely be used in other places.
2024-08-03 21:27:46 +01:00

166 lines
5.1 KiB
Go

package main
import (
"fmt"
"net/url"
"strconv"
"github.com/gin-gonic/gin"
"github.com/hrfee/jfa-go/jellyseerr"
lm "github.com/hrfee/jfa-go/logmessages"
)
// @Summary Get a list of Jellyseerr users.
// @Produce json
// @Success 200 {object} ombiUsersDTO
// @Failure 500 {object} stringResponse
// @Router /jellyseerr/users [get]
// @Security Bearer
// @tags Jellyseerr
func (app *appContext) JellyseerrUsers(gc *gin.Context) {
users, err := app.js.GetUsers()
if err != nil {
app.err.Printf(lm.FailedGetUsers, lm.Jellyseerr, err)
respond(500, "Couldn't get users", gc)
return
}
userlist := make([]ombiUser, len(users))
i := 0
for _, u := range users {
userlist[i] = ombiUser{
Name: u.Name(),
ID: strconv.FormatInt(u.ID, 10),
}
i++
}
gc.JSON(200, ombiUsersDTO{Users: userlist})
}
// @Summary Store Jellyseerr user template in an existing profile.
// @Produce json
// @Param id path string true "Jellyseerr ID of user to source from"
// @Param profile path string true "Name of profile to store in"
// @Success 200 {object} boolResponse
// @Failure 400 {object} boolResponse
// @Failure 500 {object} stringResponse
// @Router /profiles/jellyseerr/{profile}/{id} [post]
// @Security Bearer
// @tags Jellyseerr
func (app *appContext) SetJellyseerrProfile(gc *gin.Context) {
jellyseerrID, err := strconv.ParseInt(gc.Param("id"), 10, 64)
if err != nil {
respondBool(400, false, gc)
return
}
escapedProfileName := gc.Param("profile")
profileName, _ := url.QueryUnescape(escapedProfileName)
profile, ok := app.storage.GetProfileKey(profileName)
if !ok {
respondBool(400, false, gc)
return
}
u, err := app.js.UserByID(jellyseerrID)
if err != nil {
app.err.Printf(lm.FailedGetUsers, lm.Jellyseerr, err)
respond(500, "Couldn't get user", gc)
return
}
profile.Jellyseerr.User = u.UserTemplate
n, err := app.js.GetNotificationPreferencesByID(jellyseerrID)
if err != nil {
app.err.Printf(lm.FailedGetJellyseerrNotificationPrefs, gc.Param("id"), err)
respond(500, "Couldn't get user notification prefs", gc)
return
}
profile.Jellyseerr.Notifications = n.NotificationsTemplate
profile.Jellyseerr.Enabled = true
app.storage.SetProfileKey(profileName, profile)
respondBool(204, true, gc)
}
// @Summary Remove jellyseerr user template from a profile.
// @Produce json
// @Param profile path string true "Name of profile to store in"
// @Success 200 {object} boolResponse
// @Failure 400 {object} boolResponse
// @Failure 500 {object} stringResponse
// @Router /profiles/jellyseerr/{profile} [delete]
// @Security Bearer
// @tags Jellyseerr
func (app *appContext) DeleteJellyseerrProfile(gc *gin.Context) {
escapedProfileName := gc.Param("profile")
profileName, _ := url.QueryUnescape(escapedProfileName)
profile, ok := app.storage.GetProfileKey(profileName)
if !ok {
respondBool(400, false, gc)
return
}
profile.Jellyseerr.Enabled = false
app.storage.SetProfileKey(profileName, profile)
respondBool(204, true, gc)
}
type JellyseerrWrapper struct {
*jellyseerr.Jellyseerr
}
func (js *JellyseerrWrapper) ImportUser(jellyfinID string, req newUserDTO, profile Profile) (err error, ok bool) {
// Gets existing user (not possible) or imports the given user.
_, err = js.MustGetUser(jellyfinID)
if err != nil {
return
}
ok = true
err = js.ApplyTemplateToUser(jellyfinID, profile.Jellyseerr.User)
if err != nil {
err = fmt.Errorf(lm.FailedApplyTemplate, "user", lm.Jellyseerr, jellyfinID, err)
return
}
err = js.ApplyNotificationsTemplateToUser(jellyfinID, profile.Jellyseerr.Notifications)
if err != nil {
err = fmt.Errorf(lm.FailedApplyTemplate, "notifications", lm.Jellyseerr, jellyfinID, err)
return
}
return
}
func (js *JellyseerrWrapper) AddContactMethods(jellyfinID string, req newUserDTO, discord *DiscordUser, telegram *TelegramUser) (err error) {
_, err = js.MustGetUser(jellyfinID)
if err != nil {
return
}
contactMethods := map[jellyseerr.NotificationsField]any{}
if emailEnabled {
err = js.ModifyMainUserSettings(jellyfinID, jellyseerr.MainUserSettings{Email: req.Email})
if err != nil {
// FIXME: This is a little ugly, considering all other errors are unformatted
err = fmt.Errorf(lm.FailedSetEmailAddress, lm.Jellyseerr, jellyfinID, err)
return
} else {
contactMethods[jellyseerr.FieldEmailEnabled] = req.EmailContact
}
}
if discordEnabled && discord != nil {
contactMethods[jellyseerr.FieldDiscord] = discord.ID
contactMethods[jellyseerr.FieldDiscordEnabled] = req.DiscordContact
}
if telegramEnabled && discord != nil {
contactMethods[jellyseerr.FieldTelegram] = telegram.ChatID
contactMethods[jellyseerr.FieldTelegramEnabled] = req.TelegramContact
}
if len(contactMethods) > 0 {
err = js.ModifyNotifications(jellyfinID, contactMethods)
if err != nil {
// app.err.Printf(lm.FailedSyncContactMethods, lm.Jellyseerr, err)
return
}
}
return
}
func (js *JellyseerrWrapper) Name() string { return lm.Jellyseerr }
func (js *JellyseerrWrapper) Enabled(app *appContext, profile *Profile) bool {
return profile != nil && profile.Jellyseerr.Enabled && app.config.Section("jellyseerr").Key("enabled").MustBool(false)
}