wrapperr/routes/both.go
aunefyren 80720039e8 Users from Tautulli fix
Sync details to user from every Tautulli server during user aggregation
Prioritize active status to true if any Tautulli server says so
Sync users before showing statistics and validating active state
Show Tautulli servers on user page
2023-11-16 19:34:22 +01:00

331 lines
11 KiB
Go

package routes
import (
"aunefyren/wrapperr/files"
"aunefyren/wrapperr/middlewares"
"aunefyren/wrapperr/models"
"aunefyren/wrapperr/modules"
"aunefyren/wrapperr/utilities"
"log"
"net/http"
"strconv"
"strings"
"time"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
)
// Create shareable link using Plex Auth
func ApiCreateShareLink(context *gin.Context) {
configBool, err := files.GetConfigState()
if err != nil {
log.Println("Failed to retrieve configuration state. Error: " + err.Error())
context.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to retrieve configuration state."})
context.Abort()
return
} else if !configBool {
context.JSON(http.StatusBadRequest, gin.H{"error": "Wrapperr is not configured."})
context.Abort()
return
}
config, err := files.GetConfig()
if err != nil {
log.Println("Failed to load Wrapperr configuration. Error: " + err.Error())
context.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to load Wrapperr configuration."})
context.Abort()
return
}
if !config.CreateShareLinks {
log.Panicln("Shareable links are not enabled in the Wrapperr configuration.")
context.JSON(http.StatusBadRequest, gin.H{"error": "Shareable links are not enabled in the Wrapperr configuration."})
context.Abort()
return
}
adminConfig, err := files.GetAdminConfig()
if err != nil {
log.Println("Failed to load Wrapperr admin configuration. Error: " + err.Error())
context.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to load Wrapperr admin configuration."})
context.Abort()
return
}
var user_name string
var user_id int
// Try to authorize bearer token from header
if config.PlexAuth {
authorizationHeader := context.GetHeader("Authorization")
payload, httpStatus, err := middlewares.AuthGetPayloadFromAuthorization(authorizationHeader, config, adminConfig)
if err != nil {
log.Println("Failed to get payload from Authorization token. Error: " + err.Error())
context.JSON(httpStatus, gin.H{"error": err.Error()})
context.Abort()
return
}
if err != nil || payload.Admin {
log.Println("Either error or admin sessions.")
context.JSON(http.StatusUnauthorized, gin.H{"error": "Failed to authorize request."})
context.Abort()
return
} else {
plex_object, err := modules.PlexAuthValidateToken(payload.AuthToken, config.ClientKey, config.WrapperrVersion)
if err != nil {
log.Println("Could not validate Plex Auth login. Error: " + err.Error())
context.JSON(http.StatusUnauthorized, gin.H{"error": "Could not validate Plex Auth login."})
context.Abort()
return
}
user_name = plex_object.Username
user_id = plex_object.ID
}
}
// Read payload from Post input
var link_payload models.WrapperrShareLinkCreateRequest
if err := context.ShouldBindJSON(&link_payload); err != nil {
log.Println("Failed to parse request. Error: " + err.Error())
context.JSON(http.StatusBadRequest, gin.H{"error": "Failed to parse request."})
context.Abort()
return
}
currentTime := time.Now()
hash_value := uuid.New().String()
if !config.PlexAuth {
user_name = link_payload.Data.User.Name
user_id = 0
}
link_object := models.WrapperrShareLink{
Content: link_payload,
UserID: user_id,
Hash: hash_value,
Date: currentTime.Format("2006-01-02"),
WrapperrVersion: config.WrapperrVersion,
Expired: false,
}
err = files.SaveLink(&link_object, config.PlexAuth)
if err != nil {
log.Println("Failed to save new link. Error: " + err.Error())
context.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save new link."})
context.Abort()
return
}
ipString := utilities.GetOriginIPString(context)
log.Println("Saved new Wrapperr share link for " + user_name + " (" + strconv.Itoa(user_id) + ")." + ipString)
context.JSON(http.StatusCreated, gin.H{"message": "Saved Wrapperr link.", "error": false, "data": strconv.Itoa(user_id) + "-" + hash_value})
return
}
func ApiWrapperGetStatistics(context *gin.Context) {
log.Println("New wrap request.")
configBool, err := files.GetConfigState()
if err != nil {
log.Println("Failed to retrieve configuration state. Error: " + err.Error())
context.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to retrieve configuration state."})
context.Abort()
return
} else if !configBool {
context.JSON(http.StatusBadRequest, gin.H{"error": "Wrapperr is not configured."})
context.Abort()
return
}
config, err := files.GetConfig()
if err != nil {
log.Println("Failed to load Wrapperr configuration. Error: " + err.Error())
context.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to load Wrapperr configuration."})
context.Abort()
return
}
adminConfig, err := files.GetAdminConfig()
if err != nil {
log.Println("Failed to load Wrapperr admin configuration. Error: " + err.Error())
context.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to load Wrapperr admin configuration."})
context.Abort()
return
}
// Check connection to every Tautulli server
err = modules.TautulliTestEveryServer()
if err != nil {
log.Println("Failed to test Tautulli server. Error: " + err.Error())
context.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to test Tautulli server."})
context.Abort()
return
}
// Sync users from Tautulli to Wrapperr
err = modules.TautulliSyncUsersToWrapperr()
if err != nil {
log.Println("Failed to sync users from Tautulli. Error: " + err.Error())
context.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to sync users from Tautulli."})
context.Abort()
return
}
var userName string = ""
var userId int = 0
var userEmail string = ""
var userFriendlyName = ""
var userActive = false
// Try to authorize bearer token from header
authorizationHeader := context.GetHeader("Authorization")
payload, _, err := middlewares.AuthGetPayloadFromAuthorization(authorizationHeader, config, adminConfig)
// If it failed and PlexAuth is enabled, respond with and error
// If it didn't fail, and PlexAuth is enabled, declare auth as passed
if err != nil && config.PlexAuth {
log.Println("Failed to authorize authorization header. Error: " + err.Error())
context.JSON(http.StatusUnauthorized, gin.H{"error": "Failed to authorize request."})
context.Abort()
return
} else if payload.Admin && config.PlexAuth {
context.JSON(http.StatusBadRequest, gin.H{"error": "Admin login cannot retrieve statistics."})
context.Abort()
return
}
// If the user is not an admin, and PlexAuth is enabled, validate and retrieve details from Plex Token in payload
if config.PlexAuth {
plex_object, err := modules.PlexAuthValidateToken(payload.AuthToken, config.ClientKey, config.WrapperrVersion)
if err != nil {
log.Println("Could not validate Plex Auth login. Error: " + err.Error())
context.JSON(http.StatusUnauthorized, gin.H{"error": "Could not validate Plex Auth login."})
context.Abort()
return
}
// Set user details from Plex login
userName = plex_object.Username
userId = plex_object.ID
userEmail = plex_object.Email
// Check for friendly name using Tautulli
wrapperrUser, err := modules.UsersGetUser(userId)
if err != nil {
log.Println("Failed to find Wrapperr user. Error: " + err.Error())
context.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to find Wrapperr user."})
context.Abort()
return
}
userName = wrapperrUser.User
userFriendlyName = wrapperrUser.FriendlyName
userActive = wrapperrUser.Active
}
// Read payload from Post input
var wrapperr_request models.SearchWrapperrRequest
if err := context.ShouldBindJSON(&wrapperr_request); err != nil {
log.Println("Failed to parse request. Error: " + err.Error())
context.JSON(http.StatusBadRequest, gin.H{"error": "Failed to parse request."})
context.Abort()
return
}
// If auth is not passed, caching mode is false, and no PlexIdentity was received, mark it as a bad request
if wrapperr_request.PlexIdentity == "" && !config.PlexAuth {
log.Println("Cannot retrieve statistics because search parameter is invalid.")
context.JSON(http.StatusBadRequest, gin.H{"error": "Invalid search parameter."})
context.Abort()
return
}
// If no auth has been passed, caching mode is false, and user is not admin, search for the Plex details using Tautulli and PlexIdentity
if !config.PlexAuth {
UserNameFound := false
for i := 0; i < len(config.TautulliConfig); i++ {
new_id, _, _, _, _, err := modules.TautulliGetUserId(config.TautulliConfig[i].TautulliPort, config.TautulliConfig[i].TautulliIP, config.TautulliConfig[i].TautulliHttps, config.TautulliConfig[i].TautulliRoot, config.TautulliConfig[i].TautulliApiKey, strings.TrimSpace(wrapperr_request.PlexIdentity))
if err == nil {
UserNameFound = true
userId = new_id
break
}
}
if !UserNameFound {
log.Println("Failed to find user in Tautulli.")
context.JSON(http.StatusInternalServerError, gin.H{"error": "Could not find a matching user."})
context.Abort()
return
}
// Check for friendly name using Tautulli
wrapperrUser, err := modules.UsersGetUser(userId)
if err != nil {
log.Println("Failed to find Wrapperr user. Error: " + err.Error())
context.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to find Wrapperr user."})
context.Abort()
return
}
userName = wrapperrUser.User
userEmail = wrapperrUser.Email
userFriendlyName = wrapperrUser.FriendlyName
userActive = wrapperrUser.Active
}
// If no username and no user_id has been declared at this point, something is wrong. Return error.
if userName == "" || userEmail == "" || userId == 0 {
log.Println("At this point the user should have been verified, but username, email or ID is empty.")
context.JSON(http.StatusInternalServerError, gin.H{"error": "User validation error."})
context.Abort()
return
}
if !userActive {
context.JSON(http.StatusUnauthorized, gin.H{"error": "User is not active."})
context.Abort()
return
}
wrapperrReply, _, err := modules.GetWrapperStatistics(userName, userFriendlyName, userId, userEmail, config, adminConfig, false, 0)
if err != nil {
log.Println("Failed to get statistics. Error: " + err.Error())
context.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get statistics."})
context.Abort()
return
}
userhistoryEntry := models.WrapperrHistoryEntry{
Date: time.Now(),
IP: context.ClientIP(),
}
historyEntries := []models.WrapperrHistoryEntry{}
historyEntries = append(historyEntries, userhistoryEntry)
userEntry := models.WrapperrUser{
User: userName,
UserID: userId,
FriendlyName: userFriendlyName,
Email: userEmail,
Wrappings: historyEntries,
}
err = modules.UsersSaveUserEntry(userEntry)
if err != nil {
log.Println("Failed to save user history entry. Error: " + err.Error())
context.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to save user history entry."})
context.Abort()
return
}
context.JSON(http.StatusOK, wrapperrReply)
return
}