mirror of
https://github.com/aunefyren/wrapperr
synced 2025-01-09 16:28:43 +00:00
80720039e8
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
331 lines
11 KiB
Go
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
|
|
}
|