[add] admin panel, [add] better logging
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
2024-01-09 21:08:40 -05:00
parent d3d89b36f6
commit c5b181dda4
14 changed files with 588 additions and 99 deletions

View File

@@ -9,6 +9,7 @@ import (
"net/http"
"path/filepath"
"strings"
"time"
"github.com/gin-contrib/multitemplate"
"github.com/gin-contrib/sessions"
@@ -32,12 +33,15 @@ type API struct {
func NewApi(db *database.DBManager, c *config.Config, assets *embed.FS) *API {
api := &API{
HTMLPolicy: bluemonday.StrictPolicy(),
Router: gin.Default(),
Router: gin.New(),
Config: c,
DB: db,
Assets: assets,
}
// Add Logger
api.Router.Use(apiLogger())
// Assets & Web App Templates
assetsDir, _ := fs.Sub(assets, "assets")
api.Router.StaticFS("/assets", http.FS(assetsDir))
@@ -107,6 +111,9 @@ func (api *API) registerWebAppRoutes() {
api.Router.GET("/logout", api.authWebAppMiddleware, api.appAuthLogout)
api.Router.GET("/register", api.appGetRegister)
api.Router.GET("/settings", api.authWebAppMiddleware, api.appGetSettings)
api.Router.GET("/admin/logs", api.authWebAppMiddleware, api.authAdminWebAppMiddleware, api.appGetAdminLogs)
api.Router.GET("/admin", api.authWebAppMiddleware, api.authAdminWebAppMiddleware, api.appGetAdmin)
api.Router.POST("/admin", api.authWebAppMiddleware, api.authAdminWebAppMiddleware, api.appPerformAdminAction)
api.Router.POST("/login", api.appAuthFormLogin)
api.Router.POST("/register", api.appAuthFormRegister)
@@ -228,6 +235,23 @@ func (api *API) generateTemplates() *multitemplate.Renderer {
return &render
}
func apiLogger() gin.HandlerFunc {
return func(c *gin.Context) {
// Start Timer
startTime := time.Now()
// Process Request
c.Next()
// End Timer
endTime := time.Now()
latency := endTime.Sub(startTime).Round(time.Microsecond)
// Log Result
log.Infof("[HTTPRouter] %-15s (%10s) %d %7s %s", c.ClientIP(), latency, c.Writer.Status(), c.Request.Method, c.Request.URL.Path)
}
}
func generateToken(n int) ([]byte, error) {
b := make([]byte, n)
_, err := rand.Read(b)

View File

@@ -1,14 +1,17 @@
package api
import (
"archive/zip"
"crypto/md5"
"database/sql"
"fmt"
"io"
"io/fs"
"math"
"mime/multipart"
"net/http"
"os"
"path"
"path/filepath"
"strings"
"time"
@@ -24,6 +27,29 @@ import (
"reichard.io/bbank/utils"
)
type AdminAction string
const (
AA_IMPORT AdminAction = "IMPORT"
AA_BACKUP AdminAction = "BACKUP"
AA_RESTORE AdminAction = "RESTORE"
AA_METADATA_MATCH AdminAction = "METADATA_MATCH"
)
type ImportType string
const (
IMPORT_TYPE_DIRECT ImportType = "DIRECT"
IMPORT_TYPE_COPY ImportType = "COPY"
)
type BackupType string
const (
BACKUP_TYPE_COVERS BackupType = "COVERS"
BACKUP_TYPE_DOCUMENTS BackupType = "DOCUMENTS"
)
type queryParams struct {
Page *int64 `form:"page"`
Limit *int64 `form:"limit"`
@@ -51,6 +77,20 @@ type requestDocumentEdit struct {
CoverFile *multipart.FileHeader `form:"cover_file"`
}
type requestAdminAction struct {
Action AdminAction `form:"action"`
// Import Action
ImportDirectory *string `form:"import_directory"`
ImportType *ImportType `form:"import_type"`
// Backup Action
BackupTypes []BackupType `form:"backup_types"`
// Restore Action
RestoreFile *multipart.FileHeader `form:"restore_file"`
}
type requestDocumentIdentify struct {
Title *string `form:"title"`
Author *string `form:"author"`
@@ -93,7 +133,7 @@ func (api *API) appDocumentReader(c *gin.Context) {
func (api *API) appGetDocuments(c *gin.Context) {
templateVars := api.getBaseTemplateVars("documents", c)
userID := templateVars["User"].(string)
auth := templateVars["Authorization"].(authData)
qParams := bindQueryParams(c, 9)
var query *string
@@ -103,7 +143,7 @@ func (api *API) appGetDocuments(c *gin.Context) {
}
documents, err := api.DB.Queries.GetDocumentsWithStats(api.DB.Ctx, database.GetDocumentsWithStatsParams{
UserID: userID,
UserID: auth.UserName,
Query: query,
Offset: (*qParams.Page - 1) * *qParams.Limit,
Limit: *qParams.Limit,
@@ -145,7 +185,7 @@ func (api *API) appGetDocuments(c *gin.Context) {
func (api *API) appGetDocument(c *gin.Context) {
templateVars := api.getBaseTemplateVars("document", c)
userID := templateVars["User"].(string)
auth := templateVars["Authorization"].(authData)
var rDocID requestDocumentID
if err := c.ShouldBindUri(&rDocID); err != nil {
@@ -155,7 +195,7 @@ func (api *API) appGetDocument(c *gin.Context) {
}
document, err := api.DB.Queries.GetDocumentWithStats(api.DB.Ctx, database.GetDocumentWithStatsParams{
UserID: userID,
UserID: auth.UserName,
DocumentID: rDocID.DocumentID,
})
if err != nil {
@@ -172,11 +212,12 @@ func (api *API) appGetDocument(c *gin.Context) {
func (api *API) appGetProgress(c *gin.Context) {
templateVars := api.getBaseTemplateVars("progress", c)
userID := templateVars["User"].(string)
auth := templateVars["Authorization"].(authData)
qParams := bindQueryParams(c, 15)
progressFilter := database.GetProgressParams{
UserID: userID,
UserID: auth.UserName,
Offset: (*qParams.Page - 1) * *qParams.Limit,
Limit: *qParams.Limit,
}
@@ -200,11 +241,11 @@ func (api *API) appGetProgress(c *gin.Context) {
func (api *API) appGetActivity(c *gin.Context) {
templateVars := api.getBaseTemplateVars("activity", c)
userID := templateVars["User"].(string)
auth := templateVars["Authorization"].(authData)
qParams := bindQueryParams(c, 15)
activityFilter := database.GetActivityParams{
UserID: userID,
UserID: auth.UserName,
Offset: (*qParams.Page - 1) * *qParams.Limit,
Limit: *qParams.Limit,
}
@@ -228,17 +269,17 @@ func (api *API) appGetActivity(c *gin.Context) {
func (api *API) appGetHome(c *gin.Context) {
templateVars := api.getBaseTemplateVars("home", c)
userID := templateVars["User"].(string)
auth := templateVars["Authorization"].(authData)
start := time.Now()
graphData, _ := api.DB.Queries.GetDailyReadStats(api.DB.Ctx, userID)
log.Info("GetDailyReadStats Performance: ", time.Since(start))
graphData, _ := api.DB.Queries.GetDailyReadStats(api.DB.Ctx, auth.UserName)
log.Debug("[appGetHome] GetDailyReadStats Performance: ", time.Since(start))
start = time.Now()
databaseInfo, _ := api.DB.Queries.GetDatabaseInfo(api.DB.Ctx, userID)
log.Info("GetDatabaseInfo Performance: ", time.Since(start))
databaseInfo, _ := api.DB.Queries.GetDatabaseInfo(api.DB.Ctx, auth.UserName)
log.Debug("[appGetHome] GetDatabaseInfo Performance: ", time.Since(start))
streaks, _ := api.DB.Queries.GetUserStreaks(api.DB.Ctx, userID)
streaks, _ := api.DB.Queries.GetUserStreaks(api.DB.Ctx, auth.UserName)
WPMLeaderboard, _ := api.DB.Queries.GetWPMLeaderboard(api.DB.Ctx)
templateVars["Data"] = gin.H{
@@ -253,16 +294,16 @@ func (api *API) appGetHome(c *gin.Context) {
func (api *API) appGetSettings(c *gin.Context) {
templateVars := api.getBaseTemplateVars("settings", c)
userID := templateVars["User"].(string)
auth := templateVars["Authorization"].(authData)
user, err := api.DB.Queries.GetUser(api.DB.Ctx, userID)
user, err := api.DB.Queries.GetUser(api.DB.Ctx, auth.UserName)
if err != nil {
log.Error("[appGetSettings] GetUser DB Error:", err)
errorPage(c, http.StatusInternalServerError, fmt.Sprintf("GetUser DB Error: %v", err))
return
}
devices, err := api.DB.Queries.GetDevices(api.DB.Ctx, userID)
devices, err := api.DB.Queries.GetDevices(api.DB.Ctx, auth.UserName)
if err != nil {
log.Error("[appGetSettings] GetDevices DB Error:", err)
errorPage(c, http.StatusInternalServerError, fmt.Sprintf("GetDevices DB Error: %v", err))
@@ -277,6 +318,126 @@ func (api *API) appGetSettings(c *gin.Context) {
c.HTML(http.StatusOK, "page/settings", templateVars)
}
func (api *API) appGetAdmin(c *gin.Context) {
templateVars := api.getBaseTemplateVars("admin", c)
c.HTML(http.StatusOK, "page/admin", templateVars)
}
func (api *API) appGetAdminLogs(c *gin.Context) {
// Open Log File
logPath := path.Join(api.Config.ConfigPath, "logs/antholume.log")
logFile, err := os.Open(logPath)
if err != nil {
errorPage(c, http.StatusBadRequest, "Missing AnthoLume log file.")
return
}
defer logFile.Close()
// Write Log File
c.Stream(func(w io.Writer) bool {
_, err = io.Copy(w, logFile)
if err != nil {
return true
}
return false
})
}
func (api *API) appPerformAdminAction(c *gin.Context) {
templateVars := api.getBaseTemplateVars("admin", c)
var rAdminAction requestAdminAction
if err := c.ShouldBind(&rAdminAction); err != nil {
log.Error("[appPerformAdminAction] Invalid Form Bind")
errorPage(c, http.StatusBadRequest, "Invalid or missing form values.")
return
}
switch rAdminAction.Action {
case AA_IMPORT:
// TODO
case AA_METADATA_MATCH:
// TODO
// 1. Documents xref most recent metadata table?
// 2. Select all / deselect?
case AA_RESTORE:
// TODO
// 1. Consume backup ZIP
// 2. Move existing to "backup" folder (db, wal, shm, covers, documents)
// 3. Extract backup zip
// 4. Restart server?
case AA_BACKUP:
// Get File Paths
fileName := fmt.Sprintf("%s.db", api.Config.DBName)
dbLocation := path.Join(api.Config.ConfigPath, fileName)
c.Header("Content-type", "application/octet-stream")
c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=\"AnthoLumeExport_%s.zip\"", time.Now().Format("20060102")))
// Stream Backup ZIP Archive
c.Stream(func(w io.Writer) bool {
ar := zip.NewWriter(w)
exportWalker := func(currentPath string, f fs.DirEntry, err error) error {
if err != nil {
return err
}
if f.IsDir() {
return nil
}
// Open File on Disk
file, err := os.Open(currentPath)
if err != nil {
return err
}
defer file.Close()
// Derive Export Structure
fileName := filepath.Base(currentPath)
folderName := filepath.Base(filepath.Dir(currentPath))
// Create File in Export
newF, err := ar.Create(path.Join(folderName, fileName))
if err != nil {
return err
}
// Copy File in Export
_, err = io.Copy(newF, file)
if err != nil {
return err
}
return nil
}
// Copy Database File
dbFile, _ := os.Open(dbLocation)
newDbFile, _ := ar.Create(fileName)
io.Copy(newDbFile, dbFile)
// Backup Covers & Documents
for _, item := range rAdminAction.BackupTypes {
if item == BACKUP_TYPE_COVERS {
filepath.WalkDir(path.Join(api.Config.ConfigPath, "covers"), exportWalker)
} else if item == BACKUP_TYPE_DOCUMENTS {
filepath.WalkDir(path.Join(api.Config.ConfigPath, "documents"), exportWalker)
}
}
ar.Close()
return false
})
return
}
c.HTML(http.StatusOK, "page/admin", templateVars)
}
func (api *API) appGetSearch(c *gin.Context) {
templateVars := api.getBaseTemplateVars("search", c)
@@ -320,7 +481,10 @@ func (api *API) appGetRegister(c *gin.Context) {
}
func (api *API) appGetDocumentProgress(c *gin.Context) {
rUser, _ := c.Get("AuthorizedUser")
var auth authData
if data, _ := c.Get("Authorization"); data != nil {
auth = data.(authData)
}
var rDoc requestDocumentID
if err := c.ShouldBindUri(&rDoc); err != nil {
@@ -331,7 +495,7 @@ func (api *API) appGetDocumentProgress(c *gin.Context) {
progress, err := api.DB.Queries.GetDocumentProgress(api.DB.Ctx, database.GetDocumentProgressParams{
DocumentID: rDoc.DocumentID,
UserID: rUser.(string),
UserID: auth.UserName,
})
if err != nil && err != sql.ErrNoRows {
@@ -341,7 +505,7 @@ func (api *API) appGetDocumentProgress(c *gin.Context) {
}
document, err := api.DB.Queries.GetDocumentWithStats(api.DB.Ctx, database.GetDocumentWithStatsParams{
UserID: rUser.(string),
UserID: auth.UserName,
DocumentID: rDoc.DocumentID,
})
if err != nil {
@@ -361,9 +525,12 @@ func (api *API) appGetDocumentProgress(c *gin.Context) {
}
func (api *API) appGetDevices(c *gin.Context) {
rUser, _ := c.Get("AuthorizedUser")
var auth authData
if data, _ := c.Get("Authorization"); data != nil {
auth = data.(authData)
}
devices, err := api.DB.Queries.GetDevices(api.DB.Ctx, rUser.(string))
devices, err := api.DB.Queries.GetDevices(api.DB.Ctx, auth.UserName)
if err != nil && err != sql.ErrNoRows {
log.Error("[appGetDevices] GetDevices DB Error:", err)
@@ -677,7 +844,7 @@ func (api *API) appIdentifyDocument(c *gin.Context) {
// Get Template Variables
templateVars := api.getBaseTemplateVars("document", c)
userID := templateVars["User"].(string)
auth := templateVars["Authorization"].(authData)
// Get Metadata
metadataResults, err := metadata.SearchMetadata(metadata.GBOOK, metadata.MetadataInfo{
@@ -710,7 +877,7 @@ func (api *API) appIdentifyDocument(c *gin.Context) {
}
document, err := api.DB.Queries.GetDocumentWithStats(api.DB.Ctx, database.GetDocumentWithStatsParams{
UserID: userID,
UserID: auth.UserName,
DocumentID: rDocID.DocumentID,
})
if err != nil {
@@ -896,17 +1063,19 @@ func (api *API) appEditSettings(c *gin.Context) {
}
templateVars := api.getBaseTemplateVars("settings", c)
userID := templateVars["User"].(string)
auth := templateVars["Authorization"].(authData)
newUserSettings := database.UpdateUserParams{
UserID: userID,
UserID: auth.UserName,
}
// Set New Password
if rUserSettings.Password != nil && rUserSettings.NewPassword != nil {
password := fmt.Sprintf("%x", md5.Sum([]byte(*rUserSettings.Password)))
authorized := api.authorizeCredentials(userID, password)
if authorized == true {
data := api.authorizeCredentials(auth.UserName, password)
if data == nil {
templateVars["PasswordErrorMessage"] = "Invalid Password"
} else {
password := fmt.Sprintf("%x", md5.Sum([]byte(*rUserSettings.NewPassword)))
hashedPassword, err := argon2.CreateHash(password, argon2.DefaultParams)
if err != nil {
@@ -915,8 +1084,6 @@ func (api *API) appEditSettings(c *gin.Context) {
templateVars["PasswordMessage"] = "Password Updated"
newUserSettings.Password = &hashedPassword
}
} else {
templateVars["PasswordErrorMessage"] = "Invalid Password"
}
}
@@ -935,7 +1102,7 @@ func (api *API) appEditSettings(c *gin.Context) {
}
// Get User
user, err := api.DB.Queries.GetUser(api.DB.Ctx, userID)
user, err := api.DB.Queries.GetUser(api.DB.Ctx, auth.UserName)
if err != nil {
log.Error("[appEditSettings] GetUser DB Error:", err)
errorPage(c, http.StatusInternalServerError, fmt.Sprintf("GetUser DB Error: %v", err))
@@ -943,7 +1110,7 @@ func (api *API) appEditSettings(c *gin.Context) {
}
// Get Devices
devices, err := api.DB.Queries.GetDevices(api.DB.Ctx, userID)
devices, err := api.DB.Queries.GetDevices(api.DB.Ctx, auth.UserName)
if err != nil {
log.Error("[appEditSettings] GetDevices DB Error:", err)
errorPage(c, http.StatusInternalServerError, fmt.Sprintf("GetDevices DB Error: %v", err))
@@ -1002,14 +1169,14 @@ func (api *API) getDocumentsWordCount(documents []database.GetDocumentsWithStats
}
func (api *API) getBaseTemplateVars(routeName string, c *gin.Context) gin.H {
var userID string
if rUser, _ := c.Get("AuthorizedUser"); rUser != nil {
userID = rUser.(string)
var auth authData
if data, _ := c.Get("Authorization"); data != nil {
auth = data.(authData)
}
return gin.H{
"User": userID,
"RouteName": routeName,
"Authorization": auth,
"RouteName": routeName,
"Config": gin.H{
"Version": api.Config.Version,
"SearchEnabled": api.Config.SearchEnabled,

View File

@@ -14,6 +14,12 @@ import (
"reichard.io/bbank/database"
)
// Authorization Data
type authData struct {
UserName string
IsAdmin bool
}
// KOSync API Auth Headers
type authKOHeader struct {
AuthUser string `header:"x-auth-user"`
@@ -25,25 +31,28 @@ type authOPDSHeader struct {
Authorization string `header:"authorization"`
}
func (api *API) authorizeCredentials(username string, password string) (authorized bool) {
func (api *API) authorizeCredentials(username string, password string) (auth *authData) {
user, err := api.DB.Queries.GetUser(api.DB.Ctx, username)
if err != nil {
return false
return
}
if match, err := argon2.ComparePasswordAndHash(password, *user.Pass); err != nil || match != true {
return false
return
}
return true
return &authData{
UserName: user.ID,
IsAdmin: user.Admin,
}
}
func (api *API) authKOMiddleware(c *gin.Context) {
session := sessions.Default(c)
// Check Session First
if user, ok := getSession(session); ok == true {
c.Set("AuthorizedUser", user)
if auth, ok := getSession(session); ok == true {
c.Set("Authorization", auth)
c.Header("Cache-Control", "private")
c.Next()
return
@@ -61,17 +70,18 @@ func (api *API) authKOMiddleware(c *gin.Context) {
return
}
if authorized := api.authorizeCredentials(rHeader.AuthUser, rHeader.AuthKey); authorized != true {
authData := api.authorizeCredentials(rHeader.AuthUser, rHeader.AuthKey)
if authData == nil {
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
return
}
if err := setSession(session, rHeader.AuthUser); err != nil {
if err := setSession(session, *authData); err != nil {
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
return
}
c.Set("AuthorizedUser", rHeader.AuthUser)
c.Set("Authorization", *authData)
c.Header("Cache-Control", "private")
c.Next()
}
@@ -89,12 +99,13 @@ func (api *API) authOPDSMiddleware(c *gin.Context) {
// Validate Auth
password := fmt.Sprintf("%x", md5.Sum([]byte(rawPassword)))
if authorized := api.authorizeCredentials(user, password); authorized != true {
authData := api.authorizeCredentials(user, password)
if authData == nil {
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
return
}
c.Set("AuthorizedUser", user)
c.Set("Authorization", *authData)
c.Header("Cache-Control", "private")
c.Next()
}
@@ -103,8 +114,8 @@ func (api *API) authWebAppMiddleware(c *gin.Context) {
session := sessions.Default(c)
// Check Session
if user, ok := getSession(session); ok == true {
c.Set("AuthorizedUser", user)
if auth, ok := getSession(session); ok == true {
c.Set("Authorization", auth)
c.Header("Cache-Control", "private")
c.Next()
return
@@ -115,6 +126,20 @@ func (api *API) authWebAppMiddleware(c *gin.Context) {
return
}
func (api *API) authAdminWebAppMiddleware(c *gin.Context) {
if data, _ := c.Get("Authorization"); data != nil {
auth := data.(authData)
if auth.IsAdmin == true {
c.Next()
return
}
}
errorPage(c, http.StatusUnauthorized, "Admin Permissions Required")
c.Abort()
return
}
func (api *API) appAuthFormLogin(c *gin.Context) {
templateVars := api.getBaseTemplateVars("login", c)
@@ -129,7 +154,8 @@ func (api *API) appAuthFormLogin(c *gin.Context) {
// MD5 - KOSync Compatiblity
password := fmt.Sprintf("%x", md5.Sum([]byte(rawPassword)))
if authorized := api.authorizeCredentials(username, password); authorized != true {
authData := api.authorizeCredentials(username, password)
if authData == nil {
templateVars["Error"] = "Invalid Credentials"
c.HTML(http.StatusUnauthorized, "page/login", templateVars)
return
@@ -137,7 +163,7 @@ func (api *API) appAuthFormLogin(c *gin.Context) {
// Set Session
session := sessions.Default(c)
if err := setSession(session, username); err != nil {
if err := setSession(session, *authData); err != nil {
templateVars["Error"] = "Invalid Credentials"
c.HTML(http.StatusUnauthorized, "page/login", templateVars)
return
@@ -194,9 +220,22 @@ func (api *API) appAuthFormRegister(c *gin.Context) {
return
}
// Get User
user, err := api.DB.Queries.GetUser(api.DB.Ctx, username)
if err != nil {
log.Error("[appAuthFormRegister] GetUser DB Error:", err)
templateVars["Error"] = "Registration Disabled or User Already Exists"
c.HTML(http.StatusBadRequest, "page/login", templateVars)
return
}
// Set Session
auth := authData{
UserName: user.ID,
IsAdmin: user.Admin,
}
session := sessions.Default(c)
if err := setSession(session, username); err != nil {
if err := setSession(session, auth); err != nil {
errorPage(c, http.StatusUnauthorized, "Unauthorized.")
return
}
@@ -212,26 +251,35 @@ func (api *API) appAuthLogout(c *gin.Context) {
c.Redirect(http.StatusFound, "/login")
}
func getSession(session sessions.Session) (user string, ok bool) {
func getSession(session sessions.Session) (auth authData, ok bool) {
// Check Session
authorizedUser := session.Get("authorizedUser")
if authorizedUser == nil {
return "", false
isAdmin := session.Get("isAdmin")
expiresAt := session.Get("expiresAt")
if authorizedUser == nil || isAdmin == nil || expiresAt == nil {
return
}
// Create Auth Object
auth = authData{
UserName: authorizedUser.(string),
IsAdmin: isAdmin.(bool),
}
// Refresh
expiresAt := session.Get("expiresAt")
if expiresAt != nil && expiresAt.(int64)-time.Now().Unix() < 60*60*24 {
if expiresAt.(int64)-time.Now().Unix() < 60*60*24 {
log.Info("[getSession] Refreshing Session")
setSession(session, authorizedUser.(string))
setSession(session, auth)
}
return authorizedUser.(string), true
// Authorized
return auth, true
}
func setSession(session sessions.Session, user string) error {
func setSession(session sessions.Session, auth authData) error {
// Set Session Cookie
session.Set("authorizedUser", user)
session.Set("authorizedUser", auth.UserName)
session.Set("isAdmin", auth.IsAdmin)
session.Set("expiresAt", time.Now().Unix()+(60*60*24*7))
return session.Save()
}

View File

@@ -129,7 +129,10 @@ func (api *API) koCreateUser(c *gin.Context) {
}
func (api *API) koSetProgress(c *gin.Context) {
rUser, _ := c.Get("AuthorizedUser")
var auth authData
if data, _ := c.Get("Authorization"); data != nil {
auth = data.(authData)
}
var rPosition requestPosition
if err := c.ShouldBindJSON(&rPosition); err != nil {
@@ -141,7 +144,7 @@ func (api *API) koSetProgress(c *gin.Context) {
// Upsert Device
if _, err := api.DB.Queries.UpsertDevice(api.DB.Ctx, database.UpsertDeviceParams{
ID: rPosition.DeviceID,
UserID: rUser.(string),
UserID: auth.UserName,
DeviceName: rPosition.Device,
LastSynced: time.Now().UTC().Format(time.RFC3339),
}); err != nil {
@@ -160,7 +163,7 @@ func (api *API) koSetProgress(c *gin.Context) {
Percentage: rPosition.Percentage,
DocumentID: rPosition.DocumentID,
DeviceID: rPosition.DeviceID,
UserID: rUser.(string),
UserID: auth.UserName,
Progress: rPosition.Progress,
})
if err != nil {
@@ -171,7 +174,7 @@ func (api *API) koSetProgress(c *gin.Context) {
// Update Statistic
log.Info("[koSetProgress] UpdateDocumentUserStatistic Running...")
if err := api.DB.UpdateDocumentUserStatistic(rPosition.DocumentID, rUser.(string)); err != nil {
if err := api.DB.UpdateDocumentUserStatistic(rPosition.DocumentID, auth.UserName); err != nil {
log.Error("[koSetProgress] UpdateDocumentUserStatistic Error:", err)
}
log.Info("[koSetProgress] UpdateDocumentUserStatistic Complete")
@@ -183,7 +186,10 @@ func (api *API) koSetProgress(c *gin.Context) {
}
func (api *API) koGetProgress(c *gin.Context) {
rUser, _ := c.Get("AuthorizedUser")
var auth authData
if data, _ := c.Get("Authorization"); data != nil {
auth = data.(authData)
}
var rDocID requestDocumentID
if err := c.ShouldBindUri(&rDocID); err != nil {
@@ -194,7 +200,7 @@ func (api *API) koGetProgress(c *gin.Context) {
progress, err := api.DB.Queries.GetDocumentProgress(api.DB.Ctx, database.GetDocumentProgressParams{
DocumentID: rDocID.DocumentID,
UserID: rUser.(string),
UserID: auth.UserName,
})
if err == sql.ErrNoRows {
@@ -217,7 +223,10 @@ func (api *API) koGetProgress(c *gin.Context) {
}
func (api *API) koAddActivities(c *gin.Context) {
rUser, _ := c.Get("AuthorizedUser")
var auth authData
if data, _ := c.Get("Authorization"); data != nil {
auth = data.(authData)
}
var rActivity requestActivity
if err := c.ShouldBindJSON(&rActivity); err != nil {
@@ -259,7 +268,7 @@ func (api *API) koAddActivities(c *gin.Context) {
// Upsert Device
if _, err = qtx.UpsertDevice(api.DB.Ctx, database.UpsertDeviceParams{
ID: rActivity.DeviceID,
UserID: rUser.(string),
UserID: auth.UserName,
DeviceName: rActivity.Device,
LastSynced: time.Now().UTC().Format(time.RFC3339),
}); err != nil {
@@ -271,7 +280,7 @@ func (api *API) koAddActivities(c *gin.Context) {
// Add All Activity
for _, item := range rActivity.Activity {
if _, err := qtx.AddActivity(api.DB.Ctx, database.AddActivityParams{
UserID: rUser.(string),
UserID: auth.UserName,
DocumentID: item.DocumentID,
DeviceID: rActivity.DeviceID,
StartTime: time.Unix(int64(item.StartTime), 0).UTC().Format(time.RFC3339),
@@ -295,7 +304,7 @@ func (api *API) koAddActivities(c *gin.Context) {
// Update Statistic
for _, doc := range allDocuments {
log.Info("[koAddActivities] UpdateDocumentUserStatistic Running...")
if err := api.DB.UpdateDocumentUserStatistic(doc, rUser.(string)); err != nil {
if err := api.DB.UpdateDocumentUserStatistic(doc, auth.UserName); err != nil {
log.Error("[koAddActivities] UpdateDocumentUserStatistic Error:", err)
}
log.Info("[koAddActivities] UpdateDocumentUserStatistic Complete")
@@ -307,7 +316,10 @@ func (api *API) koAddActivities(c *gin.Context) {
}
func (api *API) koCheckActivitySync(c *gin.Context) {
rUser, _ := c.Get("AuthorizedUser")
var auth authData
if data, _ := c.Get("Authorization"); data != nil {
auth = data.(authData)
}
var rCheckActivity requestCheckActivitySync
if err := c.ShouldBindJSON(&rCheckActivity); err != nil {
@@ -319,7 +331,7 @@ func (api *API) koCheckActivitySync(c *gin.Context) {
// Upsert Device
if _, err := api.DB.Queries.UpsertDevice(api.DB.Ctx, database.UpsertDeviceParams{
ID: rCheckActivity.DeviceID,
UserID: rUser.(string),
UserID: auth.UserName,
DeviceName: rCheckActivity.Device,
LastSynced: time.Now().UTC().Format(time.RFC3339),
}); err != nil {
@@ -330,7 +342,7 @@ func (api *API) koCheckActivitySync(c *gin.Context) {
// Get Last Device Activity
lastActivity, err := api.DB.Queries.GetLastActivity(api.DB.Ctx, database.GetLastActivityParams{
UserID: rUser.(string),
UserID: auth.UserName,
DeviceID: rCheckActivity.DeviceID,
})
if err == sql.ErrNoRows {
@@ -405,7 +417,10 @@ func (api *API) koAddDocuments(c *gin.Context) {
}
func (api *API) koCheckDocumentsSync(c *gin.Context) {
rUser, _ := c.Get("AuthorizedUser")
var auth authData
if data, _ := c.Get("Authorization"); data != nil {
auth = data.(authData)
}
var rCheckDocs requestCheckDocumentSync
if err := c.ShouldBindJSON(&rCheckDocs); err != nil {
@@ -417,7 +432,7 @@ func (api *API) koCheckDocumentsSync(c *gin.Context) {
// Upsert Device
_, err := api.DB.Queries.UpsertDevice(api.DB.Ctx, database.UpsertDeviceParams{
ID: rCheckDocs.DeviceID,
UserID: rUser.(string),
UserID: auth.UserName,
DeviceName: rCheckDocs.Device,
LastSynced: time.Now().UTC().Format(time.RFC3339),
})

View File

@@ -61,9 +61,9 @@ func (api *API) opdsEntry(c *gin.Context) {
}
func (api *API) opdsDocuments(c *gin.Context) {
var userID string
if rUser, _ := c.Get("AuthorizedUser"); rUser != nil {
userID = rUser.(string)
var auth authData
if data, _ := c.Get("Authorization"); data != nil {
auth = data.(authData)
}
// Potential URL Parameters (Default Pagination - 100)
@@ -78,7 +78,7 @@ func (api *API) opdsDocuments(c *gin.Context) {
// Get Documents
documents, err := api.DB.Queries.GetDocumentsWithStats(api.DB.Ctx, database.GetDocumentsWithStatsParams{
UserID: userID,
UserID: auth.UserName,
Query: query,
Offset: (*qParams.Page - 1) * *qParams.Limit,
Limit: *qParams.Limit,