Compare commits
10 Commits
templ
...
7937890acd
| Author | SHA1 | Date | |
|---|---|---|---|
| 7937890acd | |||
| 938dd69e5e | |||
| 7c92c346fa | |||
| 456b6e457c | |||
| d304421798 | |||
| 0fe52bc541 | |||
| 49f3d53170 | |||
| 57f81e5dd7 | |||
| 162adfbe16 | |||
| e2cfdb3a0c |
@@ -1,5 +1,5 @@
|
|||||||
kind: pipeline
|
kind: pipeline
|
||||||
type: kubernetes
|
type: docker
|
||||||
name: default
|
name: default
|
||||||
|
|
||||||
trigger:
|
trigger:
|
||||||
@@ -27,6 +27,8 @@ steps:
|
|||||||
registry: gitea.va.reichard.io
|
registry: gitea.va.reichard.io
|
||||||
tags:
|
tags:
|
||||||
- dev
|
- dev
|
||||||
|
custom_dns:
|
||||||
|
- 8.8.8.8
|
||||||
username:
|
username:
|
||||||
from_secret: docker_username
|
from_secret: docker_username
|
||||||
password:
|
password:
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ FROM alpine AS alpine
|
|||||||
RUN apk update && apk add --no-cache ca-certificates tzdata
|
RUN apk update && apk add --no-cache ca-certificates tzdata
|
||||||
|
|
||||||
# Build Image
|
# Build Image
|
||||||
FROM golang:1.21 AS build
|
FROM golang:1.24 AS build
|
||||||
|
|
||||||
# Create Package Directory
|
# Create Package Directory
|
||||||
RUN mkdir -p /opt/antholume
|
RUN mkdir -p /opt/antholume
|
||||||
|
|||||||
2
Makefile
2
Makefile
@@ -27,7 +27,7 @@ docker_build_release_latest: build_tailwind
|
|||||||
--push .
|
--push .
|
||||||
|
|
||||||
build_tailwind:
|
build_tailwind:
|
||||||
tailwind build -o ./assets/style.css --minify
|
tailwindcss build -o ./assets/style.css --minify
|
||||||
|
|
||||||
dev: build_tailwind
|
dev: build_tailwind
|
||||||
GIN_MODE=release \
|
GIN_MODE=release \
|
||||||
|
|||||||
14
api/api.go
14
api/api.go
@@ -325,6 +325,13 @@ func (api *API) loadTemplates(
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (api *API) templateMiddleware(router *gin.Engine) gin.HandlerFunc {
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
router.HTMLRender = *api.generateTemplates()
|
||||||
|
c.Next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func loggingMiddleware(c *gin.Context) {
|
func loggingMiddleware(c *gin.Context) {
|
||||||
// Start timer
|
// Start timer
|
||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
@@ -360,10 +367,3 @@ func loggingMiddleware(c *gin.Context) {
|
|||||||
// Log result
|
// Log result
|
||||||
log.WithFields(logData).Info(fmt.Sprintf("%s %s", c.Request.Method, c.Request.URL.Path))
|
log.WithFields(logData).Info(fmt.Sprintf("%s %s", c.Request.Method, c.Request.URL.Path))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *API) templateMiddleware(router *gin.Engine) gin.HandlerFunc {
|
|
||||||
return func(c *gin.Context) {
|
|
||||||
router.HTMLRender = *api.generateTemplates()
|
|
||||||
c.Next()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package api
|
|||||||
import (
|
import (
|
||||||
"archive/zip"
|
"archive/zip"
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"context"
|
||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -112,7 +113,7 @@ func (api *API) appPerformAdminAction(c *gin.Context) {
|
|||||||
// 2. Select all / deselect?
|
// 2. Select all / deselect?
|
||||||
case adminCacheTables:
|
case adminCacheTables:
|
||||||
go func() {
|
go func() {
|
||||||
err := api.db.CacheTempTables()
|
err := api.db.CacheTempTables(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Unable to cache temp tables: ", err)
|
log.Error("Unable to cache temp tables: ", err)
|
||||||
}
|
}
|
||||||
@@ -122,7 +123,7 @@ func (api *API) appPerformAdminAction(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
case adminBackup:
|
case adminBackup:
|
||||||
// Vacuum
|
// Vacuum
|
||||||
_, err := api.db.DB.ExecContext(api.db.Ctx, "VACUUM;")
|
_, err := api.db.DB.ExecContext(c, "VACUUM;")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Unable to vacuum DB: ", err)
|
log.Error("Unable to vacuum DB: ", err)
|
||||||
appErrorPage(c, http.StatusInternalServerError, "Unable to vacuum database")
|
appErrorPage(c, http.StatusInternalServerError, "Unable to vacuum database")
|
||||||
@@ -144,7 +145,7 @@ func (api *API) appPerformAdminAction(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err := api.createBackup(w, directories)
|
err := api.createBackup(c, w, directories)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Backup Error: ", err)
|
log.Error("Backup Error: ", err)
|
||||||
}
|
}
|
||||||
@@ -261,7 +262,7 @@ func (api *API) appGetAdminLogs(c *gin.Context) {
|
|||||||
func (api *API) appGetAdminUsers(c *gin.Context) {
|
func (api *API) appGetAdminUsers(c *gin.Context) {
|
||||||
templateVars, _ := api.getBaseTemplateVars("admin-users", c)
|
templateVars, _ := api.getBaseTemplateVars("admin-users", c)
|
||||||
|
|
||||||
users, err := api.db.Queries.GetUsers(api.db.Ctx)
|
users, err := api.db.Queries.GetUsers(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("GetUsers DB Error: ", err)
|
log.Error("GetUsers DB Error: ", err)
|
||||||
appErrorPage(c, http.StatusInternalServerError, fmt.Sprintf("GetUsers DB Error: %v", err))
|
appErrorPage(c, http.StatusInternalServerError, fmt.Sprintf("GetUsers DB Error: %v", err))
|
||||||
@@ -292,11 +293,11 @@ func (api *API) appUpdateAdminUsers(c *gin.Context) {
|
|||||||
var err error
|
var err error
|
||||||
switch rUpdate.Operation {
|
switch rUpdate.Operation {
|
||||||
case opCreate:
|
case opCreate:
|
||||||
err = api.createUser(rUpdate.User, rUpdate.Password, rUpdate.IsAdmin)
|
err = api.createUser(c, rUpdate.User, rUpdate.Password, rUpdate.IsAdmin)
|
||||||
case opUpdate:
|
case opUpdate:
|
||||||
err = api.updateUser(rUpdate.User, rUpdate.Password, rUpdate.IsAdmin)
|
err = api.updateUser(c, rUpdate.User, rUpdate.Password, rUpdate.IsAdmin)
|
||||||
case opDelete:
|
case opDelete:
|
||||||
err = api.deleteUser(rUpdate.User)
|
err = api.deleteUser(c, rUpdate.User)
|
||||||
default:
|
default:
|
||||||
appErrorPage(c, http.StatusNotFound, "Unknown user operation")
|
appErrorPage(c, http.StatusNotFound, "Unknown user operation")
|
||||||
return
|
return
|
||||||
@@ -307,7 +308,7 @@ func (api *API) appUpdateAdminUsers(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
users, err := api.db.Queries.GetUsers(api.db.Ctx)
|
users, err := api.db.Queries.GetUsers(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("GetUsers DB Error: ", err)
|
log.Error("GetUsers DB Error: ", err)
|
||||||
appErrorPage(c, http.StatusInternalServerError, fmt.Sprintf("GetUsers DB Error: %v", err))
|
appErrorPage(c, http.StatusInternalServerError, fmt.Sprintf("GetUsers DB Error: %v", err))
|
||||||
@@ -448,7 +449,7 @@ func (api *API) appPerformAdminImport(c *gin.Context) {
|
|||||||
iResult.Name = fmt.Sprintf("%s - %s", *fileMeta.Author, *fileMeta.Title)
|
iResult.Name = fmt.Sprintf("%s - %s", *fileMeta.Author, *fileMeta.Title)
|
||||||
|
|
||||||
// Check already exists
|
// Check already exists
|
||||||
_, err = qtx.GetDocument(api.db.Ctx, *fileMeta.PartialMD5)
|
_, err = qtx.GetDocument(c, *fileMeta.PartialMD5)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
log.Warnf("document already exists: %s", *fileMeta.PartialMD5)
|
log.Warnf("document already exists: %s", *fileMeta.PartialMD5)
|
||||||
iResult.Status = importExists
|
iResult.Status = importExists
|
||||||
@@ -492,7 +493,7 @@ func (api *API) appPerformAdminImport(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Upsert document
|
// Upsert document
|
||||||
if _, err = qtx.UpsertDocument(api.db.Ctx, database.UpsertDocumentParams{
|
if _, err = qtx.UpsertDocument(c, database.UpsertDocumentParams{
|
||||||
ID: *fileMeta.PartialMD5,
|
ID: *fileMeta.PartialMD5,
|
||||||
Title: fileMeta.Title,
|
Title: fileMeta.Title,
|
||||||
Author: fileMeta.Author,
|
Author: fileMeta.Author,
|
||||||
@@ -627,7 +628,7 @@ func (api *API) processRestoreFile(rAdminAction requestAdminAction, c *gin.Conte
|
|||||||
|
|
||||||
// Save Backup File
|
// Save Backup File
|
||||||
w := bufio.NewWriter(backupFile)
|
w := bufio.NewWriter(backupFile)
|
||||||
err = api.createBackup(w, []string{"covers", "documents"})
|
err = api.createBackup(c, w, []string{"covers", "documents"})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Unable to save backup file: ", err)
|
log.Error("Unable to save backup file: ", err)
|
||||||
appErrorPage(c, http.StatusInternalServerError, "Unable to save backup file")
|
appErrorPage(c, http.StatusInternalServerError, "Unable to save backup file")
|
||||||
@@ -650,13 +651,13 @@ func (api *API) processRestoreFile(rAdminAction requestAdminAction, c *gin.Conte
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Reinit DB
|
// Reinit DB
|
||||||
if err := api.db.Reload(); err != nil {
|
if err := api.db.Reload(c); err != nil {
|
||||||
appErrorPage(c, http.StatusInternalServerError, "Unable to reload DB")
|
appErrorPage(c, http.StatusInternalServerError, "Unable to reload DB")
|
||||||
log.Panicf("Unable to reload DB: %v", err)
|
log.Panicf("Unable to reload DB: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rotate Auth Hashes
|
// Rotate Auth Hashes
|
||||||
if err := api.rotateAllAuthHashes(); err != nil {
|
if err := api.rotateAllAuthHashes(c); err != nil {
|
||||||
appErrorPage(c, http.StatusInternalServerError, "Unable to rotate hashes")
|
appErrorPage(c, http.StatusInternalServerError, "Unable to rotate hashes")
|
||||||
log.Panicf("Unable to rotate auth hashes: %v", err)
|
log.Panicf("Unable to rotate auth hashes: %v", err)
|
||||||
}
|
}
|
||||||
@@ -717,9 +718,9 @@ func (api *API) removeData() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *API) createBackup(w io.Writer, directories []string) error {
|
func (api *API) createBackup(ctx context.Context, w io.Writer, directories []string) error {
|
||||||
// Vacuum DB
|
// Vacuum DB
|
||||||
_, err := api.db.DB.ExecContext(api.db.Ctx, "VACUUM;")
|
_, err := api.db.DB.ExecContext(ctx, "VACUUM;")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "Unable to vacuum database")
|
return errors.Wrap(err, "Unable to vacuum database")
|
||||||
}
|
}
|
||||||
@@ -792,8 +793,8 @@ func (api *API) createBackup(w io.Writer, directories []string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *API) isLastAdmin(userID string) (bool, error) {
|
func (api *API) isLastAdmin(ctx context.Context, userID string) (bool, error) {
|
||||||
allUsers, err := api.db.Queries.GetUsers(api.db.Ctx)
|
allUsers, err := api.db.Queries.GetUsers(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, errors.Wrap(err, fmt.Sprintf("GetUsers DB Error: %v", err))
|
return false, errors.Wrap(err, fmt.Sprintf("GetUsers DB Error: %v", err))
|
||||||
}
|
}
|
||||||
@@ -809,7 +810,7 @@ func (api *API) isLastAdmin(userID string) (bool, error) {
|
|||||||
return !hasAdmin, nil
|
return !hasAdmin, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *API) createUser(user string, rawPassword *string, isAdmin *bool) error {
|
func (api *API) createUser(ctx context.Context, user string, rawPassword *string, isAdmin *bool) error {
|
||||||
// Validate Necessary Parameters
|
// Validate Necessary Parameters
|
||||||
if rawPassword == nil || *rawPassword == "" {
|
if rawPassword == nil || *rawPassword == "" {
|
||||||
return fmt.Errorf("password can't be empty")
|
return fmt.Errorf("password can't be empty")
|
||||||
@@ -844,7 +845,7 @@ func (api *API) createUser(user string, rawPassword *string, isAdmin *bool) erro
|
|||||||
createParams.AuthHash = &authHash
|
createParams.AuthHash = &authHash
|
||||||
|
|
||||||
// Create user in DB
|
// Create user in DB
|
||||||
if rows, err := api.db.Queries.CreateUser(api.db.Ctx, createParams); err != nil {
|
if rows, err := api.db.Queries.CreateUser(ctx, createParams); err != nil {
|
||||||
log.Error("CreateUser DB Error:", err)
|
log.Error("CreateUser DB Error:", err)
|
||||||
return fmt.Errorf("unable to create user")
|
return fmt.Errorf("unable to create user")
|
||||||
} else if rows == 0 {
|
} else if rows == 0 {
|
||||||
@@ -855,7 +856,7 @@ func (api *API) createUser(user string, rawPassword *string, isAdmin *bool) erro
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *API) updateUser(user string, rawPassword *string, isAdmin *bool) error {
|
func (api *API) updateUser(ctx context.Context, user string, rawPassword *string, isAdmin *bool) error {
|
||||||
// Validate Necessary Parameters
|
// Validate Necessary Parameters
|
||||||
if rawPassword == nil && isAdmin == nil {
|
if rawPassword == nil && isAdmin == nil {
|
||||||
return fmt.Errorf("nothing to update")
|
return fmt.Errorf("nothing to update")
|
||||||
@@ -870,7 +871,7 @@ func (api *API) updateUser(user string, rawPassword *string, isAdmin *bool) erro
|
|||||||
if isAdmin != nil {
|
if isAdmin != nil {
|
||||||
updateParams.Admin = *isAdmin
|
updateParams.Admin = *isAdmin
|
||||||
} else {
|
} else {
|
||||||
user, err := api.db.Queries.GetUser(api.db.Ctx, user)
|
user, err := api.db.Queries.GetUser(ctx, user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, fmt.Sprintf("GetUser DB Error: %v", err))
|
return errors.Wrap(err, fmt.Sprintf("GetUser DB Error: %v", err))
|
||||||
}
|
}
|
||||||
@@ -878,7 +879,7 @@ func (api *API) updateUser(user string, rawPassword *string, isAdmin *bool) erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check Admins - Disallow Demotion
|
// Check Admins - Disallow Demotion
|
||||||
if isLast, err := api.isLastAdmin(user); err != nil {
|
if isLast, err := api.isLastAdmin(ctx, user); err != nil {
|
||||||
return err
|
return err
|
||||||
} else if isLast && !updateParams.Admin {
|
} else if isLast && !updateParams.Admin {
|
||||||
return fmt.Errorf("unable to demote %s - last admin", user)
|
return fmt.Errorf("unable to demote %s - last admin", user)
|
||||||
@@ -908,7 +909,7 @@ func (api *API) updateUser(user string, rawPassword *string, isAdmin *bool) erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update User
|
// Update User
|
||||||
_, err := api.db.Queries.UpdateUser(api.db.Ctx, updateParams)
|
_, err := api.db.Queries.UpdateUser(ctx, updateParams)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, fmt.Sprintf("UpdateUser DB Error: %v", err))
|
return errors.Wrap(err, fmt.Sprintf("UpdateUser DB Error: %v", err))
|
||||||
}
|
}
|
||||||
@@ -916,9 +917,9 @@ func (api *API) updateUser(user string, rawPassword *string, isAdmin *bool) erro
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *API) deleteUser(user string) error {
|
func (api *API) deleteUser(ctx context.Context, user string) error {
|
||||||
// Check Admins
|
// Check Admins
|
||||||
if isLast, err := api.isLastAdmin(user); err != nil {
|
if isLast, err := api.isLastAdmin(ctx, user); err != nil {
|
||||||
return err
|
return err
|
||||||
} else if isLast {
|
} else if isLast {
|
||||||
return fmt.Errorf("unable to delete %s - last admin", user)
|
return fmt.Errorf("unable to delete %s - last admin", user)
|
||||||
@@ -934,13 +935,13 @@ func (api *API) deleteUser(user string) error {
|
|||||||
|
|
||||||
// Save Backup File (DB Only)
|
// Save Backup File (DB Only)
|
||||||
w := bufio.NewWriter(backupFile)
|
w := bufio.NewWriter(backupFile)
|
||||||
err = api.createBackup(w, []string{})
|
err = api.createBackup(ctx, w, []string{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete User
|
// Delete User
|
||||||
_, err = api.db.Queries.DeleteUser(api.db.Ctx, user)
|
_, err = api.db.Queries.DeleteUser(ctx, user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, fmt.Sprintf("DeleteUser DB Error: %v", err))
|
return errors.Wrap(err, fmt.Sprintf("DeleteUser DB Error: %v", err))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -22,6 +23,7 @@ import (
|
|||||||
"golang.org/x/exp/slices"
|
"golang.org/x/exp/slices"
|
||||||
"reichard.io/antholume/database"
|
"reichard.io/antholume/database"
|
||||||
"reichard.io/antholume/metadata"
|
"reichard.io/antholume/metadata"
|
||||||
|
"reichard.io/antholume/pkg/ptr"
|
||||||
"reichard.io/antholume/search"
|
"reichard.io/antholume/search"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -109,11 +111,12 @@ func (api *API) appGetDocuments(c *gin.Context) {
|
|||||||
query = &search
|
query = &search
|
||||||
}
|
}
|
||||||
|
|
||||||
documents, err := api.db.Queries.GetDocumentsWithStats(api.db.Ctx, database.GetDocumentsWithStatsParams{
|
documents, err := api.db.Queries.GetDocumentsWithStats(c, database.GetDocumentsWithStatsParams{
|
||||||
UserID: auth.UserName,
|
UserID: auth.UserName,
|
||||||
Query: query,
|
Query: query,
|
||||||
Offset: (*qParams.Page - 1) * *qParams.Limit,
|
Deleted: ptr.Of(false),
|
||||||
Limit: *qParams.Limit,
|
Offset: (*qParams.Page - 1) * *qParams.Limit,
|
||||||
|
Limit: *qParams.Limit,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("GetDocumentsWithStats DB Error: ", err)
|
log.Error("GetDocumentsWithStats DB Error: ", err)
|
||||||
@@ -121,14 +124,14 @@ func (api *API) appGetDocuments(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
length, err := api.db.Queries.GetDocumentsSize(api.db.Ctx, query)
|
length, err := api.db.Queries.GetDocumentsSize(c, query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("GetDocumentsSize DB Error: ", err)
|
log.Error("GetDocumentsSize DB Error: ", err)
|
||||||
appErrorPage(c, http.StatusInternalServerError, fmt.Sprintf("GetDocumentsSize DB Error: %v", err))
|
appErrorPage(c, http.StatusInternalServerError, fmt.Sprintf("GetDocumentsSize DB Error: %v", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = api.getDocumentsWordCount(documents); err != nil {
|
if err = api.getDocumentsWordCount(c, documents); err != nil {
|
||||||
log.Error("Unable to Get Word Counts: ", err)
|
log.Error("Unable to Get Word Counts: ", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,13 +163,10 @@ func (api *API) appGetDocument(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
document, err := api.db.Queries.GetDocumentWithStats(api.db.Ctx, database.GetDocumentWithStatsParams{
|
document, err := api.db.GetDocument(c, rDocID.DocumentID, auth.UserName)
|
||||||
UserID: auth.UserName,
|
|
||||||
DocumentID: rDocID.DocumentID,
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("GetDocumentWithStats DB Error: ", err)
|
log.Error("GetDocument DB Error: ", err)
|
||||||
appErrorPage(c, http.StatusInternalServerError, fmt.Sprintf("GetDocumentsWithStats DB Error: %v", err))
|
appErrorPage(c, http.StatusInternalServerError, fmt.Sprintf("GetDocument DB Error: %v", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,7 +192,7 @@ func (api *API) appGetProgress(c *gin.Context) {
|
|||||||
progressFilter.DocumentID = *qParams.Document
|
progressFilter.DocumentID = *qParams.Document
|
||||||
}
|
}
|
||||||
|
|
||||||
progress, err := api.db.Queries.GetProgress(api.db.Ctx, progressFilter)
|
progress, err := api.db.Queries.GetProgress(c, progressFilter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("GetProgress DB Error: ", err)
|
log.Error("GetProgress DB Error: ", err)
|
||||||
appErrorPage(c, http.StatusInternalServerError, fmt.Sprintf("GetActivity DB Error: %v", err))
|
appErrorPage(c, http.StatusInternalServerError, fmt.Sprintf("GetActivity DB Error: %v", err))
|
||||||
@@ -219,7 +219,7 @@ func (api *API) appGetActivity(c *gin.Context) {
|
|||||||
activityFilter.DocumentID = *qParams.Document
|
activityFilter.DocumentID = *qParams.Document
|
||||||
}
|
}
|
||||||
|
|
||||||
activity, err := api.db.Queries.GetActivity(api.db.Ctx, activityFilter)
|
activity, err := api.db.Queries.GetActivity(c, activityFilter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("GetActivity DB Error: ", err)
|
log.Error("GetActivity DB Error: ", err)
|
||||||
appErrorPage(c, http.StatusInternalServerError, fmt.Sprintf("GetActivity DB Error: %v", err))
|
appErrorPage(c, http.StatusInternalServerError, fmt.Sprintf("GetActivity DB Error: %v", err))
|
||||||
@@ -235,7 +235,7 @@ func (api *API) appGetHome(c *gin.Context) {
|
|||||||
templateVars, auth := api.getBaseTemplateVars("home", c)
|
templateVars, auth := api.getBaseTemplateVars("home", c)
|
||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
graphData, err := api.db.Queries.GetDailyReadStats(api.db.Ctx, auth.UserName)
|
graphData, err := api.db.Queries.GetDailyReadStats(c, auth.UserName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("GetDailyReadStats DB Error: ", err)
|
log.Error("GetDailyReadStats DB Error: ", err)
|
||||||
appErrorPage(c, http.StatusInternalServerError, fmt.Sprintf("GetDailyReadStats DB Error: %v", err))
|
appErrorPage(c, http.StatusInternalServerError, fmt.Sprintf("GetDailyReadStats DB Error: %v", err))
|
||||||
@@ -244,7 +244,7 @@ func (api *API) appGetHome(c *gin.Context) {
|
|||||||
log.Debug("GetDailyReadStats DB Performance: ", time.Since(start))
|
log.Debug("GetDailyReadStats DB Performance: ", time.Since(start))
|
||||||
|
|
||||||
start = time.Now()
|
start = time.Now()
|
||||||
databaseInfo, err := api.db.Queries.GetDatabaseInfo(api.db.Ctx, auth.UserName)
|
databaseInfo, err := api.db.Queries.GetDatabaseInfo(c, auth.UserName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("GetDatabaseInfo DB Error: ", err)
|
log.Error("GetDatabaseInfo DB Error: ", err)
|
||||||
appErrorPage(c, http.StatusInternalServerError, fmt.Sprintf("GetDatabaseInfo DB Error: %v", err))
|
appErrorPage(c, http.StatusInternalServerError, fmt.Sprintf("GetDatabaseInfo DB Error: %v", err))
|
||||||
@@ -253,7 +253,7 @@ func (api *API) appGetHome(c *gin.Context) {
|
|||||||
log.Debug("GetDatabaseInfo DB Performance: ", time.Since(start))
|
log.Debug("GetDatabaseInfo DB Performance: ", time.Since(start))
|
||||||
|
|
||||||
start = time.Now()
|
start = time.Now()
|
||||||
streaks, err := api.db.Queries.GetUserStreaks(api.db.Ctx, auth.UserName)
|
streaks, err := api.db.Queries.GetUserStreaks(c, auth.UserName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("GetUserStreaks DB Error: ", err)
|
log.Error("GetUserStreaks DB Error: ", err)
|
||||||
appErrorPage(c, http.StatusInternalServerError, fmt.Sprintf("GetUserStreaks DB Error: %v", err))
|
appErrorPage(c, http.StatusInternalServerError, fmt.Sprintf("GetUserStreaks DB Error: %v", err))
|
||||||
@@ -262,7 +262,7 @@ func (api *API) appGetHome(c *gin.Context) {
|
|||||||
log.Debug("GetUserStreaks DB Performance: ", time.Since(start))
|
log.Debug("GetUserStreaks DB Performance: ", time.Since(start))
|
||||||
|
|
||||||
start = time.Now()
|
start = time.Now()
|
||||||
userStatistics, err := api.db.Queries.GetUserStatistics(api.db.Ctx)
|
userStatistics, err := api.db.Queries.GetUserStatistics(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("GetUserStatistics DB Error: ", err)
|
log.Error("GetUserStatistics DB Error: ", err)
|
||||||
appErrorPage(c, http.StatusInternalServerError, fmt.Sprintf("GetUserStatistics DB Error: %v", err))
|
appErrorPage(c, http.StatusInternalServerError, fmt.Sprintf("GetUserStatistics DB Error: %v", err))
|
||||||
@@ -283,14 +283,14 @@ func (api *API) appGetHome(c *gin.Context) {
|
|||||||
func (api *API) appGetSettings(c *gin.Context) {
|
func (api *API) appGetSettings(c *gin.Context) {
|
||||||
templateVars, auth := api.getBaseTemplateVars("settings", c)
|
templateVars, auth := api.getBaseTemplateVars("settings", c)
|
||||||
|
|
||||||
user, err := api.db.Queries.GetUser(api.db.Ctx, auth.UserName)
|
user, err := api.db.Queries.GetUser(c, auth.UserName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("GetUser DB Error: ", err)
|
log.Error("GetUser DB Error: ", err)
|
||||||
appErrorPage(c, http.StatusInternalServerError, fmt.Sprintf("GetUser DB Error: %v", err))
|
appErrorPage(c, http.StatusInternalServerError, fmt.Sprintf("GetUser DB Error: %v", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
devices, err := api.db.Queries.GetDevices(api.db.Ctx, auth.UserName)
|
devices, err := api.db.Queries.GetDevices(c, auth.UserName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("GetDevices DB Error: ", err)
|
log.Error("GetDevices DB Error: ", err)
|
||||||
appErrorPage(c, http.StatusInternalServerError, fmt.Sprintf("GetDevices DB Error: %v", err))
|
appErrorPage(c, http.StatusInternalServerError, fmt.Sprintf("GetDevices DB Error: %v", err))
|
||||||
@@ -368,7 +368,7 @@ func (api *API) appGetDocumentProgress(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
progress, err := api.db.Queries.GetDocumentProgress(api.db.Ctx, database.GetDocumentProgressParams{
|
progress, err := api.db.Queries.GetDocumentProgress(c, database.GetDocumentProgressParams{
|
||||||
DocumentID: rDoc.DocumentID,
|
DocumentID: rDoc.DocumentID,
|
||||||
UserID: auth.UserName,
|
UserID: auth.UserName,
|
||||||
})
|
})
|
||||||
@@ -378,13 +378,10 @@ func (api *API) appGetDocumentProgress(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
document, err := api.db.Queries.GetDocumentWithStats(api.db.Ctx, database.GetDocumentWithStatsParams{
|
document, err := api.db.GetDocument(c, rDoc.DocumentID, auth.UserName)
|
||||||
UserID: auth.UserName,
|
|
||||||
DocumentID: rDoc.DocumentID,
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("GetDocumentWithStats DB Error: ", err)
|
log.Error("GetDocument DB Error: ", err)
|
||||||
appErrorPage(c, http.StatusInternalServerError, fmt.Sprintf("GetDocumentWithStats DB Error: %v", err))
|
appErrorPage(c, http.StatusInternalServerError, fmt.Sprintf("GetDocument DB Error: %v", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -404,7 +401,7 @@ func (api *API) appGetDevices(c *gin.Context) {
|
|||||||
auth = data.(authData)
|
auth = data.(authData)
|
||||||
}
|
}
|
||||||
|
|
||||||
devices, err := api.db.Queries.GetDevices(api.db.Ctx, auth.UserName)
|
devices, err := api.db.Queries.GetDevices(c, auth.UserName)
|
||||||
|
|
||||||
if err != nil && err != sql.ErrNoRows {
|
if err != nil && err != sql.ErrNoRows {
|
||||||
log.Error("GetDevices DB Error: ", err)
|
log.Error("GetDevices DB Error: ", err)
|
||||||
@@ -455,7 +452,7 @@ func (api *API) appUploadNewDocument(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check Already Exists
|
// Check Already Exists
|
||||||
_, err = api.db.Queries.GetDocument(api.db.Ctx, *metadataInfo.PartialMD5)
|
_, err = api.db.Queries.GetDocument(c, *metadataInfo.PartialMD5)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
log.Warnf("document already exists: %s", *metadataInfo.PartialMD5)
|
log.Warnf("document already exists: %s", *metadataInfo.PartialMD5)
|
||||||
c.Redirect(http.StatusFound, fmt.Sprintf("./documents/%s", *metadataInfo.PartialMD5))
|
c.Redirect(http.StatusFound, fmt.Sprintf("./documents/%s", *metadataInfo.PartialMD5))
|
||||||
@@ -483,7 +480,7 @@ func (api *API) appUploadNewDocument(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Upsert Document
|
// Upsert Document
|
||||||
if _, err = api.db.Queries.UpsertDocument(api.db.Ctx, database.UpsertDocumentParams{
|
if _, err = api.db.Queries.UpsertDocument(c, database.UpsertDocumentParams{
|
||||||
ID: *metadataInfo.PartialMD5,
|
ID: *metadataInfo.PartialMD5,
|
||||||
Title: metadataInfo.Title,
|
Title: metadataInfo.Title,
|
||||||
Author: metadataInfo.Author,
|
Author: metadataInfo.Author,
|
||||||
@@ -573,7 +570,7 @@ func (api *API) appEditDocument(c *gin.Context) {
|
|||||||
|
|
||||||
coverFileName = &fileName
|
coverFileName = &fileName
|
||||||
} else if rDocEdit.CoverGBID != nil {
|
} else if rDocEdit.CoverGBID != nil {
|
||||||
var coverDir string = filepath.Join(api.cfg.DataPath, "covers")
|
coverDir := filepath.Join(api.cfg.DataPath, "covers")
|
||||||
fileName, err := metadata.CacheCover(*rDocEdit.CoverGBID, coverDir, rDocID.DocumentID, true)
|
fileName, err := metadata.CacheCover(*rDocEdit.CoverGBID, coverDir, rDocID.DocumentID, true)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
coverFileName = fileName
|
coverFileName = fileName
|
||||||
@@ -581,7 +578,7 @@ func (api *API) appEditDocument(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update Document
|
// Update Document
|
||||||
if _, err := api.db.Queries.UpsertDocument(api.db.Ctx, database.UpsertDocumentParams{
|
if _, err := api.db.Queries.UpsertDocument(c, database.UpsertDocumentParams{
|
||||||
ID: rDocID.DocumentID,
|
ID: rDocID.DocumentID,
|
||||||
Title: api.sanitizeInput(rDocEdit.Title),
|
Title: api.sanitizeInput(rDocEdit.Title),
|
||||||
Author: api.sanitizeInput(rDocEdit.Author),
|
Author: api.sanitizeInput(rDocEdit.Author),
|
||||||
@@ -605,7 +602,7 @@ func (api *API) appDeleteDocument(c *gin.Context) {
|
|||||||
appErrorPage(c, http.StatusNotFound, "Invalid document")
|
appErrorPage(c, http.StatusNotFound, "Invalid document")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
changed, err := api.db.Queries.DeleteDocument(api.db.Ctx, rDocID.DocumentID)
|
changed, err := api.db.Queries.DeleteDocument(c, rDocID.DocumentID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("DeleteDocument DB Error")
|
log.Error("DeleteDocument DB Error")
|
||||||
appErrorPage(c, http.StatusInternalServerError, fmt.Sprintf("DeleteDocument DB Error: %v", err))
|
appErrorPage(c, http.StatusInternalServerError, fmt.Sprintf("DeleteDocument DB Error: %v", err))
|
||||||
@@ -667,7 +664,7 @@ func (api *API) appIdentifyDocument(c *gin.Context) {
|
|||||||
firstResult := metadataResults[0]
|
firstResult := metadataResults[0]
|
||||||
|
|
||||||
// Store First Metadata Result
|
// Store First Metadata Result
|
||||||
if _, err = api.db.Queries.AddMetadata(api.db.Ctx, database.AddMetadataParams{
|
if _, err = api.db.Queries.AddMetadata(c, database.AddMetadataParams{
|
||||||
DocumentID: rDocID.DocumentID,
|
DocumentID: rDocID.DocumentID,
|
||||||
Title: firstResult.Title,
|
Title: firstResult.Title,
|
||||||
Author: firstResult.Author,
|
Author: firstResult.Author,
|
||||||
@@ -686,13 +683,10 @@ func (api *API) appIdentifyDocument(c *gin.Context) {
|
|||||||
templateVars["MetadataError"] = "No Metadata Found"
|
templateVars["MetadataError"] = "No Metadata Found"
|
||||||
}
|
}
|
||||||
|
|
||||||
document, err := api.db.Queries.GetDocumentWithStats(api.db.Ctx, database.GetDocumentWithStatsParams{
|
document, err := api.db.GetDocument(c, rDocID.DocumentID, auth.UserName)
|
||||||
UserID: auth.UserName,
|
|
||||||
DocumentID: rDocID.DocumentID,
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("GetDocumentWithStats DB Error: ", err)
|
log.Error("GetDocument DB Error: ", err)
|
||||||
appErrorPage(c, http.StatusInternalServerError, fmt.Sprintf("GetDocumentWithStats DB Error: %v", err))
|
appErrorPage(c, http.StatusInternalServerError, fmt.Sprintf("GetDocument DB Error: %v", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -817,7 +811,7 @@ func (api *API) appSaveNewDocument(c *gin.Context) {
|
|||||||
sendDownloadMessage("Saving to database...", gin.H{"Progress": 99})
|
sendDownloadMessage("Saving to database...", gin.H{"Progress": 99})
|
||||||
|
|
||||||
// Upsert Document
|
// Upsert Document
|
||||||
if _, err = api.db.Queries.UpsertDocument(api.db.Ctx, database.UpsertDocumentParams{
|
if _, err = api.db.Queries.UpsertDocument(c, database.UpsertDocumentParams{
|
||||||
ID: *metadata.PartialMD5,
|
ID: *metadata.PartialMD5,
|
||||||
Title: &docTitle,
|
Title: &docTitle,
|
||||||
Author: &docAuthor,
|
Author: &docAuthor,
|
||||||
@@ -864,7 +858,7 @@ func (api *API) appEditSettings(c *gin.Context) {
|
|||||||
// Set New Password
|
// Set New Password
|
||||||
if rUserSettings.Password != nil && rUserSettings.NewPassword != nil {
|
if rUserSettings.Password != nil && rUserSettings.NewPassword != nil {
|
||||||
password := fmt.Sprintf("%x", md5.Sum([]byte(*rUserSettings.Password)))
|
password := fmt.Sprintf("%x", md5.Sum([]byte(*rUserSettings.Password)))
|
||||||
data := api.authorizeCredentials(auth.UserName, password)
|
data := api.authorizeCredentials(c, auth.UserName, password)
|
||||||
if data == nil {
|
if data == nil {
|
||||||
templateVars["PasswordErrorMessage"] = "Invalid Password"
|
templateVars["PasswordErrorMessage"] = "Invalid Password"
|
||||||
} else {
|
} else {
|
||||||
@@ -886,7 +880,7 @@ func (api *API) appEditSettings(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update User
|
// Update User
|
||||||
_, err := api.db.Queries.UpdateUser(api.db.Ctx, newUserSettings)
|
_, err := api.db.Queries.UpdateUser(c, newUserSettings)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("UpdateUser DB Error: ", err)
|
log.Error("UpdateUser DB Error: ", err)
|
||||||
appErrorPage(c, http.StatusInternalServerError, fmt.Sprintf("UpdateUser DB Error: %v", err))
|
appErrorPage(c, http.StatusInternalServerError, fmt.Sprintf("UpdateUser DB Error: %v", err))
|
||||||
@@ -894,7 +888,7 @@ func (api *API) appEditSettings(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get User
|
// Get User
|
||||||
user, err := api.db.Queries.GetUser(api.db.Ctx, auth.UserName)
|
user, err := api.db.Queries.GetUser(c, auth.UserName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("GetUser DB Error: ", err)
|
log.Error("GetUser DB Error: ", err)
|
||||||
appErrorPage(c, http.StatusInternalServerError, fmt.Sprintf("GetUser DB Error: %v", err))
|
appErrorPage(c, http.StatusInternalServerError, fmt.Sprintf("GetUser DB Error: %v", err))
|
||||||
@@ -902,7 +896,7 @@ func (api *API) appEditSettings(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get Devices
|
// Get Devices
|
||||||
devices, err := api.db.Queries.GetDevices(api.db.Ctx, auth.UserName)
|
devices, err := api.db.Queries.GetDevices(c, auth.UserName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("GetDevices DB Error: ", err)
|
log.Error("GetDevices DB Error: ", err)
|
||||||
appErrorPage(c, http.StatusInternalServerError, fmt.Sprintf("GetDevices DB Error: %v", err))
|
appErrorPage(c, http.StatusInternalServerError, fmt.Sprintf("GetDevices DB Error: %v", err))
|
||||||
@@ -921,7 +915,7 @@ func (api *API) appDemoModeError(c *gin.Context) {
|
|||||||
appErrorPage(c, http.StatusUnauthorized, "Not Allowed in Demo Mode")
|
appErrorPage(c, http.StatusUnauthorized, "Not Allowed in Demo Mode")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *API) getDocumentsWordCount(documents []database.GetDocumentsWithStatsRow) error {
|
func (api *API) getDocumentsWordCount(ctx context.Context, documents []database.GetDocumentsWithStatsRow) error {
|
||||||
// Do Transaction
|
// Do Transaction
|
||||||
tx, err := api.db.DB.Begin()
|
tx, err := api.db.DB.Begin()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -944,7 +938,7 @@ func (api *API) getDocumentsWordCount(documents []database.GetDocumentsWithStats
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn("Word Count Error: ", err)
|
log.Warn("Word Count Error: ", err)
|
||||||
} else {
|
} else {
|
||||||
if _, err := qtx.UpsertDocument(api.db.Ctx, database.UpsertDocumentParams{
|
if _, err := qtx.UpsertDocument(ctx, database.UpsertDocumentParams{
|
||||||
ID: item.ID,
|
ID: item.ID,
|
||||||
Words: wordCount,
|
Words: wordCount,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
@@ -1005,7 +999,7 @@ func bindQueryParams(c *gin.Context, defaultLimit int64) queryParams {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func appErrorPage(c *gin.Context, errorCode int, errorMessage string) {
|
func appErrorPage(c *gin.Context, errorCode int, errorMessage string) {
|
||||||
var errorHuman string = "We're not even sure what happened."
|
errorHuman := "We're not even sure what happened."
|
||||||
|
|
||||||
switch errorCode {
|
switch errorCode {
|
||||||
case http.StatusInternalServerError:
|
case http.StatusInternalServerError:
|
||||||
|
|||||||
39
api/auth.go
39
api/auth.go
@@ -1,6 +1,7 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -28,8 +29,8 @@ type authKOHeader struct {
|
|||||||
AuthKey string `header:"x-auth-key"`
|
AuthKey string `header:"x-auth-key"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *API) authorizeCredentials(username string, password string) (auth *authData) {
|
func (api *API) authorizeCredentials(ctx context.Context, username string, password string) (auth *authData) {
|
||||||
user, err := api.db.Queries.GetUser(api.db.Ctx, username)
|
user, err := api.db.Queries.GetUser(ctx, username)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -52,7 +53,7 @@ func (api *API) authKOMiddleware(c *gin.Context) {
|
|||||||
session := sessions.Default(c)
|
session := sessions.Default(c)
|
||||||
|
|
||||||
// Check Session First
|
// Check Session First
|
||||||
if auth, ok := api.getSession(session); ok {
|
if auth, ok := api.getSession(c, session); ok {
|
||||||
c.Set("Authorization", auth)
|
c.Set("Authorization", auth)
|
||||||
c.Header("Cache-Control", "private")
|
c.Header("Cache-Control", "private")
|
||||||
c.Next()
|
c.Next()
|
||||||
@@ -71,7 +72,7 @@ func (api *API) authKOMiddleware(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
authData := api.authorizeCredentials(rHeader.AuthUser, rHeader.AuthKey)
|
authData := api.authorizeCredentials(c, rHeader.AuthUser, rHeader.AuthKey)
|
||||||
if authData == nil {
|
if authData == nil {
|
||||||
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
|
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
|
||||||
return
|
return
|
||||||
@@ -100,7 +101,7 @@ func (api *API) authOPDSMiddleware(c *gin.Context) {
|
|||||||
|
|
||||||
// Validate Auth
|
// Validate Auth
|
||||||
password := fmt.Sprintf("%x", md5.Sum([]byte(rawPassword)))
|
password := fmt.Sprintf("%x", md5.Sum([]byte(rawPassword)))
|
||||||
authData := api.authorizeCredentials(user, password)
|
authData := api.authorizeCredentials(c, user, password)
|
||||||
if authData == nil {
|
if authData == nil {
|
||||||
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
|
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
|
||||||
return
|
return
|
||||||
@@ -115,7 +116,7 @@ func (api *API) authWebAppMiddleware(c *gin.Context) {
|
|||||||
session := sessions.Default(c)
|
session := sessions.Default(c)
|
||||||
|
|
||||||
// Check Session
|
// Check Session
|
||||||
if auth, ok := api.getSession(session); ok {
|
if auth, ok := api.getSession(c, session); ok {
|
||||||
c.Set("Authorization", auth)
|
c.Set("Authorization", auth)
|
||||||
c.Header("Cache-Control", "private")
|
c.Header("Cache-Control", "private")
|
||||||
c.Next()
|
c.Next()
|
||||||
@@ -153,7 +154,7 @@ func (api *API) appAuthLogin(c *gin.Context) {
|
|||||||
|
|
||||||
// MD5 - KOSync Compatiblity
|
// MD5 - KOSync Compatiblity
|
||||||
password := fmt.Sprintf("%x", md5.Sum([]byte(rawPassword)))
|
password := fmt.Sprintf("%x", md5.Sum([]byte(rawPassword)))
|
||||||
authData := api.authorizeCredentials(username, password)
|
authData := api.authorizeCredentials(c, username, password)
|
||||||
if authData == nil {
|
if authData == nil {
|
||||||
templateVars["Error"] = "Invalid Credentials"
|
templateVars["Error"] = "Invalid Credentials"
|
||||||
c.HTML(http.StatusUnauthorized, "page/login", templateVars)
|
c.HTML(http.StatusUnauthorized, "page/login", templateVars)
|
||||||
@@ -208,7 +209,7 @@ func (api *API) appAuthRegister(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get current users
|
// Get current users
|
||||||
currentUsers, err := api.db.Queries.GetUsers(api.db.Ctx)
|
currentUsers, err := api.db.Queries.GetUsers(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Failed to check all users: ", err)
|
log.Error("Failed to check all users: ", err)
|
||||||
templateVars["Error"] = "Failed to Create User"
|
templateVars["Error"] = "Failed to Create User"
|
||||||
@@ -224,7 +225,7 @@ func (api *API) appAuthRegister(c *gin.Context) {
|
|||||||
|
|
||||||
// Create user in DB
|
// Create user in DB
|
||||||
authHash := fmt.Sprintf("%x", rawAuthHash)
|
authHash := fmt.Sprintf("%x", rawAuthHash)
|
||||||
if rows, err := api.db.Queries.CreateUser(api.db.Ctx, database.CreateUserParams{
|
if rows, err := api.db.Queries.CreateUser(c, database.CreateUserParams{
|
||||||
ID: username,
|
ID: username,
|
||||||
Pass: &hashedPassword,
|
Pass: &hashedPassword,
|
||||||
AuthHash: &authHash,
|
AuthHash: &authHash,
|
||||||
@@ -242,7 +243,7 @@ func (api *API) appAuthRegister(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get user
|
// Get user
|
||||||
user, err := api.db.Queries.GetUser(api.db.Ctx, username)
|
user, err := api.db.Queries.GetUser(c, username)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("GetUser DB Error:", err)
|
log.Error("GetUser DB Error:", err)
|
||||||
templateVars["Error"] = "Registration Disabled or User Already Exists"
|
templateVars["Error"] = "Registration Disabled or User Already Exists"
|
||||||
@@ -312,7 +313,7 @@ func (api *API) koAuthRegister(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get current users
|
// Get current users
|
||||||
currentUsers, err := api.db.Queries.GetUsers(api.db.Ctx)
|
currentUsers, err := api.db.Queries.GetUsers(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Failed to check all users: ", err)
|
log.Error("Failed to check all users: ", err)
|
||||||
apiErrorPage(c, http.StatusBadRequest, "Failed to Create User")
|
apiErrorPage(c, http.StatusBadRequest, "Failed to Create User")
|
||||||
@@ -327,7 +328,7 @@ func (api *API) koAuthRegister(c *gin.Context) {
|
|||||||
|
|
||||||
// Create user
|
// Create user
|
||||||
authHash := fmt.Sprintf("%x", rawAuthHash)
|
authHash := fmt.Sprintf("%x", rawAuthHash)
|
||||||
if rows, err := api.db.Queries.CreateUser(api.db.Ctx, database.CreateUserParams{
|
if rows, err := api.db.Queries.CreateUser(c, database.CreateUserParams{
|
||||||
ID: rUser.Username,
|
ID: rUser.Username,
|
||||||
Pass: &hashedPassword,
|
Pass: &hashedPassword,
|
||||||
AuthHash: &authHash,
|
AuthHash: &authHash,
|
||||||
@@ -347,7 +348,7 @@ func (api *API) koAuthRegister(c *gin.Context) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *API) getSession(session sessions.Session) (auth authData, ok bool) {
|
func (api *API) getSession(ctx context.Context, session sessions.Session) (auth authData, ok bool) {
|
||||||
// Get Session
|
// Get Session
|
||||||
authorizedUser := session.Get("authorizedUser")
|
authorizedUser := session.Get("authorizedUser")
|
||||||
isAdmin := session.Get("isAdmin")
|
isAdmin := session.Get("isAdmin")
|
||||||
@@ -365,7 +366,7 @@ func (api *API) getSession(session sessions.Session) (auth authData, ok bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Validate Auth Hash
|
// Validate Auth Hash
|
||||||
correctAuthHash, err := api.getUserAuthHash(auth.UserName)
|
correctAuthHash, err := api.getUserAuthHash(ctx, auth.UserName)
|
||||||
if err != nil || correctAuthHash != auth.AuthHash {
|
if err != nil || correctAuthHash != auth.AuthHash {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -393,14 +394,14 @@ func (api *API) setSession(session sessions.Session, auth authData) error {
|
|||||||
return session.Save()
|
return session.Save()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *API) getUserAuthHash(username string) (string, error) {
|
func (api *API) getUserAuthHash(ctx context.Context, username string) (string, error) {
|
||||||
// Return Cache
|
// Return Cache
|
||||||
if api.userAuthCache[username] != "" {
|
if api.userAuthCache[username] != "" {
|
||||||
return api.userAuthCache[username], nil
|
return api.userAuthCache[username], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get DB
|
// Get DB
|
||||||
user, err := api.db.Queries.GetUser(api.db.Ctx, username)
|
user, err := api.db.Queries.GetUser(ctx, username)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("GetUser DB Error:", err)
|
log.Error("GetUser DB Error:", err)
|
||||||
return "", err
|
return "", err
|
||||||
@@ -412,7 +413,7 @@ func (api *API) getUserAuthHash(username string) (string, error) {
|
|||||||
return api.userAuthCache[username], nil
|
return api.userAuthCache[username], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *API) rotateAllAuthHashes() error {
|
func (api *API) rotateAllAuthHashes(ctx context.Context) error {
|
||||||
// Do Transaction
|
// Do Transaction
|
||||||
tx, err := api.db.DB.Begin()
|
tx, err := api.db.DB.Begin()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -428,7 +429,7 @@ func (api *API) rotateAllAuthHashes() error {
|
|||||||
}()
|
}()
|
||||||
qtx := api.db.Queries.WithTx(tx)
|
qtx := api.db.Queries.WithTx(tx)
|
||||||
|
|
||||||
users, err := qtx.GetUsers(api.db.Ctx)
|
users, err := qtx.GetUsers(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -444,7 +445,7 @@ func (api *API) rotateAllAuthHashes() error {
|
|||||||
|
|
||||||
// Update User
|
// Update User
|
||||||
authHash := fmt.Sprintf("%x", rawAuthHash)
|
authHash := fmt.Sprintf("%x", rawAuthHash)
|
||||||
if _, err = qtx.UpdateUser(api.db.Ctx, database.UpdateUserParams{
|
if _, err = qtx.UpdateUser(ctx, database.UpdateUserParams{
|
||||||
UserID: user.ID,
|
UserID: user.ID,
|
||||||
AuthHash: &authHash,
|
AuthHash: &authHash,
|
||||||
Admin: user.Admin,
|
Admin: user.Admin,
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ func (api *API) createDownloadDocumentHandler(errorFunc func(*gin.Context, int,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get Document
|
// Get Document
|
||||||
document, err := api.db.Queries.GetDocument(api.db.Ctx, rDoc.DocumentID)
|
document, err := api.db.Queries.GetDocument(c, rDoc.DocumentID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("GetDocument DB Error:", err)
|
log.Error("GetDocument DB Error:", err)
|
||||||
errorFunc(c, http.StatusBadRequest, "Unknown Document")
|
errorFunc(c, http.StatusBadRequest, "Unknown Document")
|
||||||
@@ -68,7 +68,7 @@ func (api *API) createGetCoverHandler(errorFunc func(*gin.Context, int, string))
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Validate Document Exists in DB
|
// Validate Document Exists in DB
|
||||||
document, err := api.db.Queries.GetDocument(api.db.Ctx, rDoc.DocumentID)
|
document, err := api.db.Queries.GetDocument(c, rDoc.DocumentID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("GetDocument DB Error:", err)
|
log.Error("GetDocument DB Error:", err)
|
||||||
errorFunc(c, http.StatusInternalServerError, fmt.Sprintf("GetDocument DB Error: %v", err))
|
errorFunc(c, http.StatusInternalServerError, fmt.Sprintf("GetDocument DB Error: %v", err))
|
||||||
@@ -117,7 +117,7 @@ func (api *API) createGetCoverHandler(errorFunc func(*gin.Context, int, string))
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Store First Metadata Result
|
// Store First Metadata Result
|
||||||
if _, err = api.db.Queries.AddMetadata(api.db.Ctx, database.AddMetadataParams{
|
if _, err = api.db.Queries.AddMetadata(c, database.AddMetadataParams{
|
||||||
DocumentID: document.ID,
|
DocumentID: document.ID,
|
||||||
Title: firstResult.Title,
|
Title: firstResult.Title,
|
||||||
Author: firstResult.Author,
|
Author: firstResult.Author,
|
||||||
@@ -132,7 +132,7 @@ func (api *API) createGetCoverHandler(errorFunc func(*gin.Context, int, string))
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Upsert Document
|
// Upsert Document
|
||||||
if _, err = api.db.Queries.UpsertDocument(api.db.Ctx, database.UpsertDocumentParams{
|
if _, err = api.db.Queries.UpsertDocument(c, database.UpsertDocumentParams{
|
||||||
ID: document.ID,
|
ID: document.ID,
|
||||||
Coverfile: &coverFile,
|
Coverfile: &coverFile,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ type requestDocumentID struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (api *API) koAuthorizeUser(c *gin.Context) {
|
func (api *API) koAuthorizeUser(c *gin.Context) {
|
||||||
c.JSON(200, gin.H{
|
koJSON(c, 200, gin.H{
|
||||||
"authorized": "OK",
|
"authorized": "OK",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -91,7 +91,7 @@ func (api *API) koSetProgress(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Upsert Device
|
// Upsert Device
|
||||||
if _, err := api.db.Queries.UpsertDevice(api.db.Ctx, database.UpsertDeviceParams{
|
if _, err := api.db.Queries.UpsertDevice(c, database.UpsertDeviceParams{
|
||||||
ID: rPosition.DeviceID,
|
ID: rPosition.DeviceID,
|
||||||
UserID: auth.UserName,
|
UserID: auth.UserName,
|
||||||
DeviceName: rPosition.Device,
|
DeviceName: rPosition.Device,
|
||||||
@@ -101,14 +101,14 @@ func (api *API) koSetProgress(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Upsert Document
|
// Upsert Document
|
||||||
if _, err := api.db.Queries.UpsertDocument(api.db.Ctx, database.UpsertDocumentParams{
|
if _, err := api.db.Queries.UpsertDocument(c, database.UpsertDocumentParams{
|
||||||
ID: rPosition.DocumentID,
|
ID: rPosition.DocumentID,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
log.Error("UpsertDocument DB Error:", err)
|
log.Error("UpsertDocument DB Error:", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create or Replace Progress
|
// Create or Replace Progress
|
||||||
progress, err := api.db.Queries.UpdateProgress(api.db.Ctx, database.UpdateProgressParams{
|
progress, err := api.db.Queries.UpdateProgress(c, database.UpdateProgressParams{
|
||||||
Percentage: rPosition.Percentage,
|
Percentage: rPosition.Percentage,
|
||||||
DocumentID: rPosition.DocumentID,
|
DocumentID: rPosition.DocumentID,
|
||||||
DeviceID: rPosition.DeviceID,
|
DeviceID: rPosition.DeviceID,
|
||||||
@@ -121,7 +121,7 @@ func (api *API) koSetProgress(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.JSON(http.StatusOK, gin.H{
|
koJSON(c, http.StatusOK, gin.H{
|
||||||
"document": progress.DocumentID,
|
"document": progress.DocumentID,
|
||||||
"timestamp": progress.CreatedAt,
|
"timestamp": progress.CreatedAt,
|
||||||
})
|
})
|
||||||
@@ -140,14 +140,14 @@ func (api *API) koGetProgress(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
progress, err := api.db.Queries.GetDocumentProgress(api.db.Ctx, database.GetDocumentProgressParams{
|
progress, err := api.db.Queries.GetDocumentProgress(c, database.GetDocumentProgressParams{
|
||||||
DocumentID: rDocID.DocumentID,
|
DocumentID: rDocID.DocumentID,
|
||||||
UserID: auth.UserName,
|
UserID: auth.UserName,
|
||||||
})
|
})
|
||||||
|
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
// Not Found
|
// Not Found
|
||||||
c.JSON(http.StatusOK, gin.H{})
|
koJSON(c, http.StatusOK, gin.H{})
|
||||||
return
|
return
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
log.Error("GetDocumentProgress DB Error:", err)
|
log.Error("GetDocumentProgress DB Error:", err)
|
||||||
@@ -155,7 +155,7 @@ func (api *API) koGetProgress(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.JSON(http.StatusOK, gin.H{
|
koJSON(c, http.StatusOK, gin.H{
|
||||||
"document": progress.DocumentID,
|
"document": progress.DocumentID,
|
||||||
"percentage": progress.Percentage,
|
"percentage": progress.Percentage,
|
||||||
"progress": progress.Progress,
|
"progress": progress.Progress,
|
||||||
@@ -202,7 +202,7 @@ func (api *API) koAddActivities(c *gin.Context) {
|
|||||||
|
|
||||||
// Upsert Documents
|
// Upsert Documents
|
||||||
for _, doc := range allDocuments {
|
for _, doc := range allDocuments {
|
||||||
if _, err := qtx.UpsertDocument(api.db.Ctx, database.UpsertDocumentParams{
|
if _, err := qtx.UpsertDocument(c, database.UpsertDocumentParams{
|
||||||
ID: doc,
|
ID: doc,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
log.Error("UpsertDocument DB Error:", err)
|
log.Error("UpsertDocument DB Error:", err)
|
||||||
@@ -212,7 +212,7 @@ func (api *API) koAddActivities(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Upsert Device
|
// Upsert Device
|
||||||
if _, err = qtx.UpsertDevice(api.db.Ctx, database.UpsertDeviceParams{
|
if _, err = qtx.UpsertDevice(c, database.UpsertDeviceParams{
|
||||||
ID: rActivity.DeviceID,
|
ID: rActivity.DeviceID,
|
||||||
UserID: auth.UserName,
|
UserID: auth.UserName,
|
||||||
DeviceName: rActivity.Device,
|
DeviceName: rActivity.Device,
|
||||||
@@ -225,7 +225,7 @@ func (api *API) koAddActivities(c *gin.Context) {
|
|||||||
|
|
||||||
// Add All Activity
|
// Add All Activity
|
||||||
for _, item := range rActivity.Activity {
|
for _, item := range rActivity.Activity {
|
||||||
if _, err := qtx.AddActivity(api.db.Ctx, database.AddActivityParams{
|
if _, err := qtx.AddActivity(c, database.AddActivityParams{
|
||||||
UserID: auth.UserName,
|
UserID: auth.UserName,
|
||||||
DocumentID: item.DocumentID,
|
DocumentID: item.DocumentID,
|
||||||
DeviceID: rActivity.DeviceID,
|
DeviceID: rActivity.DeviceID,
|
||||||
@@ -247,7 +247,7 @@ func (api *API) koAddActivities(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.JSON(http.StatusOK, gin.H{
|
koJSON(c, http.StatusOK, gin.H{
|
||||||
"added": len(rActivity.Activity),
|
"added": len(rActivity.Activity),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -266,7 +266,7 @@ func (api *API) koCheckActivitySync(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Upsert Device
|
// Upsert Device
|
||||||
if _, err := api.db.Queries.UpsertDevice(api.db.Ctx, database.UpsertDeviceParams{
|
if _, err := api.db.Queries.UpsertDevice(c, database.UpsertDeviceParams{
|
||||||
ID: rCheckActivity.DeviceID,
|
ID: rCheckActivity.DeviceID,
|
||||||
UserID: auth.UserName,
|
UserID: auth.UserName,
|
||||||
DeviceName: rCheckActivity.Device,
|
DeviceName: rCheckActivity.Device,
|
||||||
@@ -278,7 +278,7 @@ func (api *API) koCheckActivitySync(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get Last Device Activity
|
// Get Last Device Activity
|
||||||
lastActivity, err := api.db.Queries.GetLastActivity(api.db.Ctx, database.GetLastActivityParams{
|
lastActivity, err := api.db.Queries.GetLastActivity(c, database.GetLastActivityParams{
|
||||||
UserID: auth.UserName,
|
UserID: auth.UserName,
|
||||||
DeviceID: rCheckActivity.DeviceID,
|
DeviceID: rCheckActivity.DeviceID,
|
||||||
})
|
})
|
||||||
@@ -298,7 +298,7 @@ func (api *API) koCheckActivitySync(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.JSON(http.StatusOK, gin.H{
|
koJSON(c, http.StatusOK, gin.H{
|
||||||
"last_sync": parsedTime.Unix(),
|
"last_sync": parsedTime.Unix(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -329,7 +329,7 @@ func (api *API) koAddDocuments(c *gin.Context) {
|
|||||||
|
|
||||||
// Upsert Documents
|
// Upsert Documents
|
||||||
for _, doc := range rNewDocs.Documents {
|
for _, doc := range rNewDocs.Documents {
|
||||||
_, err := qtx.UpsertDocument(api.db.Ctx, database.UpsertDocumentParams{
|
_, err := qtx.UpsertDocument(c, database.UpsertDocumentParams{
|
||||||
ID: doc.ID,
|
ID: doc.ID,
|
||||||
Title: api.sanitizeInput(doc.Title),
|
Title: api.sanitizeInput(doc.Title),
|
||||||
Author: api.sanitizeInput(doc.Author),
|
Author: api.sanitizeInput(doc.Author),
|
||||||
@@ -352,7 +352,7 @@ func (api *API) koAddDocuments(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.JSON(http.StatusOK, gin.H{
|
koJSON(c, http.StatusOK, gin.H{
|
||||||
"changed": len(rNewDocs.Documents),
|
"changed": len(rNewDocs.Documents),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -371,7 +371,7 @@ func (api *API) koCheckDocumentsSync(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Upsert Device
|
// Upsert Device
|
||||||
_, err := api.db.Queries.UpsertDevice(api.db.Ctx, database.UpsertDeviceParams{
|
_, err := api.db.Queries.UpsertDevice(c, database.UpsertDeviceParams{
|
||||||
ID: rCheckDocs.DeviceID,
|
ID: rCheckDocs.DeviceID,
|
||||||
UserID: auth.UserName,
|
UserID: auth.UserName,
|
||||||
DeviceName: rCheckDocs.Device,
|
DeviceName: rCheckDocs.Device,
|
||||||
@@ -384,7 +384,7 @@ func (api *API) koCheckDocumentsSync(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get Missing Documents
|
// Get Missing Documents
|
||||||
missingDocs, err := api.db.Queries.GetMissingDocuments(api.db.Ctx, rCheckDocs.Have)
|
missingDocs, err := api.db.Queries.GetMissingDocuments(c, rCheckDocs.Have)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("GetMissingDocuments DB Error", err)
|
log.Error("GetMissingDocuments DB Error", err)
|
||||||
apiErrorPage(c, http.StatusBadRequest, "Invalid Request")
|
apiErrorPage(c, http.StatusBadRequest, "Invalid Request")
|
||||||
@@ -392,7 +392,7 @@ func (api *API) koCheckDocumentsSync(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get Deleted Documents
|
// Get Deleted Documents
|
||||||
deletedDocIDs, err := api.db.Queries.GetDeletedDocuments(api.db.Ctx, rCheckDocs.Have)
|
deletedDocIDs, err := api.db.Queries.GetDeletedDocuments(c, rCheckDocs.Have)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("GetDeletedDocuments DB Error", err)
|
log.Error("GetDeletedDocuments DB Error", err)
|
||||||
apiErrorPage(c, http.StatusBadRequest, "Invalid Request")
|
apiErrorPage(c, http.StatusBadRequest, "Invalid Request")
|
||||||
@@ -407,7 +407,7 @@ func (api *API) koCheckDocumentsSync(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
wantedDocs, err := api.db.Queries.GetWantedDocuments(api.db.Ctx, string(jsonHaves))
|
wantedDocs, err := api.db.Queries.GetWantedDocuments(c, string(jsonHaves))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("GetWantedDocuments DB Error", err)
|
log.Error("GetWantedDocuments DB Error", err)
|
||||||
apiErrorPage(c, http.StatusBadRequest, "Invalid Request")
|
apiErrorPage(c, http.StatusBadRequest, "Invalid Request")
|
||||||
@@ -447,7 +447,7 @@ func (api *API) koCheckDocumentsSync(c *gin.Context) {
|
|||||||
rCheckDocSync.Delete = deletedDocIDs
|
rCheckDocSync.Delete = deletedDocIDs
|
||||||
}
|
}
|
||||||
|
|
||||||
c.JSON(http.StatusOK, rCheckDocSync)
|
koJSON(c, http.StatusOK, rCheckDocSync)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *API) koUploadExistingDocument(c *gin.Context) {
|
func (api *API) koUploadExistingDocument(c *gin.Context) {
|
||||||
@@ -467,7 +467,7 @@ func (api *API) koUploadExistingDocument(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Validate Document Exists in DB
|
// Validate Document Exists in DB
|
||||||
document, err := api.db.Queries.GetDocument(api.db.Ctx, rDoc.DocumentID)
|
document, err := api.db.Queries.GetDocument(c, rDoc.DocumentID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("GetDocument DB Error:", err)
|
log.Error("GetDocument DB Error:", err)
|
||||||
apiErrorPage(c, http.StatusBadRequest, "Unknown Document")
|
apiErrorPage(c, http.StatusBadRequest, "Unknown Document")
|
||||||
@@ -522,7 +522,7 @@ func (api *API) koUploadExistingDocument(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Upsert Document
|
// Upsert Document
|
||||||
if _, err = api.db.Queries.UpsertDocument(api.db.Ctx, database.UpsertDocumentParams{
|
if _, err = api.db.Queries.UpsertDocument(c, database.UpsertDocumentParams{
|
||||||
ID: document.ID,
|
ID: document.ID,
|
||||||
Md5: metadataInfo.MD5,
|
Md5: metadataInfo.MD5,
|
||||||
Words: metadataInfo.WordCount,
|
Words: metadataInfo.WordCount,
|
||||||
@@ -534,7 +534,7 @@ func (api *API) koUploadExistingDocument(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.JSON(http.StatusOK, gin.H{
|
koJSON(c, http.StatusOK, gin.H{
|
||||||
"status": "ok",
|
"status": "ok",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -589,3 +589,10 @@ func getFileMD5(filePath string) (*string, error) {
|
|||||||
|
|
||||||
return &fileHash, nil
|
return &fileHash, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// koJSON forces koJSON Content-Type to only return `application/json`. This is addressing
|
||||||
|
// the following issue: https://github.com/koreader/koreader/issues/13629
|
||||||
|
func koJSON(c *gin.Context, code int, obj any) {
|
||||||
|
c.Header("Content-Type", "application/json")
|
||||||
|
c.JSON(code, obj)
|
||||||
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"reichard.io/antholume/database"
|
"reichard.io/antholume/database"
|
||||||
"reichard.io/antholume/opds"
|
"reichard.io/antholume/opds"
|
||||||
|
"reichard.io/antholume/pkg/ptr"
|
||||||
)
|
)
|
||||||
|
|
||||||
var mimeMapping map[string]string = map[string]string{
|
var mimeMapping map[string]string = map[string]string{
|
||||||
@@ -77,11 +78,12 @@ func (api *API) opdsDocuments(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get Documents
|
// Get Documents
|
||||||
documents, err := api.db.Queries.GetDocumentsWithStats(api.db.Ctx, database.GetDocumentsWithStatsParams{
|
documents, err := api.db.Queries.GetDocumentsWithStats(c, database.GetDocumentsWithStatsParams{
|
||||||
UserID: auth.UserName,
|
UserID: auth.UserName,
|
||||||
Query: query,
|
Query: query,
|
||||||
Offset: (*qParams.Page - 1) * *qParams.Limit,
|
Deleted: ptr.Of(false),
|
||||||
Limit: *qParams.Limit,
|
Offset: (*qParams.Page - 1) * *qParams.Limit,
|
||||||
|
Limit: *qParams.Limit,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("GetDocumentsWithStats DB Error:", err)
|
log.Error("GetDocumentsWithStats DB Error:", err)
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ func getTimeZones() []string {
|
|||||||
|
|
||||||
// niceSeconds takes in an int (in seconds) and returns a string readable
|
// niceSeconds takes in an int (in seconds) and returns a string readable
|
||||||
// representation. For example 1928371 -> "22d 7h 39m 31s".
|
// representation. For example 1928371 -> "22d 7h 39m 31s".
|
||||||
|
// Deprecated: Use formatters.FormatDuration
|
||||||
func niceSeconds(input int64) (result string) {
|
func niceSeconds(input int64) (result string) {
|
||||||
if input == 0 {
|
if input == 0 {
|
||||||
return "N/A"
|
return "N/A"
|
||||||
@@ -85,6 +86,7 @@ func niceSeconds(input int64) (result string) {
|
|||||||
|
|
||||||
// niceNumbers takes in an int and returns a string representation. For example
|
// niceNumbers takes in an int and returns a string representation. For example
|
||||||
// 19823 -> "19.8k".
|
// 19823 -> "19.8k".
|
||||||
|
// Deprecated: Use formatters.FormatNumber
|
||||||
func niceNumbers(input int64) string {
|
func niceNumbers(input int64) string {
|
||||||
if input == 0 {
|
if input == 0 {
|
||||||
return "0"
|
return "0"
|
||||||
|
|||||||
@@ -82,13 +82,30 @@
|
|||||||
id="top-bar"
|
id="top-bar"
|
||||||
class="transition-all duration-200 absolute z-10 bg-gray-100 dark:bg-gray-800 w-full px-2"
|
class="transition-all duration-200 absolute z-10 bg-gray-100 dark:bg-gray-800 w-full px-2"
|
||||||
>
|
>
|
||||||
<div class="w-full h-32 flex items-center justify-around relative">
|
<div class="max-h-[75vh] w-full flex flex-col items-center justify-around relative dark:text-white">
|
||||||
<div class="text-gray-500 absolute top-6 left-4 flex flex-col gap-4">
|
<div class="h-32">
|
||||||
<a href="#">
|
<div class="text-gray-500 absolute top-6 left-4 flex flex-col gap-4">
|
||||||
|
<a href="#">
|
||||||
|
<svg
|
||||||
|
width="32"
|
||||||
|
height="32"
|
||||||
|
class="cursor-pointer hover:text-gray-800 dark:hover:text-gray-100"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="currentColor"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
d="M20.5355 3.46447C19.0711 2 16.714 2 12 2C7.28595 2 4.92893 2 3.46447 3.46447C2 4.92893 2 7.28595 2 12C2 16.714 2 19.0711 3.46447 20.5355C4.92893 22 7.28595 22 12 22C16.714 22 19.0711 22 20.5355 20.5355C22 19.0711 22 16.714 22 12C22 7.28595 22 4.92893 20.5355 3.46447ZM14.0303 8.46967C14.3232 8.76256 14.3232 9.23744 14.0303 9.53033L11.5607 12L14.0303 14.4697C14.3232 14.7626 14.3232 15.2374 14.0303 15.5303C13.7374 15.8232 13.2626 15.8232 12.9697 15.5303L9.96967 12.5303C9.82902 12.3897 9.75 12.1989 9.75 12C9.75 11.8011 9.82902 11.6103 9.96967 11.4697L12.9697 8.46967C13.2626 8.17678 13.7374 8.17678 14.0303 8.46967Z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
|
||||||
<svg
|
<svg
|
||||||
width="32"
|
width="32"
|
||||||
height="32"
|
height="32"
|
||||||
class="cursor-pointer hover:text-gray-800 dark:hover:text-gray-100"
|
class="cursor-pointer hover:text-gray-800 dark:hover:text-gray-100 close-top-bar"
|
||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
fill="currentColor"
|
fill="currentColor"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
@@ -96,61 +113,47 @@
|
|||||||
<path
|
<path
|
||||||
fill-rule="evenodd"
|
fill-rule="evenodd"
|
||||||
clip-rule="evenodd"
|
clip-rule="evenodd"
|
||||||
d="M20.5355 3.46447C19.0711 2 16.714 2 12 2C7.28595 2 4.92893 2 3.46447 3.46447C2 4.92893 2 7.28595 2 12C2 16.714 2 19.0711 3.46447 20.5355C4.92893 22 7.28595 22 12 22C16.714 22 19.0711 22 20.5355 20.5355C22 19.0711 22 16.714 22 12C22 7.28595 22 4.92893 20.5355 3.46447ZM14.0303 8.46967C14.3232 8.76256 14.3232 9.23744 14.0303 9.53033L11.5607 12L14.0303 14.4697C14.3232 14.7626 14.3232 15.2374 14.0303 15.5303C13.7374 15.8232 13.2626 15.8232 12.9697 15.5303L9.96967 12.5303C9.82902 12.3897 9.75 12.1989 9.75 12C9.75 11.8011 9.82902 11.6103 9.96967 11.4697L12.9697 8.46967C13.2626 8.17678 13.7374 8.17678 14.0303 8.46967Z"
|
d="M12 22C7.28595 22 4.92893 22 3.46447 20.5355C2 19.0711 2 16.714 2 12C2 7.28595 2 4.92893 3.46447 3.46447C4.92893 2 7.28595 2 12 2C16.714 2 19.0711 2 20.5355 3.46447C22 4.92893 22 7.28595 22 12C22 16.714 22 19.0711 20.5355 20.5355C19.0711 22 16.714 22 12 22ZM8.96965 8.96967C9.26254 8.67678 9.73742 8.67678 10.0303 8.96967L12 10.9394L13.9696 8.96969C14.2625 8.6768 14.7374 8.6768 15.0303 8.96969C15.3232 9.26258 15.3232 9.73746 15.0303 10.0303L13.0606 12L15.0303 13.9697C15.3232 14.2625 15.3232 14.7374 15.0303 15.0303C14.7374 15.3232 14.2625 15.3232 13.9696 15.0303L12 13.0607L10.0303 15.0303C9.73744 15.3232 9.26256 15.3232 8.96967 15.0303C8.67678 14.7374 8.67678 14.2626 8.96967 13.9697L10.9393 12L8.96965 10.0303C8.67676 9.73744 8.67676 9.26256 8.96965 8.96967Z"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</a>
|
|
||||||
|
|
||||||
<svg
|
|
||||||
width="32"
|
|
||||||
height="32"
|
|
||||||
class="cursor-pointer hover:text-gray-800 dark:hover:text-gray-100 close-top-bar"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
fill="currentColor"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
fill-rule="evenodd"
|
|
||||||
clip-rule="evenodd"
|
|
||||||
d="M12 22C7.28595 22 4.92893 22 3.46447 20.5355C2 19.0711 2 16.714 2 12C2 7.28595 2 4.92893 3.46447 3.46447C4.92893 2 7.28595 2 12 2C16.714 2 19.0711 2 20.5355 3.46447C22 4.92893 22 7.28595 22 12C22 16.714 22 19.0711 20.5355 20.5355C19.0711 22 16.714 22 12 22ZM8.96965 8.96967C9.26254 8.67678 9.73742 8.67678 10.0303 8.96967L12 10.9394L13.9696 8.96969C14.2625 8.6768 14.7374 8.6768 15.0303 8.96969C15.3232 9.26258 15.3232 9.73746 15.0303 10.0303L13.0606 12L15.0303 13.9697C15.3232 14.2625 15.3232 14.7374 15.0303 15.0303C14.7374 15.3232 14.2625 15.3232 13.9696 15.0303L12 13.0607L10.0303 15.0303C9.73744 15.3232 9.26256 15.3232 8.96967 15.0303C8.67678 14.7374 8.67678 14.2626 8.96967 13.9697L10.9393 12L8.96965 10.0303C8.67676 9.73744 8.67676 9.26256 8.96965 8.96967Z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex gap-10 h-full p-4 pl-14 rounded">
|
|
||||||
<div class="h-full my-auto relative">
|
|
||||||
<a href="#">
|
|
||||||
<img
|
|
||||||
class="rounded object-cover h-full"
|
|
||||||
src="/assets/images/no-cover.jpg"
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="flex gap-7 justify-around dark:text-white text-sm">
|
|
||||||
<div class="flex flex-col gap-4">
|
<div class="flex gap-10 h-full p-4 pl-14 rounded">
|
||||||
<div class="inline-flex shrink-0 items-center">
|
<div class="h-full my-auto relative">
|
||||||
<div>
|
<a href="#">
|
||||||
<p class="text-gray-400">Title</p>
|
<img
|
||||||
<p
|
class="rounded object-cover h-full"
|
||||||
class="font-medium whitespace-nowrap text-ellipsis overflow-hidden max-w-[50dvw]"
|
src="/assets/images/no-cover.jpg"
|
||||||
>
|
/>
|
||||||
"N/A"
|
</a>
|
||||||
</p>
|
</div>
|
||||||
|
<div class="flex gap-7 justify-around dark:text-white text-sm">
|
||||||
|
<div class="flex flex-col gap-4">
|
||||||
|
<div class="inline-flex shrink-0 items-center">
|
||||||
|
<div>
|
||||||
|
<p class="text-gray-400">Title</p>
|
||||||
|
<p
|
||||||
|
class="font-medium whitespace-nowrap text-ellipsis overflow-hidden max-w-[50dvw]"
|
||||||
|
>
|
||||||
|
"N/A"
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="inline-flex shrink-0 items-center">
|
||||||
<div class="inline-flex shrink-0 items-center">
|
<div>
|
||||||
<div>
|
<p class="text-gray-400">Author</p>
|
||||||
<p class="text-gray-400">Author</p>
|
<p
|
||||||
<p
|
class="font-medium whitespace-nowrap text-ellipsis overflow-hidden max-w-[50dvw]"
|
||||||
class="font-medium whitespace-nowrap text-ellipsis overflow-hidden max-w-[50dvw]"
|
>
|
||||||
>
|
"N/A"
|
||||||
"N/A"
|
</p>
|
||||||
</p>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="toc" class="w-full text-center max-h-[50%] overflow-scroll no-scrollbar"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -66,6 +66,56 @@ function populateMetadata(data) {
|
|||||||
authorEl.innerText = data.author;
|
authorEl.innerText = data.author;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Populate the Table of Contents
|
||||||
|
**/
|
||||||
|
function populateTOC() {
|
||||||
|
if (!currentReader.book.navigation.toc) {
|
||||||
|
console.warn("[populateTOC] No TOC");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let tocEl = document.querySelector("#toc");
|
||||||
|
if (!tocEl) {
|
||||||
|
console.warn("[populateTOC] No TOC Element");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the Table of Contents
|
||||||
|
let parsedTOC = currentReader.book.navigation.toc.reduce((agg, item) => {
|
||||||
|
let sectionTitle = item.label.trim();
|
||||||
|
agg.push({ title: sectionTitle, href: item.href });
|
||||||
|
if (item.subitems.length == 0) {
|
||||||
|
return agg;
|
||||||
|
}
|
||||||
|
|
||||||
|
let allSubSections = item.subitems.map(item => {
|
||||||
|
let itemTitle = item.label.trim();
|
||||||
|
if (sectionTitle != "") {
|
||||||
|
itemTitle = sectionTitle + " - " + item.label.trim();
|
||||||
|
}
|
||||||
|
return { title: itemTitle, href: item.href };
|
||||||
|
});
|
||||||
|
agg.push(...allSubSections);
|
||||||
|
|
||||||
|
return agg;
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
// Add Table of Contents to DOM
|
||||||
|
let listEl = document.createElement("ul");
|
||||||
|
listEl.classList.add("m-4")
|
||||||
|
parsedTOC.forEach(item => {
|
||||||
|
let listItem = document.createElement("li");
|
||||||
|
listItem.style.cursor = "pointer";
|
||||||
|
listItem.addEventListener("click", () => {
|
||||||
|
currentReader.rendition.display(item.href);
|
||||||
|
});
|
||||||
|
listItem.textContent = item.title;
|
||||||
|
listEl.appendChild(listItem);
|
||||||
|
});
|
||||||
|
tocEl.appendChild(listEl);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the main reader class. All functionality is wrapped in this class.
|
* This is the main reader class. All functionality is wrapped in this class.
|
||||||
* Responsible for handling gesture / clicks, flushing progress & activity,
|
* Responsible for handling gesture / clicks, flushing progress & activity,
|
||||||
@@ -439,6 +489,7 @@ class EBookReader {
|
|||||||
// ------------------------------------------------ //
|
// ------------------------------------------------ //
|
||||||
// ----------------- Swipe Helpers ---------------- //
|
// ----------------- Swipe Helpers ---------------- //
|
||||||
// ------------------------------------------------ //
|
// ------------------------------------------------ //
|
||||||
|
let disablePagination = false;
|
||||||
let touchStartX,
|
let touchStartX,
|
||||||
touchStartY,
|
touchStartY,
|
||||||
touchEndX,
|
touchEndX,
|
||||||
@@ -459,25 +510,38 @@ class EBookReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Swipe Left
|
// Swipe Left
|
||||||
if (touchEndX + drasticity < touchStartX) {
|
if (!disablePagination && touchEndX + drasticity < touchStartX) {
|
||||||
nextPage();
|
nextPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Swipe Right
|
// Swipe Right
|
||||||
if (touchEndX - drasticity > touchStartX) {
|
if (!disablePagination && touchEndX - drasticity > touchStartX) {
|
||||||
prevPage();
|
prevPage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleSwipeDown() {
|
function handleSwipeDown() {
|
||||||
if (bottomBar.classList.contains("bottom-0"))
|
if (bottomBar.classList.contains("bottom-0")) {
|
||||||
bottomBar.classList.remove("bottom-0");
|
bottomBar.classList.remove("bottom-0");
|
||||||
else topBar.classList.add("top-0");
|
disablePagination = false;
|
||||||
|
} else {
|
||||||
|
topBar.classList.add("top-0");
|
||||||
|
populateTOC()
|
||||||
|
disablePagination = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleSwipeUp() {
|
function handleSwipeUp() {
|
||||||
if (topBar.classList.contains("top-0")) topBar.classList.remove("top-0");
|
if (topBar.classList.contains("top-0")) {
|
||||||
else bottomBar.classList.add("bottom-0");
|
topBar.classList.remove("top-0");
|
||||||
|
disablePagination = false;
|
||||||
|
|
||||||
|
const tocEl = document.querySelector("#toc");
|
||||||
|
if (tocEl) tocEl.innerHTML = "";
|
||||||
|
} else {
|
||||||
|
bottomBar.classList.add("bottom-0");
|
||||||
|
disablePagination = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.rendition.hooks.render.register(function (doc, data) {
|
this.rendition.hooks.render.register(function (doc, data) {
|
||||||
@@ -523,8 +587,8 @@ class EBookReader {
|
|||||||
// Handle Event
|
// Handle Event
|
||||||
if (yCoord < top) handleSwipeDown();
|
if (yCoord < top) handleSwipeDown();
|
||||||
else if (yCoord > bottom) handleSwipeUp();
|
else if (yCoord > bottom) handleSwipeUp();
|
||||||
else if (xCoord < left) prevPage();
|
else if (!disablePagination && xCoord < left) prevPage();
|
||||||
else if (xCoord > right) nextPage();
|
else if (!disablePagination && xCoord > right) nextPage();
|
||||||
else {
|
else {
|
||||||
bottomBar.classList.remove("bottom-0");
|
bottomBar.classList.remove("bottom-0");
|
||||||
topBar.classList.remove("top-0");
|
topBar.classList.remove("top-0");
|
||||||
@@ -670,6 +734,9 @@ class EBookReader {
|
|||||||
// Close Top Bar
|
// Close Top Bar
|
||||||
document.querySelector(".close-top-bar").addEventListener("click", () => {
|
document.querySelector(".close-top-bar").addEventListener("click", () => {
|
||||||
topBar.classList.remove("top-0");
|
topBar.classList.remove("top-0");
|
||||||
|
|
||||||
|
const tocEl = document.querySelector("#toc");
|
||||||
|
if (tocEl) tocEl.innerHTML = "";
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -949,10 +1016,16 @@ class EBookReader {
|
|||||||
**/
|
**/
|
||||||
async getXPathFromCFI(cfi) {
|
async getXPathFromCFI(cfi) {
|
||||||
// Get DocFragment (Spine Index)
|
// Get DocFragment (Spine Index)
|
||||||
let startCFI = cfi.replace("epubcfi(", "");
|
let cfiBaseMatch = cfi.match(/\(([^!]+)/);
|
||||||
|
if (!cfiBaseMatch) {
|
||||||
|
console.error("[getXPathFromCFI] No CFI Match");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
let startCFI = cfiBaseMatch[1];
|
||||||
|
|
||||||
let docFragmentIndex =
|
let docFragmentIndex =
|
||||||
this.book.spine.spineItems.find((item) =>
|
this.book.spine.spineItems.find((item) =>
|
||||||
startCFI.startsWith(item.cfiBase),
|
item.cfiBase == startCFI
|
||||||
).index + 1;
|
).index + 1;
|
||||||
|
|
||||||
// Base Progress
|
// Base Progress
|
||||||
@@ -1029,10 +1102,6 @@ class EBookReader {
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Match Item Index
|
|
||||||
let indexMatch = xpath.match(/\.(\d+)$/);
|
|
||||||
let itemIndex = indexMatch ? parseInt(indexMatch[1]) : 0;
|
|
||||||
|
|
||||||
// Get Spine Item
|
// Get Spine Item
|
||||||
let spinePosition = parseInt(fragMatch[1]) - 1;
|
let spinePosition = parseInt(fragMatch[1]) - 1;
|
||||||
let sectionItem = this.book.spine.get(spinePosition);
|
let sectionItem = this.book.spine.get(spinePosition);
|
||||||
@@ -1124,6 +1193,11 @@ class EBookReader {
|
|||||||
let element = docSearch.iterateNext() || derivedSelectorElement;
|
let element = docSearch.iterateNext() || derivedSelectorElement;
|
||||||
let cfi = sectionItem.cfiFromElement(element);
|
let cfi = sectionItem.cfiFromElement(element);
|
||||||
|
|
||||||
|
// Hack - epub.js crashes sometimes when its a bare section with no element
|
||||||
|
// so just return the first.
|
||||||
|
if (cfi.endsWith("!/)"))
|
||||||
|
cfi = cfi.slice(0, -1) + "0)"
|
||||||
|
|
||||||
return { cfi, element };
|
return { cfi, element };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1271,14 +1345,3 @@ class EBookReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", initReader);
|
document.addEventListener("DOMContentLoaded", initReader);
|
||||||
|
|
||||||
// WIP
|
|
||||||
async function getTOC() {
|
|
||||||
let toc = currentReader.book.navigation.toc;
|
|
||||||
|
|
||||||
// Alternatively:
|
|
||||||
// let nav = await currentReader.book.loaded.navigation;
|
|
||||||
// let toc = nav.toc;
|
|
||||||
|
|
||||||
currentReader.rendition.display(nav.toc[10].href);
|
|
||||||
}
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -1,6 +1,6 @@
|
|||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.27.0
|
// sqlc v1.29.0
|
||||||
|
|
||||||
package database
|
package database
|
||||||
|
|
||||||
|
|||||||
27
database/documents.go
Normal file
27
database/documents.go
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
package database
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"reichard.io/antholume/pkg/ptr"
|
||||||
|
"reichard.io/antholume/pkg/sliceutils"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (d *DBManager) GetDocument(ctx context.Context, docID, userID string) (*GetDocumentsWithStatsRow, error) {
|
||||||
|
documents, err := d.Queries.GetDocumentsWithStats(ctx, GetDocumentsWithStatsParams{
|
||||||
|
ID: ptr.Of(docID),
|
||||||
|
UserID: userID,
|
||||||
|
Limit: 1,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
document, found := sliceutils.First(documents)
|
||||||
|
if !found {
|
||||||
|
return nil, fmt.Errorf("document not found: %s", docID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &document, nil
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package database
|
package database
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@@ -26,7 +27,7 @@ func (suite *DocumentsTestSuite) SetupTest() {
|
|||||||
suite.dbm = NewMgr(&cfg)
|
suite.dbm = NewMgr(&cfg)
|
||||||
|
|
||||||
// Create Document
|
// Create Document
|
||||||
_, err := suite.dbm.Queries.UpsertDocument(suite.dbm.Ctx, UpsertDocumentParams{
|
_, err := suite.dbm.Queries.UpsertDocument(context.Background(), UpsertDocumentParams{
|
||||||
ID: documentID,
|
ID: documentID,
|
||||||
Title: &documentTitle,
|
Title: &documentTitle,
|
||||||
Author: &documentAuthor,
|
Author: &documentAuthor,
|
||||||
@@ -42,7 +43,7 @@ func (suite *DocumentsTestSuite) SetupTest() {
|
|||||||
// - (q *Queries) GetDocumentsWithStats
|
// - (q *Queries) GetDocumentsWithStats
|
||||||
// - (q *Queries) GetMissingDocuments
|
// - (q *Queries) GetMissingDocuments
|
||||||
func (suite *DocumentsTestSuite) TestGetDocument() {
|
func (suite *DocumentsTestSuite) TestGetDocument() {
|
||||||
doc, err := suite.dbm.Queries.GetDocument(suite.dbm.Ctx, documentID)
|
doc, err := suite.dbm.Queries.GetDocument(context.Background(), documentID)
|
||||||
suite.Nil(err, "should have nil err")
|
suite.Nil(err, "should have nil err")
|
||||||
suite.Equal(documentID, doc.ID, "should have changed the document")
|
suite.Equal(documentID, doc.ID, "should have changed the document")
|
||||||
}
|
}
|
||||||
@@ -50,7 +51,7 @@ func (suite *DocumentsTestSuite) TestGetDocument() {
|
|||||||
func (suite *DocumentsTestSuite) TestUpsertDocument() {
|
func (suite *DocumentsTestSuite) TestUpsertDocument() {
|
||||||
testDocID := "docid1"
|
testDocID := "docid1"
|
||||||
|
|
||||||
doc, err := suite.dbm.Queries.UpsertDocument(suite.dbm.Ctx, UpsertDocumentParams{
|
doc, err := suite.dbm.Queries.UpsertDocument(context.Background(), UpsertDocumentParams{
|
||||||
ID: testDocID,
|
ID: testDocID,
|
||||||
Title: &documentTitle,
|
Title: &documentTitle,
|
||||||
Author: &documentAuthor,
|
Author: &documentAuthor,
|
||||||
@@ -63,51 +64,51 @@ func (suite *DocumentsTestSuite) TestUpsertDocument() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (suite *DocumentsTestSuite) TestDeleteDocument() {
|
func (suite *DocumentsTestSuite) TestDeleteDocument() {
|
||||||
changed, err := suite.dbm.Queries.DeleteDocument(suite.dbm.Ctx, documentID)
|
changed, err := suite.dbm.Queries.DeleteDocument(context.Background(), documentID)
|
||||||
suite.Nil(err, "should have nil err")
|
suite.Nil(err, "should have nil err")
|
||||||
suite.Equal(int64(1), changed, "should have changed the document")
|
suite.Equal(int64(1), changed, "should have changed the document")
|
||||||
|
|
||||||
doc, err := suite.dbm.Queries.GetDocument(suite.dbm.Ctx, documentID)
|
doc, err := suite.dbm.Queries.GetDocument(context.Background(), documentID)
|
||||||
suite.Nil(err, "should have nil err")
|
suite.Nil(err, "should have nil err")
|
||||||
suite.True(doc.Deleted, "should have deleted the document")
|
suite.True(doc.Deleted, "should have deleted the document")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *DocumentsTestSuite) TestGetDeletedDocuments() {
|
func (suite *DocumentsTestSuite) TestGetDeletedDocuments() {
|
||||||
changed, err := suite.dbm.Queries.DeleteDocument(suite.dbm.Ctx, documentID)
|
changed, err := suite.dbm.Queries.DeleteDocument(context.Background(), documentID)
|
||||||
suite.Nil(err, "should have nil err")
|
suite.Nil(err, "should have nil err")
|
||||||
suite.Equal(int64(1), changed, "should have changed the document")
|
suite.Equal(int64(1), changed, "should have changed the document")
|
||||||
|
|
||||||
deletedDocs, err := suite.dbm.Queries.GetDeletedDocuments(suite.dbm.Ctx, []string{documentID})
|
deletedDocs, err := suite.dbm.Queries.GetDeletedDocuments(context.Background(), []string{documentID})
|
||||||
suite.Nil(err, "should have nil err")
|
suite.Nil(err, "should have nil err")
|
||||||
suite.Len(deletedDocs, 1, "should have one deleted document")
|
suite.Len(deletedDocs, 1, "should have one deleted document")
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO - Convert GetWantedDocuments -> (sqlc.slice('document_ids'));
|
// TODO - Convert GetWantedDocuments -> (sqlc.slice('document_ids'));
|
||||||
func (suite *DocumentsTestSuite) TestGetWantedDocuments() {
|
func (suite *DocumentsTestSuite) TestGetWantedDocuments() {
|
||||||
wantedDocs, err := suite.dbm.Queries.GetWantedDocuments(suite.dbm.Ctx, fmt.Sprintf("[\"%s\"]", documentID))
|
wantedDocs, err := suite.dbm.Queries.GetWantedDocuments(context.Background(), fmt.Sprintf("[\"%s\"]", documentID))
|
||||||
suite.Nil(err, "should have nil err")
|
suite.Nil(err, "should have nil err")
|
||||||
suite.Len(wantedDocs, 1, "should have one wanted document")
|
suite.Len(wantedDocs, 1, "should have one wanted document")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *DocumentsTestSuite) TestGetMissingDocuments() {
|
func (suite *DocumentsTestSuite) TestGetMissingDocuments() {
|
||||||
// Create Document
|
// Create Document
|
||||||
_, err := suite.dbm.Queries.UpsertDocument(suite.dbm.Ctx, UpsertDocumentParams{
|
_, err := suite.dbm.Queries.UpsertDocument(context.Background(), UpsertDocumentParams{
|
||||||
ID: documentID,
|
ID: documentID,
|
||||||
Filepath: &documentFilepath,
|
Filepath: &documentFilepath,
|
||||||
})
|
})
|
||||||
suite.NoError(err)
|
suite.NoError(err)
|
||||||
|
|
||||||
missingDocs, err := suite.dbm.Queries.GetMissingDocuments(suite.dbm.Ctx, []string{documentID})
|
missingDocs, err := suite.dbm.Queries.GetMissingDocuments(context.Background(), []string{documentID})
|
||||||
suite.Nil(err, "should have nil err")
|
suite.Nil(err, "should have nil err")
|
||||||
suite.Len(missingDocs, 0, "should have no wanted document")
|
suite.Len(missingDocs, 0, "should have no wanted document")
|
||||||
|
|
||||||
missingDocs, err = suite.dbm.Queries.GetMissingDocuments(suite.dbm.Ctx, []string{"other"})
|
missingDocs, err = suite.dbm.Queries.GetMissingDocuments(context.Background(), []string{"other"})
|
||||||
suite.Nil(err, "should have nil err")
|
suite.Nil(err, "should have nil err")
|
||||||
suite.Len(missingDocs, 1, "should have one missing document")
|
suite.Len(missingDocs, 1, "should have one missing document")
|
||||||
suite.Equal(documentID, missingDocs[0].ID, "should have missing doc")
|
suite.Equal(documentID, missingDocs[0].ID, "should have missing doc")
|
||||||
|
|
||||||
// TODO - https://github.com/sqlc-dev/sqlc/issues/3451
|
// TODO - https://github.com/sqlc-dev/sqlc/issues/3451
|
||||||
// missingDocs, err = suite.dbm.Queries.GetMissingDocuments(suite.dbm.Ctx, []string{})
|
// missingDocs, err = suite.dbm.Queries.GetMissingDocuments(context.Background(), []string{})
|
||||||
// suite.Nil(err, "should have nil err")
|
// suite.Nil(err, "should have nil err")
|
||||||
// suite.Len(missingDocs, 1, "should have one missing document")
|
// suite.Len(missingDocs, 1, "should have one missing document")
|
||||||
// suite.Equal(documentID, missingDocs[0].ID, "should have missing doc")
|
// suite.Equal(documentID, missingDocs[0].ID, "should have missing doc")
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import (
|
|||||||
"database/sql"
|
"database/sql"
|
||||||
"database/sql/driver"
|
"database/sql/driver"
|
||||||
"embed"
|
"embed"
|
||||||
_ "embed"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@@ -20,7 +19,6 @@ import (
|
|||||||
|
|
||||||
type DBManager struct {
|
type DBManager struct {
|
||||||
DB *sql.DB
|
DB *sql.DB
|
||||||
Ctx context.Context
|
|
||||||
Queries *Queries
|
Queries *Queries
|
||||||
cfg *config.Config
|
cfg *config.Config
|
||||||
}
|
}
|
||||||
@@ -54,12 +52,9 @@ func init() {
|
|||||||
// NewMgr Returns an initialized manager
|
// NewMgr Returns an initialized manager
|
||||||
func NewMgr(c *config.Config) *DBManager {
|
func NewMgr(c *config.Config) *DBManager {
|
||||||
// Create Manager
|
// Create Manager
|
||||||
dbm := &DBManager{
|
dbm := &DBManager{cfg: c}
|
||||||
Ctx: context.Background(),
|
|
||||||
cfg: c,
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := dbm.init(); err != nil {
|
if err := dbm.init(context.Background()); err != nil {
|
||||||
log.Panic("Unable to init DB")
|
log.Panic("Unable to init DB")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,7 +62,7 @@ func NewMgr(c *config.Config) *DBManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// init loads the DB manager
|
// init loads the DB manager
|
||||||
func (dbm *DBManager) init() error {
|
func (dbm *DBManager) init(ctx context.Context) error {
|
||||||
// Build DB Location
|
// Build DB Location
|
||||||
var dbLocation string
|
var dbLocation string
|
||||||
switch dbm.cfg.DBType {
|
switch dbm.cfg.DBType {
|
||||||
@@ -113,14 +108,14 @@ func (dbm *DBManager) init() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update settings
|
// Update settings
|
||||||
err = dbm.updateSettings()
|
err = dbm.updateSettings(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Panicf("Error running DB settings update: %v", err)
|
log.Panicf("Error running DB settings update: %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cache tables
|
// Cache tables
|
||||||
if err := dbm.CacheTempTables(); err != nil {
|
if err := dbm.CacheTempTables(ctx); err != nil {
|
||||||
log.Warn("Refreshing temp table cache failed: ", err)
|
log.Warn("Refreshing temp table cache failed: ", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,7 +123,7 @@ func (dbm *DBManager) init() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Reload closes the DB & reinits
|
// Reload closes the DB & reinits
|
||||||
func (dbm *DBManager) Reload() error {
|
func (dbm *DBManager) Reload(ctx context.Context) error {
|
||||||
// Close handle
|
// Close handle
|
||||||
err := dbm.DB.Close()
|
err := dbm.DB.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -136,7 +131,7 @@ func (dbm *DBManager) Reload() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Reinit DB
|
// Reinit DB
|
||||||
if err := dbm.init(); err != nil {
|
if err := dbm.init(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,15 +139,15 @@ func (dbm *DBManager) Reload() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CacheTempTables clears existing statistics and recalculates
|
// CacheTempTables clears existing statistics and recalculates
|
||||||
func (dbm *DBManager) CacheTempTables() error {
|
func (dbm *DBManager) CacheTempTables(ctx context.Context) error {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
if _, err := dbm.DB.ExecContext(dbm.Ctx, user_streaks); err != nil {
|
if _, err := dbm.DB.ExecContext(ctx, user_streaks); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
log.Debug("Cached 'user_streaks' in: ", time.Since(start))
|
log.Debug("Cached 'user_streaks' in: ", time.Since(start))
|
||||||
|
|
||||||
start = time.Now()
|
start = time.Now()
|
||||||
if _, err := dbm.DB.ExecContext(dbm.Ctx, document_user_statistics); err != nil {
|
if _, err := dbm.DB.ExecContext(ctx, document_user_statistics); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
log.Debug("Cached 'document_user_statistics' in: ", time.Since(start))
|
log.Debug("Cached 'document_user_statistics' in: ", time.Since(start))
|
||||||
@@ -162,7 +157,7 @@ func (dbm *DBManager) CacheTempTables() error {
|
|||||||
|
|
||||||
// updateSettings ensures that we're enforcing foreign keys and enable journal
|
// updateSettings ensures that we're enforcing foreign keys and enable journal
|
||||||
// mode.
|
// mode.
|
||||||
func (dbm *DBManager) updateSettings() error {
|
func (dbm *DBManager) updateSettings(ctx context.Context) error {
|
||||||
// Set SQLite PRAGMA Settings
|
// Set SQLite PRAGMA Settings
|
||||||
pragmaQuery := `
|
pragmaQuery := `
|
||||||
PRAGMA foreign_keys = ON;
|
PRAGMA foreign_keys = ON;
|
||||||
@@ -174,7 +169,7 @@ func (dbm *DBManager) updateSettings() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update Antholume Version in DB
|
// Update Antholume Version in DB
|
||||||
if _, err := dbm.Queries.UpdateSettings(dbm.Ctx, UpdateSettingsParams{
|
if _, err := dbm.Queries.UpdateSettings(ctx, UpdateSettingsParams{
|
||||||
Name: "version",
|
Name: "version",
|
||||||
Value: dbm.cfg.Version,
|
Value: dbm.cfg.Version,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package database
|
package database
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
@@ -46,7 +47,7 @@ func (suite *DatabaseTestSuite) SetupTest() {
|
|||||||
// Create User
|
// Create User
|
||||||
rawAuthHash, _ := utils.GenerateToken(64)
|
rawAuthHash, _ := utils.GenerateToken(64)
|
||||||
authHash := fmt.Sprintf("%x", rawAuthHash)
|
authHash := fmt.Sprintf("%x", rawAuthHash)
|
||||||
_, err := suite.dbm.Queries.CreateUser(suite.dbm.Ctx, CreateUserParams{
|
_, err := suite.dbm.Queries.CreateUser(context.Background(), CreateUserParams{
|
||||||
ID: userID,
|
ID: userID,
|
||||||
Pass: &userPass,
|
Pass: &userPass,
|
||||||
AuthHash: &authHash,
|
AuthHash: &authHash,
|
||||||
@@ -54,7 +55,7 @@ func (suite *DatabaseTestSuite) SetupTest() {
|
|||||||
suite.NoError(err)
|
suite.NoError(err)
|
||||||
|
|
||||||
// Create Document
|
// Create Document
|
||||||
_, err = suite.dbm.Queries.UpsertDocument(suite.dbm.Ctx, UpsertDocumentParams{
|
_, err = suite.dbm.Queries.UpsertDocument(context.Background(), UpsertDocumentParams{
|
||||||
ID: documentID,
|
ID: documentID,
|
||||||
Title: &documentTitle,
|
Title: &documentTitle,
|
||||||
Author: &documentAuthor,
|
Author: &documentAuthor,
|
||||||
@@ -64,7 +65,7 @@ func (suite *DatabaseTestSuite) SetupTest() {
|
|||||||
suite.NoError(err)
|
suite.NoError(err)
|
||||||
|
|
||||||
// Create Device
|
// Create Device
|
||||||
_, err = suite.dbm.Queries.UpsertDevice(suite.dbm.Ctx, UpsertDeviceParams{
|
_, err = suite.dbm.Queries.UpsertDevice(context.Background(), UpsertDeviceParams{
|
||||||
ID: deviceID,
|
ID: deviceID,
|
||||||
UserID: userID,
|
UserID: userID,
|
||||||
DeviceName: deviceName,
|
DeviceName: deviceName,
|
||||||
@@ -80,7 +81,7 @@ func (suite *DatabaseTestSuite) SetupTest() {
|
|||||||
counter += 1
|
counter += 1
|
||||||
|
|
||||||
// Add Item
|
// Add Item
|
||||||
activity, err := suite.dbm.Queries.AddActivity(suite.dbm.Ctx, AddActivityParams{
|
activity, err := suite.dbm.Queries.AddActivity(context.Background(), AddActivityParams{
|
||||||
DocumentID: documentID,
|
DocumentID: documentID,
|
||||||
DeviceID: deviceID,
|
DeviceID: deviceID,
|
||||||
UserID: userID,
|
UserID: userID,
|
||||||
@@ -95,7 +96,7 @@ func (suite *DatabaseTestSuite) SetupTest() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Initiate Cache
|
// Initiate Cache
|
||||||
err = suite.dbm.CacheTempTables()
|
err = suite.dbm.CacheTempTables(context.Background())
|
||||||
suite.NoError(err)
|
suite.NoError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,7 +106,7 @@ func (suite *DatabaseTestSuite) SetupTest() {
|
|||||||
// - (q *Queries) UpsertDevice
|
// - (q *Queries) UpsertDevice
|
||||||
func (suite *DatabaseTestSuite) TestDevice() {
|
func (suite *DatabaseTestSuite) TestDevice() {
|
||||||
testDevice := "dev123"
|
testDevice := "dev123"
|
||||||
device, err := suite.dbm.Queries.UpsertDevice(suite.dbm.Ctx, UpsertDeviceParams{
|
device, err := suite.dbm.Queries.UpsertDevice(context.Background(), UpsertDeviceParams{
|
||||||
ID: testDevice,
|
ID: testDevice,
|
||||||
UserID: userID,
|
UserID: userID,
|
||||||
DeviceName: deviceName,
|
DeviceName: deviceName,
|
||||||
@@ -123,7 +124,7 @@ func (suite *DatabaseTestSuite) TestDevice() {
|
|||||||
// - (q *Queries) GetLastActivity
|
// - (q *Queries) GetLastActivity
|
||||||
func (suite *DatabaseTestSuite) TestActivity() {
|
func (suite *DatabaseTestSuite) TestActivity() {
|
||||||
// Validate Exists
|
// Validate Exists
|
||||||
existsRows, err := suite.dbm.Queries.GetActivity(suite.dbm.Ctx, GetActivityParams{
|
existsRows, err := suite.dbm.Queries.GetActivity(context.Background(), GetActivityParams{
|
||||||
UserID: userID,
|
UserID: userID,
|
||||||
Offset: 0,
|
Offset: 0,
|
||||||
Limit: 50,
|
Limit: 50,
|
||||||
@@ -133,7 +134,7 @@ func (suite *DatabaseTestSuite) TestActivity() {
|
|||||||
suite.Len(existsRows, 10, "should have correct number of rows get activity")
|
suite.Len(existsRows, 10, "should have correct number of rows get activity")
|
||||||
|
|
||||||
// Validate Doesn't Exist
|
// Validate Doesn't Exist
|
||||||
doesntExistsRows, err := suite.dbm.Queries.GetActivity(suite.dbm.Ctx, GetActivityParams{
|
doesntExistsRows, err := suite.dbm.Queries.GetActivity(context.Background(), GetActivityParams{
|
||||||
UserID: userID,
|
UserID: userID,
|
||||||
DocumentID: "unknownDoc",
|
DocumentID: "unknownDoc",
|
||||||
DocFilter: true,
|
DocFilter: true,
|
||||||
@@ -151,7 +152,7 @@ func (suite *DatabaseTestSuite) TestActivity() {
|
|||||||
// - (q *Queries) GetDatabaseInfo
|
// - (q *Queries) GetDatabaseInfo
|
||||||
// - (q *Queries) UpdateSettings
|
// - (q *Queries) UpdateSettings
|
||||||
func (suite *DatabaseTestSuite) TestGetDailyReadStats() {
|
func (suite *DatabaseTestSuite) TestGetDailyReadStats() {
|
||||||
readStats, err := suite.dbm.Queries.GetDailyReadStats(suite.dbm.Ctx, userID)
|
readStats, err := suite.dbm.Queries.GetDailyReadStats(context.Background(), userID)
|
||||||
|
|
||||||
suite.Nil(err, "should have nil err")
|
suite.Nil(err, "should have nil err")
|
||||||
suite.Len(readStats, 30, "should have length of 30")
|
suite.Len(readStats, 30, "should have length of 30")
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.27.0
|
// sqlc v1.29.0
|
||||||
|
|
||||||
package database
|
package database
|
||||||
|
|
||||||
@@ -78,7 +78,7 @@ type DocumentUserStatistic struct {
|
|||||||
WeeklyWpm float64 `json:"weekly_wpm"`
|
WeeklyWpm float64 `json:"weekly_wpm"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Metadatum struct {
|
type Metadata struct {
|
||||||
ID int64 `json:"id"`
|
ID int64 `json:"id"`
|
||||||
DocumentID string `json:"document_id"`
|
DocumentID string `json:"document_id"`
|
||||||
Title *string `json:"title"`
|
Title *string `json:"title"`
|
||||||
|
|||||||
@@ -163,42 +163,6 @@ ORDER BY
|
|||||||
DESC
|
DESC
|
||||||
LIMIT 1;
|
LIMIT 1;
|
||||||
|
|
||||||
-- name: GetDocumentWithStats :one
|
|
||||||
SELECT
|
|
||||||
docs.id,
|
|
||||||
docs.title,
|
|
||||||
docs.author,
|
|
||||||
docs.description,
|
|
||||||
docs.isbn10,
|
|
||||||
docs.isbn13,
|
|
||||||
docs.filepath,
|
|
||||||
docs.words,
|
|
||||||
|
|
||||||
CAST(COALESCE(dus.total_wpm, 0.0) AS INTEGER) AS wpm,
|
|
||||||
COALESCE(dus.read_percentage, 0) AS read_percentage,
|
|
||||||
COALESCE(dus.total_time_seconds, 0) AS total_time_seconds,
|
|
||||||
STRFTIME('%Y-%m-%d %H:%M:%S', LOCAL_TIME(COALESCE(dus.last_read, STRFTIME('%Y-%m-%dT%H:%M:%SZ', 0, 'unixepoch')), users.timezone))
|
|
||||||
AS last_read,
|
|
||||||
ROUND(CAST(CASE
|
|
||||||
WHEN dus.percentage IS NULL THEN 0.0
|
|
||||||
WHEN (dus.percentage * 100.0) > 97.0 THEN 100.0
|
|
||||||
ELSE dus.percentage * 100.0
|
|
||||||
END AS REAL), 2) AS percentage,
|
|
||||||
CAST(CASE
|
|
||||||
WHEN dus.total_time_seconds IS NULL THEN 0.0
|
|
||||||
ELSE
|
|
||||||
CAST(dus.total_time_seconds AS REAL)
|
|
||||||
/ (dus.read_percentage * 100.0)
|
|
||||||
END AS INTEGER) AS seconds_per_percent
|
|
||||||
FROM documents AS docs
|
|
||||||
LEFT JOIN users ON users.id = $user_id
|
|
||||||
LEFT JOIN
|
|
||||||
document_user_statistics AS dus
|
|
||||||
ON dus.document_id = docs.id AND dus.user_id = $user_id
|
|
||||||
WHERE users.id = $user_id
|
|
||||||
AND docs.id = $document_id
|
|
||||||
LIMIT 1;
|
|
||||||
|
|
||||||
-- name: GetDocuments :many
|
-- name: GetDocuments :many
|
||||||
SELECT * FROM documents
|
SELECT * FROM documents
|
||||||
ORDER BY created_at DESC
|
ORDER BY created_at DESC
|
||||||
@@ -236,26 +200,25 @@ SELECT
|
|||||||
WHEN (dus.percentage * 100.0) > 97.0 THEN 100.0
|
WHEN (dus.percentage * 100.0) > 97.0 THEN 100.0
|
||||||
ELSE dus.percentage * 100.0
|
ELSE dus.percentage * 100.0
|
||||||
END AS REAL), 2) AS percentage,
|
END AS REAL), 2) AS percentage,
|
||||||
|
CAST(CASE
|
||||||
CASE
|
|
||||||
WHEN dus.total_time_seconds IS NULL THEN 0.0
|
WHEN dus.total_time_seconds IS NULL THEN 0.0
|
||||||
ELSE
|
ELSE
|
||||||
ROUND(
|
CAST(dus.total_time_seconds AS REAL)
|
||||||
CAST(dus.total_time_seconds AS REAL)
|
/ (dus.read_percentage * 100.0)
|
||||||
/ (dus.read_percentage * 100.0)
|
END AS INTEGER) AS seconds_per_percent
|
||||||
)
|
|
||||||
END AS seconds_per_percent
|
|
||||||
FROM documents AS docs
|
FROM documents AS docs
|
||||||
LEFT JOIN users ON users.id = $user_id
|
LEFT JOIN users ON users.id = $user_id
|
||||||
LEFT JOIN
|
LEFT JOIN
|
||||||
document_user_statistics AS dus
|
document_user_statistics AS dus
|
||||||
ON dus.document_id = docs.id AND dus.user_id = $user_id
|
ON dus.document_id = docs.id AND dus.user_id = $user_id
|
||||||
WHERE
|
WHERE
|
||||||
docs.deleted = false AND (
|
(docs.id = sqlc.narg('id') OR $id IS NULL)
|
||||||
$query IS NULL OR (
|
AND (docs.deleted = sqlc.narg(deleted) OR $deleted IS NULL)
|
||||||
docs.title LIKE $query OR
|
AND (
|
||||||
|
(
|
||||||
|
docs.title LIKE sqlc.narg('query') OR
|
||||||
docs.author LIKE $query
|
docs.author LIKE $query
|
||||||
)
|
) OR $query IS NULL
|
||||||
)
|
)
|
||||||
ORDER BY dus.last_read DESC, docs.created_at DESC
|
ORDER BY dus.last_read DESC, docs.created_at DESC
|
||||||
LIMIT $limit
|
LIMIT $limit
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.27.0
|
// sqlc v1.29.0
|
||||||
// source: query.sql
|
// source: query.sql
|
||||||
|
|
||||||
package database
|
package database
|
||||||
@@ -85,7 +85,7 @@ type AddMetadataParams struct {
|
|||||||
Isbn13 *string `json:"isbn13"`
|
Isbn13 *string `json:"isbn13"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) AddMetadata(ctx context.Context, arg AddMetadataParams) (Metadatum, error) {
|
func (q *Queries) AddMetadata(ctx context.Context, arg AddMetadataParams) (Metadata, error) {
|
||||||
row := q.db.QueryRowContext(ctx, addMetadata,
|
row := q.db.QueryRowContext(ctx, addMetadata,
|
||||||
arg.DocumentID,
|
arg.DocumentID,
|
||||||
arg.Title,
|
arg.Title,
|
||||||
@@ -96,7 +96,7 @@ func (q *Queries) AddMetadata(ctx context.Context, arg AddMetadataParams) (Metad
|
|||||||
arg.Isbn10,
|
arg.Isbn10,
|
||||||
arg.Isbn13,
|
arg.Isbn13,
|
||||||
)
|
)
|
||||||
var i Metadatum
|
var i Metadata
|
||||||
err := row.Scan(
|
err := row.Scan(
|
||||||
&i.ID,
|
&i.ID,
|
||||||
&i.DocumentID,
|
&i.DocumentID,
|
||||||
@@ -543,87 +543,6 @@ func (q *Queries) GetDocumentProgress(ctx context.Context, arg GetDocumentProgre
|
|||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
||||||
const getDocumentWithStats = `-- name: GetDocumentWithStats :one
|
|
||||||
SELECT
|
|
||||||
docs.id,
|
|
||||||
docs.title,
|
|
||||||
docs.author,
|
|
||||||
docs.description,
|
|
||||||
docs.isbn10,
|
|
||||||
docs.isbn13,
|
|
||||||
docs.filepath,
|
|
||||||
docs.words,
|
|
||||||
|
|
||||||
CAST(COALESCE(dus.total_wpm, 0.0) AS INTEGER) AS wpm,
|
|
||||||
COALESCE(dus.read_percentage, 0) AS read_percentage,
|
|
||||||
COALESCE(dus.total_time_seconds, 0) AS total_time_seconds,
|
|
||||||
STRFTIME('%Y-%m-%d %H:%M:%S', LOCAL_TIME(COALESCE(dus.last_read, STRFTIME('%Y-%m-%dT%H:%M:%SZ', 0, 'unixepoch')), users.timezone))
|
|
||||||
AS last_read,
|
|
||||||
ROUND(CAST(CASE
|
|
||||||
WHEN dus.percentage IS NULL THEN 0.0
|
|
||||||
WHEN (dus.percentage * 100.0) > 97.0 THEN 100.0
|
|
||||||
ELSE dus.percentage * 100.0
|
|
||||||
END AS REAL), 2) AS percentage,
|
|
||||||
CAST(CASE
|
|
||||||
WHEN dus.total_time_seconds IS NULL THEN 0.0
|
|
||||||
ELSE
|
|
||||||
CAST(dus.total_time_seconds AS REAL)
|
|
||||||
/ (dus.read_percentage * 100.0)
|
|
||||||
END AS INTEGER) AS seconds_per_percent
|
|
||||||
FROM documents AS docs
|
|
||||||
LEFT JOIN users ON users.id = ?1
|
|
||||||
LEFT JOIN
|
|
||||||
document_user_statistics AS dus
|
|
||||||
ON dus.document_id = docs.id AND dus.user_id = ?1
|
|
||||||
WHERE users.id = ?1
|
|
||||||
AND docs.id = ?2
|
|
||||||
LIMIT 1
|
|
||||||
`
|
|
||||||
|
|
||||||
type GetDocumentWithStatsParams struct {
|
|
||||||
UserID string `json:"user_id"`
|
|
||||||
DocumentID string `json:"document_id"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type GetDocumentWithStatsRow struct {
|
|
||||||
ID string `json:"id"`
|
|
||||||
Title *string `json:"title"`
|
|
||||||
Author *string `json:"author"`
|
|
||||||
Description *string `json:"description"`
|
|
||||||
Isbn10 *string `json:"isbn10"`
|
|
||||||
Isbn13 *string `json:"isbn13"`
|
|
||||||
Filepath *string `json:"filepath"`
|
|
||||||
Words *int64 `json:"words"`
|
|
||||||
Wpm int64 `json:"wpm"`
|
|
||||||
ReadPercentage float64 `json:"read_percentage"`
|
|
||||||
TotalTimeSeconds int64 `json:"total_time_seconds"`
|
|
||||||
LastRead interface{} `json:"last_read"`
|
|
||||||
Percentage float64 `json:"percentage"`
|
|
||||||
SecondsPerPercent int64 `json:"seconds_per_percent"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (q *Queries) GetDocumentWithStats(ctx context.Context, arg GetDocumentWithStatsParams) (GetDocumentWithStatsRow, error) {
|
|
||||||
row := q.db.QueryRowContext(ctx, getDocumentWithStats, arg.UserID, arg.DocumentID)
|
|
||||||
var i GetDocumentWithStatsRow
|
|
||||||
err := row.Scan(
|
|
||||||
&i.ID,
|
|
||||||
&i.Title,
|
|
||||||
&i.Author,
|
|
||||||
&i.Description,
|
|
||||||
&i.Isbn10,
|
|
||||||
&i.Isbn13,
|
|
||||||
&i.Filepath,
|
|
||||||
&i.Words,
|
|
||||||
&i.Wpm,
|
|
||||||
&i.ReadPercentage,
|
|
||||||
&i.TotalTimeSeconds,
|
|
||||||
&i.LastRead,
|
|
||||||
&i.Percentage,
|
|
||||||
&i.SecondsPerPercent,
|
|
||||||
)
|
|
||||||
return i, err
|
|
||||||
}
|
|
||||||
|
|
||||||
const getDocuments = `-- name: GetDocuments :many
|
const getDocuments = `-- name: GetDocuments :many
|
||||||
SELECT id, md5, basepath, filepath, coverfile, title, author, series, series_index, lang, description, words, gbid, olid, isbn10, isbn13, synced, deleted, updated_at, created_at FROM documents
|
SELECT id, md5, basepath, filepath, coverfile, title, author, series, series_index, lang, description, words, gbid, olid, isbn10, isbn13, synced, deleted, updated_at, created_at FROM documents
|
||||||
ORDER BY created_at DESC
|
ORDER BY created_at DESC
|
||||||
@@ -719,37 +638,38 @@ SELECT
|
|||||||
WHEN (dus.percentage * 100.0) > 97.0 THEN 100.0
|
WHEN (dus.percentage * 100.0) > 97.0 THEN 100.0
|
||||||
ELSE dus.percentage * 100.0
|
ELSE dus.percentage * 100.0
|
||||||
END AS REAL), 2) AS percentage,
|
END AS REAL), 2) AS percentage,
|
||||||
|
CAST(CASE
|
||||||
CASE
|
|
||||||
WHEN dus.total_time_seconds IS NULL THEN 0.0
|
WHEN dus.total_time_seconds IS NULL THEN 0.0
|
||||||
ELSE
|
ELSE
|
||||||
ROUND(
|
CAST(dus.total_time_seconds AS REAL)
|
||||||
CAST(dus.total_time_seconds AS REAL)
|
/ (dus.read_percentage * 100.0)
|
||||||
/ (dus.read_percentage * 100.0)
|
END AS INTEGER) AS seconds_per_percent
|
||||||
)
|
|
||||||
END AS seconds_per_percent
|
|
||||||
FROM documents AS docs
|
FROM documents AS docs
|
||||||
LEFT JOIN users ON users.id = ?1
|
LEFT JOIN users ON users.id = ?1
|
||||||
LEFT JOIN
|
LEFT JOIN
|
||||||
document_user_statistics AS dus
|
document_user_statistics AS dus
|
||||||
ON dus.document_id = docs.id AND dus.user_id = ?1
|
ON dus.document_id = docs.id AND dus.user_id = ?1
|
||||||
WHERE
|
WHERE
|
||||||
docs.deleted = false AND (
|
(docs.id = ?2 OR ?2 IS NULL)
|
||||||
?2 IS NULL OR (
|
AND (docs.deleted = ?3 OR ?3 IS NULL)
|
||||||
docs.title LIKE ?2 OR
|
AND (
|
||||||
docs.author LIKE ?2
|
(
|
||||||
)
|
docs.title LIKE ?4 OR
|
||||||
|
docs.author LIKE ?4
|
||||||
|
) OR ?4 IS NULL
|
||||||
)
|
)
|
||||||
ORDER BY dus.last_read DESC, docs.created_at DESC
|
ORDER BY dus.last_read DESC, docs.created_at DESC
|
||||||
LIMIT ?4
|
LIMIT ?6
|
||||||
OFFSET ?3
|
OFFSET ?5
|
||||||
`
|
`
|
||||||
|
|
||||||
type GetDocumentsWithStatsParams struct {
|
type GetDocumentsWithStatsParams struct {
|
||||||
UserID string `json:"user_id"`
|
UserID string `json:"user_id"`
|
||||||
Query interface{} `json:"query"`
|
ID *string `json:"id"`
|
||||||
Offset int64 `json:"offset"`
|
Deleted *bool `json:"-"`
|
||||||
Limit int64 `json:"limit"`
|
Query *string `json:"query"`
|
||||||
|
Offset int64 `json:"offset"`
|
||||||
|
Limit int64 `json:"limit"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type GetDocumentsWithStatsRow struct {
|
type GetDocumentsWithStatsRow struct {
|
||||||
@@ -766,12 +686,14 @@ type GetDocumentsWithStatsRow struct {
|
|||||||
TotalTimeSeconds int64 `json:"total_time_seconds"`
|
TotalTimeSeconds int64 `json:"total_time_seconds"`
|
||||||
LastRead interface{} `json:"last_read"`
|
LastRead interface{} `json:"last_read"`
|
||||||
Percentage float64 `json:"percentage"`
|
Percentage float64 `json:"percentage"`
|
||||||
SecondsPerPercent interface{} `json:"seconds_per_percent"`
|
SecondsPerPercent int64 `json:"seconds_per_percent"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) GetDocumentsWithStats(ctx context.Context, arg GetDocumentsWithStatsParams) ([]GetDocumentsWithStatsRow, error) {
|
func (q *Queries) GetDocumentsWithStats(ctx context.Context, arg GetDocumentsWithStatsParams) ([]GetDocumentsWithStatsRow, error) {
|
||||||
rows, err := q.db.QueryContext(ctx, getDocumentsWithStats,
|
rows, err := q.db.QueryContext(ctx, getDocumentsWithStats,
|
||||||
arg.UserID,
|
arg.UserID,
|
||||||
|
arg.ID,
|
||||||
|
arg.Deleted,
|
||||||
arg.Query,
|
arg.Query,
|
||||||
arg.Offset,
|
arg.Offset,
|
||||||
arg.Limit,
|
arg.Limit,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package database
|
package database
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
@@ -36,7 +37,7 @@ func (suite *UsersTestSuite) SetupTest() {
|
|||||||
// Create User
|
// Create User
|
||||||
rawAuthHash, _ := utils.GenerateToken(64)
|
rawAuthHash, _ := utils.GenerateToken(64)
|
||||||
authHash := fmt.Sprintf("%x", rawAuthHash)
|
authHash := fmt.Sprintf("%x", rawAuthHash)
|
||||||
_, err := suite.dbm.Queries.CreateUser(suite.dbm.Ctx, CreateUserParams{
|
_, err := suite.dbm.Queries.CreateUser(context.Background(), CreateUserParams{
|
||||||
ID: testUserID,
|
ID: testUserID,
|
||||||
Pass: &testUserPass,
|
Pass: &testUserPass,
|
||||||
AuthHash: &authHash,
|
AuthHash: &authHash,
|
||||||
@@ -44,7 +45,7 @@ func (suite *UsersTestSuite) SetupTest() {
|
|||||||
suite.NoError(err)
|
suite.NoError(err)
|
||||||
|
|
||||||
// Create Document
|
// Create Document
|
||||||
_, err = suite.dbm.Queries.UpsertDocument(suite.dbm.Ctx, UpsertDocumentParams{
|
_, err = suite.dbm.Queries.UpsertDocument(context.Background(), UpsertDocumentParams{
|
||||||
ID: documentID,
|
ID: documentID,
|
||||||
Title: &documentTitle,
|
Title: &documentTitle,
|
||||||
Author: &documentAuthor,
|
Author: &documentAuthor,
|
||||||
@@ -53,7 +54,7 @@ func (suite *UsersTestSuite) SetupTest() {
|
|||||||
suite.NoError(err)
|
suite.NoError(err)
|
||||||
|
|
||||||
// Create Device
|
// Create Device
|
||||||
_, err = suite.dbm.Queries.UpsertDevice(suite.dbm.Ctx, UpsertDeviceParams{
|
_, err = suite.dbm.Queries.UpsertDevice(context.Background(), UpsertDeviceParams{
|
||||||
ID: deviceID,
|
ID: deviceID,
|
||||||
UserID: testUserID,
|
UserID: testUserID,
|
||||||
DeviceName: deviceName,
|
DeviceName: deviceName,
|
||||||
@@ -62,7 +63,7 @@ func (suite *UsersTestSuite) SetupTest() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (suite *UsersTestSuite) TestGetUser() {
|
func (suite *UsersTestSuite) TestGetUser() {
|
||||||
user, err := suite.dbm.Queries.GetUser(suite.dbm.Ctx, testUserID)
|
user, err := suite.dbm.Queries.GetUser(context.Background(), testUserID)
|
||||||
suite.Nil(err, "should have nil err")
|
suite.Nil(err, "should have nil err")
|
||||||
suite.Equal(testUserPass, *user.Pass)
|
suite.Equal(testUserPass, *user.Pass)
|
||||||
}
|
}
|
||||||
@@ -76,7 +77,7 @@ func (suite *UsersTestSuite) TestCreateUser() {
|
|||||||
suite.Nil(err, "should have nil err")
|
suite.Nil(err, "should have nil err")
|
||||||
|
|
||||||
authHash := fmt.Sprintf("%x", rawAuthHash)
|
authHash := fmt.Sprintf("%x", rawAuthHash)
|
||||||
changed, err := suite.dbm.Queries.CreateUser(suite.dbm.Ctx, CreateUserParams{
|
changed, err := suite.dbm.Queries.CreateUser(context.Background(), CreateUserParams{
|
||||||
ID: testUser,
|
ID: testUser,
|
||||||
Pass: &testPass,
|
Pass: &testPass,
|
||||||
AuthHash: &authHash,
|
AuthHash: &authHash,
|
||||||
@@ -85,29 +86,29 @@ func (suite *UsersTestSuite) TestCreateUser() {
|
|||||||
suite.Nil(err, "should have nil err")
|
suite.Nil(err, "should have nil err")
|
||||||
suite.Equal(int64(1), changed)
|
suite.Equal(int64(1), changed)
|
||||||
|
|
||||||
user, err := suite.dbm.Queries.GetUser(suite.dbm.Ctx, testUser)
|
user, err := suite.dbm.Queries.GetUser(context.Background(), testUser)
|
||||||
suite.Nil(err, "should have nil err")
|
suite.Nil(err, "should have nil err")
|
||||||
suite.Equal(testPass, *user.Pass)
|
suite.Equal(testPass, *user.Pass)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *UsersTestSuite) TestDeleteUser() {
|
func (suite *UsersTestSuite) TestDeleteUser() {
|
||||||
changed, err := suite.dbm.Queries.DeleteUser(suite.dbm.Ctx, testUserID)
|
changed, err := suite.dbm.Queries.DeleteUser(context.Background(), testUserID)
|
||||||
suite.Nil(err, "should have nil err")
|
suite.Nil(err, "should have nil err")
|
||||||
suite.Equal(int64(1), changed, "should have one changed row")
|
suite.Equal(int64(1), changed, "should have one changed row")
|
||||||
|
|
||||||
_, err = suite.dbm.Queries.GetUser(suite.dbm.Ctx, testUserID)
|
_, err = suite.dbm.Queries.GetUser(context.Background(), testUserID)
|
||||||
suite.ErrorIs(err, sql.ErrNoRows, "should have no rows error")
|
suite.ErrorIs(err, sql.ErrNoRows, "should have no rows error")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *UsersTestSuite) TestGetUsers() {
|
func (suite *UsersTestSuite) TestGetUsers() {
|
||||||
users, err := suite.dbm.Queries.GetUsers(suite.dbm.Ctx)
|
users, err := suite.dbm.Queries.GetUsers(context.Background())
|
||||||
suite.Nil(err, "should have nil err")
|
suite.Nil(err, "should have nil err")
|
||||||
suite.Len(users, 1, "should have single user")
|
suite.Len(users, 1, "should have single user")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *UsersTestSuite) TestUpdateUser() {
|
func (suite *UsersTestSuite) TestUpdateUser() {
|
||||||
newPassword := "newPass123"
|
newPassword := "newPass123"
|
||||||
user, err := suite.dbm.Queries.UpdateUser(suite.dbm.Ctx, UpdateUserParams{
|
user, err := suite.dbm.Queries.UpdateUser(context.Background(), UpdateUserParams{
|
||||||
UserID: testUserID,
|
UserID: testUserID,
|
||||||
Password: &newPassword,
|
Password: &newPassword,
|
||||||
})
|
})
|
||||||
@@ -116,11 +117,11 @@ func (suite *UsersTestSuite) TestUpdateUser() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (suite *UsersTestSuite) TestGetUserStatistics() {
|
func (suite *UsersTestSuite) TestGetUserStatistics() {
|
||||||
err := suite.dbm.CacheTempTables()
|
err := suite.dbm.CacheTempTables(context.Background())
|
||||||
suite.NoError(err)
|
suite.NoError(err)
|
||||||
|
|
||||||
// Ensure Zero Items
|
// Ensure Zero Items
|
||||||
userStats, err := suite.dbm.Queries.GetUserStatistics(suite.dbm.Ctx)
|
userStats, err := suite.dbm.Queries.GetUserStatistics(context.Background())
|
||||||
suite.Nil(err, "should have nil err")
|
suite.Nil(err, "should have nil err")
|
||||||
suite.Empty(userStats, "should be empty")
|
suite.Empty(userStats, "should be empty")
|
||||||
|
|
||||||
@@ -133,7 +134,7 @@ func (suite *UsersTestSuite) TestGetUserStatistics() {
|
|||||||
counter += 1
|
counter += 1
|
||||||
|
|
||||||
// Add Item
|
// Add Item
|
||||||
activity, err := suite.dbm.Queries.AddActivity(suite.dbm.Ctx, AddActivityParams{
|
activity, err := suite.dbm.Queries.AddActivity(context.Background(), AddActivityParams{
|
||||||
DocumentID: documentID,
|
DocumentID: documentID,
|
||||||
DeviceID: deviceID,
|
DeviceID: deviceID,
|
||||||
UserID: testUserID,
|
UserID: testUserID,
|
||||||
@@ -147,21 +148,21 @@ func (suite *UsersTestSuite) TestGetUserStatistics() {
|
|||||||
suite.Equal(counter, activity.ID, fmt.Sprintf("[%d] should have correct id for add activity", counter))
|
suite.Equal(counter, activity.ID, fmt.Sprintf("[%d] should have correct id for add activity", counter))
|
||||||
}
|
}
|
||||||
|
|
||||||
err = suite.dbm.CacheTempTables()
|
err = suite.dbm.CacheTempTables(context.Background())
|
||||||
suite.NoError(err)
|
suite.NoError(err)
|
||||||
|
|
||||||
// Ensure One Item
|
// Ensure One Item
|
||||||
userStats, err = suite.dbm.Queries.GetUserStatistics(suite.dbm.Ctx)
|
userStats, err = suite.dbm.Queries.GetUserStatistics(context.Background())
|
||||||
suite.Nil(err, "should have nil err")
|
suite.Nil(err, "should have nil err")
|
||||||
suite.Len(userStats, 1, "should have length of one")
|
suite.Len(userStats, 1, "should have length of one")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *UsersTestSuite) TestGetUsersStreaks() {
|
func (suite *UsersTestSuite) TestGetUsersStreaks() {
|
||||||
err := suite.dbm.CacheTempTables()
|
err := suite.dbm.CacheTempTables(context.Background())
|
||||||
suite.NoError(err)
|
suite.NoError(err)
|
||||||
|
|
||||||
// Ensure Zero Items
|
// Ensure Zero Items
|
||||||
userStats, err := suite.dbm.Queries.GetUserStreaks(suite.dbm.Ctx, testUserID)
|
userStats, err := suite.dbm.Queries.GetUserStreaks(context.Background(), testUserID)
|
||||||
suite.Nil(err, "should have nil err")
|
suite.Nil(err, "should have nil err")
|
||||||
suite.Empty(userStats, "should be empty")
|
suite.Empty(userStats, "should be empty")
|
||||||
|
|
||||||
@@ -174,7 +175,7 @@ func (suite *UsersTestSuite) TestGetUsersStreaks() {
|
|||||||
counter += 1
|
counter += 1
|
||||||
|
|
||||||
// Add Item
|
// Add Item
|
||||||
activity, err := suite.dbm.Queries.AddActivity(suite.dbm.Ctx, AddActivityParams{
|
activity, err := suite.dbm.Queries.AddActivity(context.Background(), AddActivityParams{
|
||||||
DocumentID: documentID,
|
DocumentID: documentID,
|
||||||
DeviceID: deviceID,
|
DeviceID: deviceID,
|
||||||
UserID: testUserID,
|
UserID: testUserID,
|
||||||
@@ -188,11 +189,11 @@ func (suite *UsersTestSuite) TestGetUsersStreaks() {
|
|||||||
suite.Equal(counter, activity.ID, fmt.Sprintf("[%d] should have correct id for add activity", counter))
|
suite.Equal(counter, activity.ID, fmt.Sprintf("[%d] should have correct id for add activity", counter))
|
||||||
}
|
}
|
||||||
|
|
||||||
err = suite.dbm.CacheTempTables()
|
err = suite.dbm.CacheTempTables(context.Background())
|
||||||
suite.NoError(err)
|
suite.NoError(err)
|
||||||
|
|
||||||
// Ensure Two Item
|
// Ensure Two Item
|
||||||
userStats, err = suite.dbm.Queries.GetUserStreaks(suite.dbm.Ctx, testUserID)
|
userStats, err = suite.dbm.Queries.GetUserStreaks(context.Background(), testUserID)
|
||||||
suite.Nil(err, "should have nil err")
|
suite.Nil(err, "should have nil err")
|
||||||
suite.Len(userStats, 2, "should have length of two")
|
suite.Len(userStats, 2, "should have length of two")
|
||||||
|
|
||||||
|
|||||||
61
flake.lock
generated
Normal file
61
flake.lock
generated
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"flake-utils": {
|
||||||
|
"inputs": {
|
||||||
|
"systems": "systems"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1731533236,
|
||||||
|
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1754292888,
|
||||||
|
"narHash": "sha256-1ziydHSiDuSnaiPzCQh1mRFBsM2d2yRX9I+5OPGEmIE=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "ce01daebf8489ba97bd1609d185ea276efdeb121",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixos-25.05",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-utils": "flake-utils",
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"systems": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
||||||
29
flake.nix
Normal file
29
flake.nix
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
description = "Development Environment";
|
||||||
|
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05";
|
||||||
|
flake-utils.url = "github:numtide/flake-utils";
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs = { self, nixpkgs, flake-utils }:
|
||||||
|
flake-utils.lib.eachDefaultSystem (system:
|
||||||
|
let
|
||||||
|
pkgs = nixpkgs.legacyPackages.${system};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
devShells.default = pkgs.mkShell {
|
||||||
|
packages = with pkgs; [
|
||||||
|
go
|
||||||
|
golangci-lint
|
||||||
|
nodejs
|
||||||
|
tailwindcss
|
||||||
|
python311Packages.grip
|
||||||
|
];
|
||||||
|
shellHook = ''
|
||||||
|
export PATH=$PATH:~/go/bin
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
94
go.mod
94
go.mod
@@ -1,81 +1,85 @@
|
|||||||
module reichard.io/antholume
|
module reichard.io/antholume
|
||||||
|
|
||||||
go 1.21
|
go 1.24
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/PuerkitoBio/goquery v1.8.1
|
github.com/PuerkitoBio/goquery v1.10.3
|
||||||
github.com/alexedwards/argon2id v1.0.0
|
github.com/alexedwards/argon2id v1.0.0
|
||||||
github.com/gabriel-vasile/mimetype v1.4.3
|
github.com/gabriel-vasile/mimetype v1.4.9
|
||||||
github.com/gin-contrib/multitemplate v0.0.0-20231230012943-32b233489a81
|
github.com/gin-contrib/multitemplate v1.1.1
|
||||||
github.com/gin-contrib/sessions v0.0.5
|
github.com/gin-contrib/sessions v1.0.4
|
||||||
github.com/gin-gonic/gin v1.9.1
|
github.com/gin-gonic/gin v1.10.1
|
||||||
github.com/itchyny/gojq v0.12.14
|
github.com/itchyny/gojq v0.12.17
|
||||||
github.com/microcosm-cc/bluemonday v1.0.26
|
github.com/jarcoal/httpmock v1.3.1
|
||||||
github.com/pressly/goose/v3 v3.17.0
|
github.com/microcosm-cc/bluemonday v1.0.27
|
||||||
|
github.com/pkg/errors v0.9.1
|
||||||
|
github.com/pressly/goose/v3 v3.24.3
|
||||||
github.com/sirupsen/logrus v1.9.3
|
github.com/sirupsen/logrus v1.9.3
|
||||||
github.com/taylorskalyo/goreader v0.0.0-20230626212555-e7f5644f8115
|
github.com/stretchr/testify v1.10.0
|
||||||
github.com/urfave/cli/v2 v2.27.1
|
github.com/taylorskalyo/goreader v1.0.1
|
||||||
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a
|
github.com/urfave/cli/v2 v2.27.7
|
||||||
|
golang.org/x/exp v0.0.0-20250718183923-645b1fa84792
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
||||||
modernc.org/sqlite v1.28.0
|
modernc.org/sqlite v1.38.2
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/andybalholm/cascadia v1.3.2 // indirect
|
github.com/andybalholm/cascadia v1.3.3 // indirect
|
||||||
github.com/aymerick/douceur v0.2.0 // indirect
|
github.com/aymerick/douceur v0.2.0 // indirect
|
||||||
github.com/bytedance/sonic v1.10.2 // indirect
|
github.com/bytedance/sonic v1.14.0 // indirect
|
||||||
|
github.com/bytedance/sonic/loader v0.3.0 // indirect
|
||||||
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
|
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
|
||||||
github.com/chenzhuoyu/iasm v0.9.1 // indirect
|
github.com/chenzhuoyu/iasm v0.9.1 // indirect
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect
|
github.com/cloudwego/base64x v0.1.6 // indirect
|
||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
github.com/gin-contrib/sse v1.1.0 // indirect
|
||||||
github.com/go-playground/locales v0.14.1 // indirect
|
github.com/go-playground/locales v0.14.1 // indirect
|
||||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
github.com/go-playground/validator/v10 v10.17.0 // indirect
|
github.com/go-playground/validator/v10 v10.27.0 // indirect
|
||||||
github.com/goccy/go-json v0.10.2 // indirect
|
github.com/goccy/go-json v0.10.5 // indirect
|
||||||
github.com/google/uuid v1.6.0 // indirect
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
github.com/gorilla/context v1.1.2 // indirect
|
github.com/gorilla/context v1.1.2 // indirect
|
||||||
github.com/gorilla/css v1.0.1 // indirect
|
github.com/gorilla/css v1.0.1 // indirect
|
||||||
github.com/gorilla/securecookie v1.1.2 // indirect
|
github.com/gorilla/securecookie v1.1.2 // indirect
|
||||||
github.com/gorilla/sessions v1.2.2 // indirect
|
github.com/gorilla/sessions v1.4.0 // indirect
|
||||||
github.com/itchyny/timefmt-go v0.1.5 // indirect
|
github.com/itchyny/timefmt-go v0.1.6 // indirect
|
||||||
github.com/jarcoal/httpmock v1.3.1 // indirect
|
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
||||||
github.com/klauspost/cpuid/v2 v2.2.6 // indirect
|
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
|
||||||
github.com/leodido/go-urn v1.2.4 // indirect
|
github.com/leodido/go-urn v1.4.0 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
|
github.com/mfridman/interpolate v0.0.2 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.1.1 // indirect
|
github.com/ncruces/go-strftime v0.1.9 // indirect
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||||
github.com/sethvargo/go-retry v0.2.4 // indirect
|
github.com/sethvargo/go-retry v0.3.0 // indirect
|
||||||
github.com/stretchr/testify v1.8.4 // indirect
|
|
||||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||||
github.com/ugorji/go/codec v1.2.12 // indirect
|
github.com/ugorji/go/codec v1.3.0 // indirect
|
||||||
github.com/xrash/smetrics v0.0.0-20231213231151-1d8dd44e695e // indirect
|
github.com/xrash/smetrics v0.0.0-20250705151800-55b8f293f342 // indirect
|
||||||
go.uber.org/multierr v1.11.0 // indirect
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
golang.org/x/arch v0.7.0 // indirect
|
golang.org/x/arch v0.20.0 // indirect
|
||||||
golang.org/x/crypto v0.18.0 // indirect
|
golang.org/x/crypto v0.41.0 // indirect
|
||||||
golang.org/x/mod v0.14.0 // indirect
|
golang.org/x/mod v0.27.0 // indirect
|
||||||
golang.org/x/net v0.20.0 // indirect
|
golang.org/x/net v0.43.0 // indirect
|
||||||
golang.org/x/sync v0.6.0 // indirect
|
golang.org/x/sync v0.16.0 // indirect
|
||||||
golang.org/x/sys v0.16.0 // indirect
|
golang.org/x/sys v0.35.0 // indirect
|
||||||
golang.org/x/text v0.14.0 // indirect
|
golang.org/x/text v0.28.0 // indirect
|
||||||
golang.org/x/tools v0.17.0 // indirect
|
golang.org/x/tools v0.36.0 // indirect
|
||||||
google.golang.org/protobuf v1.32.0 // indirect
|
google.golang.org/protobuf v1.36.7 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
lukechampine.com/uint128 v1.3.0 // indirect
|
lukechampine.com/uint128 v1.3.0 // indirect
|
||||||
modernc.org/cc/v3 v3.41.0 // indirect
|
modernc.org/cc/v3 v3.41.0 // indirect
|
||||||
modernc.org/ccgo/v3 v3.16.15 // indirect
|
modernc.org/ccgo/v3 v3.17.0 // indirect
|
||||||
modernc.org/libc v1.40.7 // indirect
|
modernc.org/libc v1.66.6 // indirect
|
||||||
modernc.org/mathutil v1.6.0 // indirect
|
modernc.org/mathutil v1.7.1 // indirect
|
||||||
modernc.org/memory v1.7.2 // indirect
|
modernc.org/memory v1.11.0 // indirect
|
||||||
modernc.org/opt v0.1.3 // indirect
|
modernc.org/opt v0.1.4 // indirect
|
||||||
modernc.org/strutil v1.2.0 // indirect
|
modernc.org/strutil v1.2.1 // indirect
|
||||||
modernc.org/token v1.1.0 // indirect
|
modernc.org/token v1.1.0 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
153
go.sum
153
go.sum
@@ -2,27 +2,38 @@ github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25
|
|||||||
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||||
github.com/ClickHouse/ch-go v0.58.2 h1:jSm2szHbT9MCAB1rJ3WuCJqmGLi5UTjlNu+f530UTS0=
|
github.com/ClickHouse/ch-go v0.58.2 h1:jSm2szHbT9MCAB1rJ3WuCJqmGLi5UTjlNu+f530UTS0=
|
||||||
github.com/ClickHouse/ch-go v0.58.2/go.mod h1:Ap/0bEmiLa14gYjCiRkYGbXvbe8vwdrfTYWhsuQ99aw=
|
github.com/ClickHouse/ch-go v0.58.2/go.mod h1:Ap/0bEmiLa14gYjCiRkYGbXvbe8vwdrfTYWhsuQ99aw=
|
||||||
|
github.com/ClickHouse/ch-go v0.65.1 h1:SLuxmLl5Mjj44/XbINsK2HFvzqup0s6rwKLFH347ZhU=
|
||||||
github.com/ClickHouse/clickhouse-go/v2 v2.16.0 h1:rhMfnPewXPnY4Q4lQRGdYuTLRBRKJEIEYHtbUMrzmvI=
|
github.com/ClickHouse/clickhouse-go/v2 v2.16.0 h1:rhMfnPewXPnY4Q4lQRGdYuTLRBRKJEIEYHtbUMrzmvI=
|
||||||
github.com/ClickHouse/clickhouse-go/v2 v2.16.0/go.mod h1:J7SPfIxwR+x4mQ+o8MLSe0oY50NNntEqCIjFe/T1VPM=
|
github.com/ClickHouse/clickhouse-go/v2 v2.16.0/go.mod h1:J7SPfIxwR+x4mQ+o8MLSe0oY50NNntEqCIjFe/T1VPM=
|
||||||
|
github.com/ClickHouse/clickhouse-go/v2 v2.34.0 h1:Y4rqkdrRHgExvC4o/NTbLdY5LFQ3LHS77/RNFxFX3Co=
|
||||||
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
|
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
|
||||||
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
|
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
|
||||||
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw=
|
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw=
|
||||||
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk=
|
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk=
|
||||||
github.com/PuerkitoBio/goquery v1.8.1 h1:uQxhNlArOIdbrH1tr0UXwdVFgDcZDrZVdcpygAcwmWM=
|
github.com/PuerkitoBio/goquery v1.8.1 h1:uQxhNlArOIdbrH1tr0UXwdVFgDcZDrZVdcpygAcwmWM=
|
||||||
github.com/PuerkitoBio/goquery v1.8.1/go.mod h1:Q8ICL1kNUJ2sXGoAhPGUdYDJvgQgHzJsnnd3H7Ho5jQ=
|
github.com/PuerkitoBio/goquery v1.8.1/go.mod h1:Q8ICL1kNUJ2sXGoAhPGUdYDJvgQgHzJsnnd3H7Ho5jQ=
|
||||||
|
github.com/PuerkitoBio/goquery v1.10.3 h1:pFYcNSqHxBD06Fpj/KsbStFRsgRATgnf3LeXiUkhzPo=
|
||||||
|
github.com/PuerkitoBio/goquery v1.10.3/go.mod h1:tMUX0zDMHXYlAQk6p35XxQMqMweEKB7iK7iLNd4RH4Y=
|
||||||
github.com/alexedwards/argon2id v1.0.0 h1:wJzDx66hqWX7siL/SRUmgz3F8YMrd/nfX/xHHcQQP0w=
|
github.com/alexedwards/argon2id v1.0.0 h1:wJzDx66hqWX7siL/SRUmgz3F8YMrd/nfX/xHHcQQP0w=
|
||||||
github.com/alexedwards/argon2id v1.0.0/go.mod h1:tYKkqIjzXvZdzPvADMWOEZ+l6+BD6CtBXMj5fnJppiw=
|
github.com/alexedwards/argon2id v1.0.0/go.mod h1:tYKkqIjzXvZdzPvADMWOEZ+l6+BD6CtBXMj5fnJppiw=
|
||||||
github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI=
|
github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI=
|
||||||
github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||||
|
github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA=
|
||||||
github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA=
|
github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA=
|
||||||
github.com/andybalholm/cascadia v1.3.2 h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsViSLyss=
|
github.com/andybalholm/cascadia v1.3.2 h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsViSLyss=
|
||||||
github.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU=
|
github.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU=
|
||||||
|
github.com/andybalholm/cascadia v1.3.3 h1:AG2YHrzJIm4BZ19iwJ/DAua6Btl3IwJX+VI4kktS1LM=
|
||||||
|
github.com/andybalholm/cascadia v1.3.3/go.mod h1:xNd9bqTn98Ln4DwST8/nG+H0yuB8Hmgu1YHNnWw0GeA=
|
||||||
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
|
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
|
||||||
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
|
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
|
||||||
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
|
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
|
||||||
github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM=
|
github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM=
|
||||||
github.com/bytedance/sonic v1.10.2 h1:GQebETVBxYB7JGWJtLBi07OVzWwt+8dWA00gEVW2ZFE=
|
github.com/bytedance/sonic v1.10.2 h1:GQebETVBxYB7JGWJtLBi07OVzWwt+8dWA00gEVW2ZFE=
|
||||||
github.com/bytedance/sonic v1.10.2/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4=
|
github.com/bytedance/sonic v1.10.2/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4=
|
||||||
|
github.com/bytedance/sonic v1.14.0 h1:/OfKt8HFw0kh2rj8N0F6C/qPGRESq0BbaNZgcNXXzQQ=
|
||||||
|
github.com/bytedance/sonic v1.14.0/go.mod h1:WoEbx8WTcFJfzCe0hbmyTGrfjt8PzNEBdxlNUO24NhA=
|
||||||
|
github.com/bytedance/sonic/loader v0.3.0 h1:dskwH8edlzNMctoruo8FPTJDF3vLtDT0sXZwvZJyqeA=
|
||||||
|
github.com/bytedance/sonic/loader v0.3.0/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI=
|
||||||
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
|
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
|
||||||
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||||
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
|
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
|
||||||
@@ -32,10 +43,15 @@ github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpV
|
|||||||
github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog=
|
github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog=
|
||||||
github.com/chenzhuoyu/iasm v0.9.1 h1:tUHQJXo3NhBqw6s33wkGn9SP3bvrWLdlVIJ3hQBL7P0=
|
github.com/chenzhuoyu/iasm v0.9.1 h1:tUHQJXo3NhBqw6s33wkGn9SP3bvrWLdlVIJ3hQBL7P0=
|
||||||
github.com/chenzhuoyu/iasm v0.9.1/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog=
|
github.com/chenzhuoyu/iasm v0.9.1/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog=
|
||||||
|
github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M=
|
||||||
|
github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU=
|
||||||
|
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
|
||||||
github.com/containerd/continuity v0.4.3 h1:6HVkalIp+2u1ZLH1J/pYX2oBVXlJZvh1X1A7bEZ9Su8=
|
github.com/containerd/continuity v0.4.3 h1:6HVkalIp+2u1ZLH1J/pYX2oBVXlJZvh1X1A7bEZ9Su8=
|
||||||
github.com/containerd/continuity v0.4.3/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ=
|
github.com/containerd/continuity v0.4.3/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.3 h1:qMCsGGgs+MAzDFyp9LpAe1Lqy/fY/qCovCm0qnXZOBM=
|
github.com/cpuguy83/go-md2man/v2 v2.0.3 h1:qMCsGGgs+MAzDFyp9LpAe1Lqy/fY/qCovCm0qnXZOBM=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo=
|
||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
@@ -52,23 +68,36 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp
|
|||||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||||
github.com/elastic/go-sysinfo v1.11.2 h1:mcm4OSYVMyws6+n2HIVMGkln5HOpo5Ie1ZmbbNn0jg4=
|
github.com/elastic/go-sysinfo v1.11.2 h1:mcm4OSYVMyws6+n2HIVMGkln5HOpo5Ie1ZmbbNn0jg4=
|
||||||
github.com/elastic/go-sysinfo v1.11.2/go.mod h1:GKqR8bbMK/1ITnez9NIsIfXQr25aLhRJa7AfT8HpBFQ=
|
github.com/elastic/go-sysinfo v1.11.2/go.mod h1:GKqR8bbMK/1ITnez9NIsIfXQr25aLhRJa7AfT8HpBFQ=
|
||||||
|
github.com/elastic/go-sysinfo v1.15.3 h1:W+RnmhKFkqPTCRoFq2VCTmsT4p/fwpo+3gKNQsn1XU0=
|
||||||
github.com/elastic/go-windows v1.0.1 h1:AlYZOldA+UJ0/2nBuqWdo90GFCgG9xuyw9SYzGUtJm0=
|
github.com/elastic/go-windows v1.0.1 h1:AlYZOldA+UJ0/2nBuqWdo90GFCgG9xuyw9SYzGUtJm0=
|
||||||
github.com/elastic/go-windows v1.0.1/go.mod h1:FoVvqWSun28vaDQPbj2Elfc0JahhPB7WQEGa3c814Ss=
|
github.com/elastic/go-windows v1.0.1/go.mod h1:FoVvqWSun28vaDQPbj2Elfc0JahhPB7WQEGa3c814Ss=
|
||||||
|
github.com/elastic/go-windows v1.0.2 h1:yoLLsAsV5cfg9FLhZ9EXZ2n2sQFKeDYrHenkcivY4vI=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
|
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
|
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
|
||||||
|
github.com/gabriel-vasile/mimetype v1.4.9 h1:5k+WDwEsD9eTLL8Tz3L0VnmVh9QxGjRmjBvAG7U/oYY=
|
||||||
|
github.com/gabriel-vasile/mimetype v1.4.9/go.mod h1:WnSQhFKJuBlRyLiKohA/2DtIlPFAbguNaG7QCHcyGok=
|
||||||
github.com/gin-contrib/multitemplate v0.0.0-20231230012943-32b233489a81 h1:hQ/WeoPMTbN8NHk5i96dWy3D4uF7yCU+kORyWG+P4oU=
|
github.com/gin-contrib/multitemplate v0.0.0-20231230012943-32b233489a81 h1:hQ/WeoPMTbN8NHk5i96dWy3D4uF7yCU+kORyWG+P4oU=
|
||||||
github.com/gin-contrib/multitemplate v0.0.0-20231230012943-32b233489a81/go.mod h1:XLLtIXoP9+9zGcEDc7gAGV3AksGPO+vzv4kXHMJSdU0=
|
github.com/gin-contrib/multitemplate v0.0.0-20231230012943-32b233489a81/go.mod h1:XLLtIXoP9+9zGcEDc7gAGV3AksGPO+vzv4kXHMJSdU0=
|
||||||
|
github.com/gin-contrib/multitemplate v1.1.1 h1:uzhT/ZWS9nBd1h6P+AaxWaVSVAJRAcKH4yafrBU8sPc=
|
||||||
|
github.com/gin-contrib/multitemplate v1.1.1/go.mod h1:1Sa4984P8+x87U0cg5yWxK4jpbK1cXMYegUCZK6XT/M=
|
||||||
github.com/gin-contrib/sessions v0.0.5 h1:CATtfHmLMQrMNpJRgzjWXD7worTh7g7ritsQfmF+0jE=
|
github.com/gin-contrib/sessions v0.0.5 h1:CATtfHmLMQrMNpJRgzjWXD7worTh7g7ritsQfmF+0jE=
|
||||||
github.com/gin-contrib/sessions v0.0.5/go.mod h1:vYAuaUPqie3WUSsft6HUlCjlwwoJQs97miaG2+7neKY=
|
github.com/gin-contrib/sessions v0.0.5/go.mod h1:vYAuaUPqie3WUSsft6HUlCjlwwoJQs97miaG2+7neKY=
|
||||||
|
github.com/gin-contrib/sessions v1.0.4 h1:ha6CNdpYiTOK/hTp05miJLbpTSNfOnFg5Jm2kbcqy8U=
|
||||||
|
github.com/gin-contrib/sessions v1.0.4/go.mod h1:ccmkrb2z6iU2osiAHZG3x3J4suJK+OU27oqzlWOqQgs=
|
||||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||||
|
github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w=
|
||||||
|
github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM=
|
||||||
github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk=
|
github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk=
|
||||||
github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
|
github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
|
||||||
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
|
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
|
||||||
|
github.com/gin-gonic/gin v1.10.1 h1:T0ujvqyCSqRopADpgPgiTT63DUQVSfojyME59Ei63pQ=
|
||||||
|
github.com/gin-gonic/gin v1.10.1/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
|
||||||
github.com/go-faster/city v1.0.1 h1:4WAxSZ3V2Ws4QRDrscLEDcibJY8uf41H6AhXDrNDcGw=
|
github.com/go-faster/city v1.0.1 h1:4WAxSZ3V2Ws4QRDrscLEDcibJY8uf41H6AhXDrNDcGw=
|
||||||
github.com/go-faster/city v1.0.1/go.mod h1:jKcUJId49qdW3L1qKHH/3wPeUstCVpVSXTM6vO3VcTw=
|
github.com/go-faster/city v1.0.1/go.mod h1:jKcUJId49qdW3L1qKHH/3wPeUstCVpVSXTM6vO3VcTw=
|
||||||
github.com/go-faster/errors v0.6.1 h1:nNIPOBkprlKzkThvS/0YaX8Zs9KewLCOSFQS5BU06FI=
|
github.com/go-faster/errors v0.6.1 h1:nNIPOBkprlKzkThvS/0YaX8Zs9KewLCOSFQS5BU06FI=
|
||||||
github.com/go-faster/errors v0.6.1/go.mod h1:5MGV2/2T9yvlrbhe9pD9LO5Z/2zCSq2T8j+Jpi2LAyY=
|
github.com/go-faster/errors v0.6.1/go.mod h1:5MGV2/2T9yvlrbhe9pD9LO5Z/2zCSq2T8j+Jpi2LAyY=
|
||||||
|
github.com/go-faster/errors v0.7.1 h1:MkJTnDoEdi9pDabt1dpWf7AA8/BaSYZqibYyhZ20AYg=
|
||||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||||
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||||
@@ -81,26 +110,36 @@ github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91
|
|||||||
github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
|
github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
|
||||||
github.com/go-playground/validator/v10 v10.17.0 h1:SmVVlfAOtlZncTxRuinDPomC2DkXJ4E5T9gDA0AIH74=
|
github.com/go-playground/validator/v10 v10.17.0 h1:SmVVlfAOtlZncTxRuinDPomC2DkXJ4E5T9gDA0AIH74=
|
||||||
github.com/go-playground/validator/v10 v10.17.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
github.com/go-playground/validator/v10 v10.17.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
||||||
|
github.com/go-playground/validator/v10 v10.27.0 h1:w8+XrWVMhGkxOaaowyKH35gFydVHOvC0/uWoy2Fzwn4=
|
||||||
|
github.com/go-playground/validator/v10 v10.27.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo=
|
||||||
github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
|
github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
|
||||||
github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
||||||
|
github.com/go-sql-driver/mysql v1.9.2 h1:4cNKDYQ1I84SXslGddlsrMhc8k4LeDVj6Ad6WRjiHuU=
|
||||||
github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||||
|
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
|
||||||
|
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||||
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
|
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
|
||||||
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||||
|
github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI=
|
||||||
|
github.com/golang/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4=
|
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
|
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||||
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
|
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
|
||||||
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
|
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
|
||||||
|
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs=
|
||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
@@ -113,35 +152,48 @@ github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kX
|
|||||||
github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo=
|
github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo=
|
||||||
github.com/gorilla/sessions v1.2.2 h1:lqzMYz6bOfvn2WriPUjNByzeXIlVzURcPmgMczkmTjY=
|
github.com/gorilla/sessions v1.2.2 h1:lqzMYz6bOfvn2WriPUjNByzeXIlVzURcPmgMczkmTjY=
|
||||||
github.com/gorilla/sessions v1.2.2/go.mod h1:ePLdVu+jbEgHH+KWw8I1z2wqd0BAdAQh/8LRvBeoNcQ=
|
github.com/gorilla/sessions v1.2.2/go.mod h1:ePLdVu+jbEgHH+KWw8I1z2wqd0BAdAQh/8LRvBeoNcQ=
|
||||||
|
github.com/gorilla/sessions v1.4.0 h1:kpIYOp/oi6MG/p5PgxApU8srsSw9tuFbt46Lt7auzqQ=
|
||||||
|
github.com/gorilla/sessions v1.4.0/go.mod h1:FLWm50oby91+hl7p/wRxDth9bWSuk0qVL2emc7lT5ik=
|
||||||
github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
|
github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
|
||||||
github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
|
github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
|
||||||
github.com/itchyny/gojq v0.12.14 h1:6k8vVtsrhQSYgSGg827AD+PVVaB1NLXEdX+dda2oZCc=
|
github.com/itchyny/gojq v0.12.14 h1:6k8vVtsrhQSYgSGg827AD+PVVaB1NLXEdX+dda2oZCc=
|
||||||
github.com/itchyny/gojq v0.12.14/go.mod h1:y1G7oO7XkcR1LPZO59KyoCRy08T3j9vDYRV0GgYSS+s=
|
github.com/itchyny/gojq v0.12.14/go.mod h1:y1G7oO7XkcR1LPZO59KyoCRy08T3j9vDYRV0GgYSS+s=
|
||||||
|
github.com/itchyny/gojq v0.12.17 h1:8av8eGduDb5+rvEdaOO+zQUjA04MS0m3Ps8HiD+fceg=
|
||||||
|
github.com/itchyny/gojq v0.12.17/go.mod h1:WBrEMkgAfAGO1LUcGOckBl5O726KPp+OlkKug0I/FEY=
|
||||||
github.com/itchyny/timefmt-go v0.1.5 h1:G0INE2la8S6ru/ZI5JecgyzbbJNs5lG1RcBqa7Jm6GE=
|
github.com/itchyny/timefmt-go v0.1.5 h1:G0INE2la8S6ru/ZI5JecgyzbbJNs5lG1RcBqa7Jm6GE=
|
||||||
github.com/itchyny/timefmt-go v0.1.5/go.mod h1:nEP7L+2YmAbT2kZ2HfSs1d8Xtw9LY8D2stDBckWakZ8=
|
github.com/itchyny/timefmt-go v0.1.5/go.mod h1:nEP7L+2YmAbT2kZ2HfSs1d8Xtw9LY8D2stDBckWakZ8=
|
||||||
|
github.com/itchyny/timefmt-go v0.1.6 h1:ia3s54iciXDdzWzwaVKXZPbiXzxxnv1SPGFfM/myJ5Q=
|
||||||
|
github.com/itchyny/timefmt-go v0.1.6/go.mod h1:RRDZYC5s9ErkjQvTvvU7keJjxUYzIISJGxm9/mAERQg=
|
||||||
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
|
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
|
||||||
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||||
|
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
|
||||||
github.com/jackc/pgx/v5 v5.5.1 h1:5I9etrGkLrN+2XPCsi6XLlV5DITbSL/xBZdmAxFcXPI=
|
github.com/jackc/pgx/v5 v5.5.1 h1:5I9etrGkLrN+2XPCsi6XLlV5DITbSL/xBZdmAxFcXPI=
|
||||||
github.com/jackc/pgx/v5 v5.5.1/go.mod h1:Ig06C2Vu0t5qXC60W8sqIthScaEnFvojjj9dSljmHRA=
|
github.com/jackc/pgx/v5 v5.5.1/go.mod h1:Ig06C2Vu0t5qXC60W8sqIthScaEnFvojjj9dSljmHRA=
|
||||||
|
github.com/jackc/pgx/v5 v5.7.4 h1:9wKznZrhWa2QiHL+NjTSPP6yjl3451BX3imWDnokYlg=
|
||||||
github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
|
github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
|
||||||
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
||||||
|
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
|
||||||
github.com/jarcoal/httpmock v1.3.1 h1:iUx3whfZWVf3jT01hQTO/Eo5sAYtB2/rqaUuOtpInww=
|
github.com/jarcoal/httpmock v1.3.1 h1:iUx3whfZWVf3jT01hQTO/Eo5sAYtB2/rqaUuOtpInww=
|
||||||
github.com/jarcoal/httpmock v1.3.1/go.mod h1:3yb8rc4BI7TCBhFY8ng0gjuLKJNquuDNiPaZjnENuYg=
|
github.com/jarcoal/httpmock v1.3.1/go.mod h1:3yb8rc4BI7TCBhFY8ng0gjuLKJNquuDNiPaZjnENuYg=
|
||||||
github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 h1:rp+c0RAYOWj8l6qbCUTSiRLG/iKnW3K3/QfPPuSsBt4=
|
github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 h1:rp+c0RAYOWj8l6qbCUTSiRLG/iKnW3K3/QfPPuSsBt4=
|
||||||
github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak=
|
github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak=
|
||||||
github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4=
|
github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4=
|
||||||
github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc=
|
github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc=
|
||||||
|
github.com/jonboulle/clockwork v0.5.0 h1:Hyh9A8u51kptdkR+cqRpT1EebBwTn1oK9YfGYbdFz6I=
|
||||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
|
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
|
||||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
|
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
|
||||||
github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4=
|
github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4=
|
||||||
github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||||
|
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
||||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||||
github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc=
|
github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc=
|
||||||
github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
|
||||||
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
|
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||||
@@ -154,13 +206,22 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
|||||||
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
|
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
|
||||||
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
|
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
|
||||||
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
|
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
|
||||||
|
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||||
|
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
|
||||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
|
github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
|
||||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||||
|
github.com/maxatome/go-testdeep v1.12.0 h1:Ql7Go8Tg0C1D/uMMX59LAoYK7LffeJQ6X2T04nTH68g=
|
||||||
|
github.com/maxatome/go-testdeep v1.12.0/go.mod h1:lPZc/HAcJMP92l7yI6TRz1aZN5URwUBUAfUNvrclaNM=
|
||||||
|
github.com/mfridman/interpolate v0.0.2 h1:pnuTK7MQIxxFz1Gr+rjSIx9u7qVjf5VOoM/u6BbAxPY=
|
||||||
|
github.com/mfridman/interpolate v0.0.2/go.mod h1:p+7uk6oE07mpE/Ik1b8EckO0O4ZXiGAfshKBWLUM9Xg=
|
||||||
github.com/microcosm-cc/bluemonday v1.0.26 h1:xbqSvqzQMeEHCqMi64VAs4d8uy6Mequs3rQ0k/Khz58=
|
github.com/microcosm-cc/bluemonday v1.0.26 h1:xbqSvqzQMeEHCqMi64VAs4d8uy6Mequs3rQ0k/Khz58=
|
||||||
github.com/microcosm-cc/bluemonday v1.0.26/go.mod h1:JyzOCs9gkyQyjs+6h10UEVSe02CGwkhd72Xdqh78TWs=
|
github.com/microcosm-cc/bluemonday v1.0.26/go.mod h1:JyzOCs9gkyQyjs+6h10UEVSe02CGwkhd72Xdqh78TWs=
|
||||||
|
github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk=
|
||||||
|
github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA=
|
||||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||||
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
|
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
|
||||||
@@ -170,6 +231,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w
|
|||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
|
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
|
||||||
|
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
||||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||||
github.com/opencontainers/image-spec v1.1.0-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/cbdlwvlWt0pnFI=
|
github.com/opencontainers/image-spec v1.1.0-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/cbdlwvlWt0pnFI=
|
||||||
@@ -180,11 +243,15 @@ github.com/ory/dockertest/v3 v3.10.0 h1:4K3z2VMe8Woe++invjaTB7VRyQXQy5UY+loujO4a
|
|||||||
github.com/ory/dockertest/v3 v3.10.0/go.mod h1:nr57ZbRWMqfsdGdFNLHz5jjNdDb7VVFnzAeW1n5N1Lg=
|
github.com/ory/dockertest/v3 v3.10.0/go.mod h1:nr57ZbRWMqfsdGdFNLHz5jjNdDb7VVFnzAeW1n5N1Lg=
|
||||||
github.com/paulmach/orb v0.10.0 h1:guVYVqzxHE/CQ1KpfGO077TR0ATHSNjp4s6XGLn3W9s=
|
github.com/paulmach/orb v0.10.0 h1:guVYVqzxHE/CQ1KpfGO077TR0ATHSNjp4s6XGLn3W9s=
|
||||||
github.com/paulmach/orb v0.10.0/go.mod h1:5mULz1xQfs3bmQm63QEJA6lNGujuRafwA5S/EnuLaLU=
|
github.com/paulmach/orb v0.10.0/go.mod h1:5mULz1xQfs3bmQm63QEJA6lNGujuRafwA5S/EnuLaLU=
|
||||||
|
github.com/paulmach/orb v0.11.1 h1:3koVegMC4X/WeiXYz9iswopaTwMem53NzTJuTF20JzU=
|
||||||
github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
|
github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
|
||||||
github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI=
|
github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI=
|
||||||
github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
|
github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
|
||||||
|
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
|
||||||
|
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
|
||||||
github.com/pierrec/lz4/v4 v4.1.18 h1:xaKrnTkyoqfh1YItXl56+6KJNVYWlEEPuAQW9xsplYQ=
|
github.com/pierrec/lz4/v4 v4.1.18 h1:xaKrnTkyoqfh1YItXl56+6KJNVYWlEEPuAQW9xsplYQ=
|
||||||
github.com/pierrec/lz4/v4 v4.1.18/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
github.com/pierrec/lz4/v4 v4.1.18/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||||
|
github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU=
|
||||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
@@ -192,21 +259,28 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
|
|||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/pressly/goose/v3 v3.17.0 h1:fT4CL3LRm4kfyLuPWzDFAoxjR5ZHjeJ6uQhibQtBaIs=
|
github.com/pressly/goose/v3 v3.17.0 h1:fT4CL3LRm4kfyLuPWzDFAoxjR5ZHjeJ6uQhibQtBaIs=
|
||||||
github.com/pressly/goose/v3 v3.17.0/go.mod h1:22aw7NpnCPlS86oqkO/+3+o9FuCaJg4ZVWRUO3oGzHQ=
|
github.com/pressly/goose/v3 v3.17.0/go.mod h1:22aw7NpnCPlS86oqkO/+3+o9FuCaJg4ZVWRUO3oGzHQ=
|
||||||
|
github.com/pressly/goose/v3 v3.24.3 h1:DSWWNwwggVUsYZ0X2VitiAa9sKuqtBfe+Jr9zFGwWlM=
|
||||||
|
github.com/pressly/goose/v3 v3.24.3/go.mod h1:v9zYL4xdViLHCUUJh/mhjnm6JrK7Eul8AS93IxiZM4E=
|
||||||
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
|
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
|
||||||
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
|
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
|
||||||
|
github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg=
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||||
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
|
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
|
||||||
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
||||||
|
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys=
|
github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys=
|
||||||
github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
|
github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
|
||||||
github.com/sethvargo/go-retry v0.2.4 h1:T+jHEQy/zKJf5s95UkguisicE0zuF9y7+/vgz08Ocec=
|
github.com/sethvargo/go-retry v0.2.4 h1:T+jHEQy/zKJf5s95UkguisicE0zuF9y7+/vgz08Ocec=
|
||||||
github.com/sethvargo/go-retry v0.2.4/go.mod h1:1afjQuvh7s4gflMObvjLPaWgluLLyhA1wmVZ6KLpICw=
|
github.com/sethvargo/go-retry v0.2.4/go.mod h1:1afjQuvh7s4gflMObvjLPaWgluLLyhA1wmVZ6KLpICw=
|
||||||
|
github.com/sethvargo/go-retry v0.3.0 h1:EEt31A35QhrcRZtrYFDTBg91cqZVnFL2navjDrah2SE=
|
||||||
|
github.com/sethvargo/go-retry v0.3.0/go.mod h1:mNX17F0C/HguQMyMyJxcnU471gOZGxCLyYaFyAZraas=
|
||||||
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
|
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
|
||||||
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||||
|
github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
|
||||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
@@ -221,16 +295,24 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o
|
|||||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
|
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||||
|
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
github.com/taylorskalyo/goreader v0.0.0-20230626212555-e7f5644f8115 h1:OEAIMYp5l9kJ2kT9UPL5QSUriKIIDhnLmpJTy69sltA=
|
github.com/taylorskalyo/goreader v0.0.0-20230626212555-e7f5644f8115 h1:OEAIMYp5l9kJ2kT9UPL5QSUriKIIDhnLmpJTy69sltA=
|
||||||
github.com/taylorskalyo/goreader v0.0.0-20230626212555-e7f5644f8115/go.mod h1:AIVbkIe1G7fpFHiKOdxZnU5p9tFPYNTQyH3H5IrRkGw=
|
github.com/taylorskalyo/goreader v0.0.0-20230626212555-e7f5644f8115/go.mod h1:AIVbkIe1G7fpFHiKOdxZnU5p9tFPYNTQyH3H5IrRkGw=
|
||||||
|
github.com/taylorskalyo/goreader v1.0.1 h1:eS9SYiHai2aAHhm+YMGRTqrvNt2aoRMTd7p6ftm0crY=
|
||||||
|
github.com/taylorskalyo/goreader v1.0.1/go.mod h1:JrUsWCgnk4C3P5Jsr7Pf2mFrMpsR0ls/0bjR5aorYTI=
|
||||||
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||||
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||||
github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
|
github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
|
||||||
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
|
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
|
||||||
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
|
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
|
||||||
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||||
|
github.com/ugorji/go/codec v1.3.0 h1:Qd2W2sQawAfG8XSvzwhBeoGq71zXOC/Q1E9y/wUcsUA=
|
||||||
|
github.com/ugorji/go/codec v1.3.0/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4=
|
||||||
github.com/urfave/cli/v2 v2.27.1 h1:8xSQ6szndafKVRmfyeUMxkNUJQMjL1F2zmsZ+qHpfho=
|
github.com/urfave/cli/v2 v2.27.1 h1:8xSQ6szndafKVRmfyeUMxkNUJQMjL1F2zmsZ+qHpfho=
|
||||||
github.com/urfave/cli/v2 v2.27.1/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
|
github.com/urfave/cli/v2 v2.27.1/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
|
||||||
|
github.com/urfave/cli/v2 v2.27.7 h1:bH59vdhbjLv3LAvIu6gd0usJHgoTTPhCFib8qqOwXYU=
|
||||||
|
github.com/urfave/cli/v2 v2.27.7/go.mod h1:CyNAG/xg+iAOg0N4MPGZqVmv2rCoP267496AOXUZjA4=
|
||||||
github.com/vertica/vertica-sql-go v1.3.3 h1:fL+FKEAEy5ONmsvya2WH5T8bhkvY27y/Ik3ReR2T+Qw=
|
github.com/vertica/vertica-sql-go v1.3.3 h1:fL+FKEAEy5ONmsvya2WH5T8bhkvY27y/Ik3ReR2T+Qw=
|
||||||
github.com/vertica/vertica-sql-go v1.3.3/go.mod h1:jnn2GFuv+O2Jcjktb7zyc4Utlbu9YVqpHH/lx63+1M4=
|
github.com/vertica/vertica-sql-go v1.3.3/go.mod h1:jnn2GFuv+O2Jcjktb7zyc4Utlbu9YVqpHH/lx63+1M4=
|
||||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
|
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
|
||||||
@@ -241,32 +323,53 @@ github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17
|
|||||||
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
||||||
github.com/xrash/smetrics v0.0.0-20231213231151-1d8dd44e695e h1:+SOyEddqYF09QP7vr7CgJ1eti3pY9Fn3LHO1M1r/0sI=
|
github.com/xrash/smetrics v0.0.0-20231213231151-1d8dd44e695e h1:+SOyEddqYF09QP7vr7CgJ1eti3pY9Fn3LHO1M1r/0sI=
|
||||||
github.com/xrash/smetrics v0.0.0-20231213231151-1d8dd44e695e/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
|
github.com/xrash/smetrics v0.0.0-20231213231151-1d8dd44e695e/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
|
||||||
|
github.com/xrash/smetrics v0.0.0-20250705151800-55b8f293f342 h1:FnBeRrxr7OU4VvAzt5X7s6266i6cSVkkFPS0TuXWbIg=
|
||||||
|
github.com/xrash/smetrics v0.0.0-20250705151800-55b8f293f342/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM=
|
||||||
github.com/ydb-platform/ydb-go-genproto v0.0.0-20231012155159-f85a672542fd h1:dzWP1Lu+A40W883dK/Mr3xyDSM/2MggS8GtHT0qgAnE=
|
github.com/ydb-platform/ydb-go-genproto v0.0.0-20231012155159-f85a672542fd h1:dzWP1Lu+A40W883dK/Mr3xyDSM/2MggS8GtHT0qgAnE=
|
||||||
github.com/ydb-platform/ydb-go-genproto v0.0.0-20231012155159-f85a672542fd/go.mod h1:Er+FePu1dNUieD+XTMDduGpQuCPssK5Q4BjF+IIXJ3I=
|
github.com/ydb-platform/ydb-go-genproto v0.0.0-20231012155159-f85a672542fd/go.mod h1:Er+FePu1dNUieD+XTMDduGpQuCPssK5Q4BjF+IIXJ3I=
|
||||||
|
github.com/ydb-platform/ydb-go-genproto v0.0.0-20241112172322-ea1f63298f77 h1:LY6cI8cP4B9rrpTleZk95+08kl2gF4rixG7+V/dwL6Q=
|
||||||
github.com/ydb-platform/ydb-go-sdk/v3 v3.54.2 h1:E0yUuuX7UmPxXm92+yQCjMveLFO3zfvYFIJVuAqsVRA=
|
github.com/ydb-platform/ydb-go-sdk/v3 v3.54.2 h1:E0yUuuX7UmPxXm92+yQCjMveLFO3zfvYFIJVuAqsVRA=
|
||||||
github.com/ydb-platform/ydb-go-sdk/v3 v3.54.2/go.mod h1:fjBLQ2TdQNl4bMjuWl9adoTGBypwUTPoGC+EqYqiIcU=
|
github.com/ydb-platform/ydb-go-sdk/v3 v3.54.2/go.mod h1:fjBLQ2TdQNl4bMjuWl9adoTGBypwUTPoGC+EqYqiIcU=
|
||||||
|
github.com/ydb-platform/ydb-go-sdk/v3 v3.108.1 h1:ixAiqjj2S/dNuJqrz4AxSqgw2P5OBMXp68hB5nNriUk=
|
||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
go.opentelemetry.io/otel v1.20.0 h1:vsb/ggIY+hUjD/zCAQHpzTmndPqv/ml2ArbsbfBYTAc=
|
go.opentelemetry.io/otel v1.20.0 h1:vsb/ggIY+hUjD/zCAQHpzTmndPqv/ml2ArbsbfBYTAc=
|
||||||
go.opentelemetry.io/otel v1.20.0/go.mod h1:oUIGj3D77RwJdM6PPZImDpSZGDvkD9fhesHny69JFrs=
|
go.opentelemetry.io/otel v1.20.0/go.mod h1:oUIGj3D77RwJdM6PPZImDpSZGDvkD9fhesHny69JFrs=
|
||||||
|
go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
|
||||||
go.opentelemetry.io/otel/trace v1.20.0 h1:+yxVAPZPbQhbC3OfAkeIVTky6iTFpcr4SiY9om7mXSQ=
|
go.opentelemetry.io/otel/trace v1.20.0 h1:+yxVAPZPbQhbC3OfAkeIVTky6iTFpcr4SiY9om7mXSQ=
|
||||||
go.opentelemetry.io/otel/trace v1.20.0/go.mod h1:HJSK7F/hA5RlzpZ0zKDCHCDHm556LCDtKaAo6JmBFUU=
|
go.opentelemetry.io/otel/trace v1.20.0/go.mod h1:HJSK7F/hA5RlzpZ0zKDCHCDHm556LCDtKaAo6JmBFUU=
|
||||||
|
go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs=
|
||||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||||
golang.org/x/arch v0.7.0 h1:pskyeJh/3AmoQ8CPE95vxHLqp1G1GfGNXTmcl9NEKTc=
|
golang.org/x/arch v0.7.0 h1:pskyeJh/3AmoQ8CPE95vxHLqp1G1GfGNXTmcl9NEKTc=
|
||||||
golang.org/x/arch v0.7.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
golang.org/x/arch v0.7.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
||||||
|
golang.org/x/arch v0.20.0 h1:dx1zTU0MAE98U+TQ8BLl7XsJbgze2WnNKF/8tGp/Q6c=
|
||||||
|
golang.org/x/arch v0.20.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
|
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||||
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
|
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
|
||||||
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
||||||
|
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||||
|
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||||
|
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||||
|
golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4=
|
||||||
|
golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc=
|
||||||
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a h1:Q8/wZp0KX97QFTc2ywcOE0YRjZPVIx+MXInMzdvQqcA=
|
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a h1:Q8/wZp0KX97QFTc2ywcOE0YRjZPVIx+MXInMzdvQqcA=
|
||||||
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08=
|
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08=
|
||||||
|
golang.org/x/exp v0.0.0-20250718183923-645b1fa84792 h1:R9PFI6EUdfVKgwKjZef7QIwGcBKu86OEFpJ9nUEP2l4=
|
||||||
|
golang.org/x/exp v0.0.0-20250718183923-645b1fa84792/go.mod h1:A+z0yzpGtvnG90cToK5n2tu8UJVP2XUATh+r+sfOOOc=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
|
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
|
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
|
||||||
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
|
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
|
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
|
golang.org/x/mod v0.27.0 h1:kb+q2PyFnEADO2IEF935ehFUXlWiNjJWtRNgBLSfbxQ=
|
||||||
|
golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
@@ -275,13 +378,24 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
|||||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
||||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||||
|
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||||
golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
|
golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
|
||||||
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
|
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
|
||||||
|
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||||
|
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||||
|
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
||||||
|
golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
|
||||||
|
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||||
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
|
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
|
||||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
|
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
|
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
|
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
|
||||||
|
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@@ -295,15 +409,26 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
|
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
|
||||||
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
|
||||||
|
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||||
|
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||||
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
|
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
|
||||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||||
|
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||||
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
||||||
|
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||||
|
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||||
|
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
@@ -313,22 +438,35 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
|||||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
|
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
|
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||||
|
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
|
||||||
|
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||||
|
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||||
golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc=
|
golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc=
|
||||||
golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
|
golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
|
||||||
|
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||||
|
golang.org/x/tools v0.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg=
|
||||||
|
golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 h1:Jyp0Hsi0bmHXG6k9eATXoYtjd6e2UzZ1SCn/wIupY14=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 h1:Jyp0Hsi0bmHXG6k9eATXoYtjd6e2UzZ1SCn/wIupY14=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:oQ5rr10WTTMvP4A36n8JpR1OrO1BEiV4f78CneXZxkA=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:oQ5rr10WTTMvP4A36n8JpR1OrO1BEiV4f78CneXZxkA=
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463 h1:e0AIkUUhxyBKh6ssZNrAMeqhA7RKUj42346d1y02i2g=
|
||||||
google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk=
|
google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk=
|
||||||
google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98=
|
google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98=
|
||||||
|
google.golang.org/grpc v1.71.0 h1:kF77BGdPTQ4/JZWMlb9VpJ5pa25aqvVqogsxNHHdeBg=
|
||||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||||
google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
|
google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
|
||||||
google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||||
|
google.golang.org/protobuf v1.36.7 h1:IgrO7UwFQGJdRNXH/sQux4R1Dj1WAKcLElzeeRaXV2A=
|
||||||
|
google.golang.org/protobuf v1.36.7/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
@@ -344,28 +482,43 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
|||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM=
|
howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM=
|
||||||
howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g=
|
howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g=
|
||||||
|
howett.net/plist v1.0.1 h1:37GdZ8tP09Q35o9ych3ehygcsL+HqKSwzctveSlarvM=
|
||||||
lukechampine.com/uint128 v1.3.0 h1:cDdUVfRwDUDovz610ABgFD17nXD4/uDgVHl2sC3+sbo=
|
lukechampine.com/uint128 v1.3.0 h1:cDdUVfRwDUDovz610ABgFD17nXD4/uDgVHl2sC3+sbo=
|
||||||
lukechampine.com/uint128 v1.3.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
|
lukechampine.com/uint128 v1.3.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
|
||||||
modernc.org/cc/v3 v3.41.0 h1:QoR1Sn3YWlmA1T4vLaKZfawdVtSiGx8H+cEojbC7v1Q=
|
modernc.org/cc/v3 v3.41.0 h1:QoR1Sn3YWlmA1T4vLaKZfawdVtSiGx8H+cEojbC7v1Q=
|
||||||
modernc.org/cc/v3 v3.41.0/go.mod h1:Ni4zjJYJ04CDOhG7dn640WGfwBzfE0ecX8TyMB0Fv0Y=
|
modernc.org/cc/v3 v3.41.0/go.mod h1:Ni4zjJYJ04CDOhG7dn640WGfwBzfE0ecX8TyMB0Fv0Y=
|
||||||
modernc.org/ccgo/v3 v3.16.15 h1:KbDR3ZAVU+wiLyMESPtbtE/Add4elztFyfsWoNTgxS0=
|
modernc.org/ccgo/v3 v3.16.15 h1:KbDR3ZAVU+wiLyMESPtbtE/Add4elztFyfsWoNTgxS0=
|
||||||
modernc.org/ccgo/v3 v3.16.15/go.mod h1:yT7B+/E2m43tmMOT51GMoM98/MtHIcQQSleGnddkUNI=
|
modernc.org/ccgo/v3 v3.16.15/go.mod h1:yT7B+/E2m43tmMOT51GMoM98/MtHIcQQSleGnddkUNI=
|
||||||
|
modernc.org/ccgo/v3 v3.17.0 h1:o3OmOqx4/OFnl4Vm3G8Bgmqxnvxnh0nbxeT5p/dWChA=
|
||||||
|
modernc.org/ccgo/v3 v3.17.0/go.mod h1:Sg3fwVpmLvCUTaqEUjiBDAvshIaKDB0RXaf+zgqFu8I=
|
||||||
modernc.org/ccorpus v1.11.6 h1:J16RXiiqiCgua6+ZvQot4yUuUy8zxgqbqEEUuGPlISk=
|
modernc.org/ccorpus v1.11.6 h1:J16RXiiqiCgua6+ZvQot4yUuUy8zxgqbqEEUuGPlISk=
|
||||||
modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ=
|
modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ=
|
||||||
modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM=
|
modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM=
|
||||||
modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM=
|
modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM=
|
||||||
modernc.org/libc v1.40.7 h1:oeLS0G067ZqUu+v143Dqad0btMfKmNS7SuOsnkq0Ysg=
|
modernc.org/libc v1.40.7 h1:oeLS0G067ZqUu+v143Dqad0btMfKmNS7SuOsnkq0Ysg=
|
||||||
modernc.org/libc v1.40.7/go.mod h1:YAXkAZ8ktnkCKaN9sw/UDeUVkGYJ/YquGO4FTi5nmHE=
|
modernc.org/libc v1.40.7/go.mod h1:YAXkAZ8ktnkCKaN9sw/UDeUVkGYJ/YquGO4FTi5nmHE=
|
||||||
|
modernc.org/libc v1.66.6 h1:RyQpwAhM/19nXD8y3iejM/AjmKwY2TjxZTlUWTsWw2U=
|
||||||
|
modernc.org/libc v1.66.6/go.mod h1:j8z0EYAuumoMQ3+cWXtmw6m+LYn3qm8dcZDFtFTSq+M=
|
||||||
modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
|
modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
|
||||||
modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo=
|
modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo=
|
||||||
|
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
|
||||||
|
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
|
||||||
modernc.org/memory v1.7.2 h1:Klh90S215mmH8c9gO98QxQFsY+W451E8AnzjoE2ee1E=
|
modernc.org/memory v1.7.2 h1:Klh90S215mmH8c9gO98QxQFsY+W451E8AnzjoE2ee1E=
|
||||||
modernc.org/memory v1.7.2/go.mod h1:NO4NVCQy0N7ln+T9ngWqOQfi7ley4vpwvARR+Hjw95E=
|
modernc.org/memory v1.7.2/go.mod h1:NO4NVCQy0N7ln+T9ngWqOQfi7ley4vpwvARR+Hjw95E=
|
||||||
|
modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI=
|
||||||
|
modernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw=
|
||||||
modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
|
modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
|
||||||
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
|
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
|
||||||
|
modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8=
|
||||||
|
modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=
|
||||||
modernc.org/sqlite v1.28.0 h1:Zx+LyDDmXczNnEQdvPuEfcFVA2ZPyaD7UCZDjef3BHQ=
|
modernc.org/sqlite v1.28.0 h1:Zx+LyDDmXczNnEQdvPuEfcFVA2ZPyaD7UCZDjef3BHQ=
|
||||||
modernc.org/sqlite v1.28.0/go.mod h1:Qxpazz0zH8Z1xCFyi5GSL3FzbtZ3fvbjmywNogldEW0=
|
modernc.org/sqlite v1.28.0/go.mod h1:Qxpazz0zH8Z1xCFyi5GSL3FzbtZ3fvbjmywNogldEW0=
|
||||||
|
modernc.org/sqlite v1.38.2 h1:Aclu7+tgjgcQVShZqim41Bbw9Cho0y/7WzYptXqkEek=
|
||||||
|
modernc.org/sqlite v1.38.2/go.mod h1:cPTJYSlgg3Sfg046yBShXENNtPrWrDX8bsbAQBzgQ5E=
|
||||||
modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA=
|
modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA=
|
||||||
modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0=
|
modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0=
|
||||||
|
modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
|
||||||
|
modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
|
||||||
modernc.org/tcl v1.15.2 h1:C4ybAYCGJw968e+Me18oW55kD/FexcHbqH2xak1ROSY=
|
modernc.org/tcl v1.15.2 h1:C4ybAYCGJw968e+Me18oW55kD/FexcHbqH2xak1ROSY=
|
||||||
modernc.org/tcl v1.15.2/go.mod h1:3+k/ZaEbKrC8ePv8zJWPtBSW0V7Gg9g8rkmhI1Kfs3c=
|
modernc.org/tcl v1.15.2/go.mod h1:3+k/ZaEbKrC8ePv8zJWPtBSW0V7Gg9g8rkmhI1Kfs3c=
|
||||||
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
|
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
|
||||||
|
|||||||
37
pkg/formatters/duration.go
Normal file
37
pkg/formatters/duration.go
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
package formatters
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FormatDuration takes a duration and returns a human-readable duration string.
|
||||||
|
// For example: 1928371 seconds -> "22d 7h 39m 31s"
|
||||||
|
func FormatDuration(d time.Duration) string {
|
||||||
|
if d == 0 {
|
||||||
|
return "N/A"
|
||||||
|
}
|
||||||
|
|
||||||
|
var parts []string
|
||||||
|
|
||||||
|
days := int(d.Hours()) / 24
|
||||||
|
hours := int(d.Hours()) % 24
|
||||||
|
minutes := int(d.Minutes()) % 60
|
||||||
|
seconds := int(d.Seconds()) % 60
|
||||||
|
|
||||||
|
if days > 0 {
|
||||||
|
parts = append(parts, fmt.Sprintf("%dd", days))
|
||||||
|
}
|
||||||
|
if hours > 0 {
|
||||||
|
parts = append(parts, fmt.Sprintf("%dh", hours))
|
||||||
|
}
|
||||||
|
if minutes > 0 {
|
||||||
|
parts = append(parts, fmt.Sprintf("%dm", minutes))
|
||||||
|
}
|
||||||
|
if seconds > 0 {
|
||||||
|
parts = append(parts, fmt.Sprintf("%ds", seconds))
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.Join(parts, " ")
|
||||||
|
}
|
||||||
45
pkg/formatters/numbers.go
Normal file
45
pkg/formatters/numbers.go
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
package formatters
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FormatNumber takes an int64 and returns a human-readable string.
|
||||||
|
// For example: 19823 -> "19.8k", 1500000 -> "1.5M"
|
||||||
|
func FormatNumber(input int64) string {
|
||||||
|
if input == 0 {
|
||||||
|
return "0"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle Negative
|
||||||
|
negative := input < 0
|
||||||
|
if negative {
|
||||||
|
input = -input
|
||||||
|
}
|
||||||
|
|
||||||
|
abbreviations := []string{"", "k", "M", "B", "T"}
|
||||||
|
abbrevIndex := int(math.Log10(float64(input)) / 3)
|
||||||
|
|
||||||
|
// Bounds Check
|
||||||
|
if abbrevIndex >= len(abbreviations) {
|
||||||
|
abbrevIndex = len(abbreviations) - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
scaledNumber := float64(input) / math.Pow(10, float64(abbrevIndex*3))
|
||||||
|
|
||||||
|
var result string
|
||||||
|
if scaledNumber >= 100 {
|
||||||
|
result = fmt.Sprintf("%.0f%s", scaledNumber, abbreviations[abbrevIndex])
|
||||||
|
} else if scaledNumber >= 10 {
|
||||||
|
result = fmt.Sprintf("%.1f%s", scaledNumber, abbreviations[abbrevIndex])
|
||||||
|
} else {
|
||||||
|
result = fmt.Sprintf("%.2f%s", scaledNumber, abbreviations[abbrevIndex])
|
||||||
|
}
|
||||||
|
|
||||||
|
if negative {
|
||||||
|
result = "-" + result
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
13
pkg/ptr/ptr.go
Normal file
13
pkg/ptr/ptr.go
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
package ptr
|
||||||
|
|
||||||
|
func Of[T any](v T) *T {
|
||||||
|
return &v
|
||||||
|
}
|
||||||
|
|
||||||
|
func Deref[T any](v *T) T {
|
||||||
|
var zeroT T
|
||||||
|
if v == nil {
|
||||||
|
return zeroT
|
||||||
|
}
|
||||||
|
return *v
|
||||||
|
}
|
||||||
17
pkg/sliceutils/sliceutils.go
Normal file
17
pkg/sliceutils/sliceutils.go
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package sliceutils
|
||||||
|
|
||||||
|
func First[T any](s []T) (T, bool) {
|
||||||
|
if len(s) == 0 {
|
||||||
|
var zeroT T
|
||||||
|
return zeroT, false
|
||||||
|
}
|
||||||
|
return s[0], true
|
||||||
|
}
|
||||||
|
|
||||||
|
func Map[R, I any](s []I, f func(I) R) []R {
|
||||||
|
r := make([]R, 0, len(s))
|
||||||
|
for _, v := range s {
|
||||||
|
r = append(r, f(v))
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
18
pkg/utils/utils.go
Normal file
18
pkg/utils/utils.go
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
func Ternary[T any](cond bool, tVal, fVal T) T {
|
||||||
|
if cond {
|
||||||
|
return tVal
|
||||||
|
}
|
||||||
|
return fVal
|
||||||
|
}
|
||||||
|
|
||||||
|
func FirstNonZero[T comparable](v ...T) T {
|
||||||
|
var zero T
|
||||||
|
for _, val := range v {
|
||||||
|
if val != zero {
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return zero
|
||||||
|
}
|
||||||
@@ -32,7 +32,7 @@ func parseAnnasArchive(body io.ReadCloser) ([]SearchItem, error) {
|
|||||||
|
|
||||||
// Normalize Results
|
// Normalize Results
|
||||||
var allEntries []SearchItem
|
var allEntries []SearchItem
|
||||||
doc.Find("form > div.w-full > div.w-full > div > div.justify-center").Each(func(ix int, rawBook *goquery.Selection) {
|
doc.Find("#aarecord-list > div.justify-center").Each(func(ix int, rawBook *goquery.Selection) {
|
||||||
rawBook = getAnnasArchiveBookSelection(rawBook)
|
rawBook = getAnnasArchiveBookSelection(rawBook)
|
||||||
|
|
||||||
// Parse Details
|
// Parse Details
|
||||||
@@ -44,29 +44,19 @@ func parseAnnasArchive(body io.ReadCloser) ([]SearchItem, error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
language := detailsSplit[0]
|
|
||||||
fileType := detailsSplit[1]
|
|
||||||
fileSize := detailsSplit[3]
|
|
||||||
|
|
||||||
// Get Title & Author
|
|
||||||
title := rawBook.Find("h3").Text()
|
|
||||||
author := rawBook.Find("div:nth-child(2) > div:nth-child(4)").Text()
|
|
||||||
|
|
||||||
// Parse MD5
|
// Parse MD5
|
||||||
itemHref, _ := rawBook.Find("a").Attr("href")
|
itemHref, _ := rawBook.Find("a").Attr("href")
|
||||||
hrefArray := strings.Split(itemHref, "/")
|
hrefArray := strings.Split(itemHref, "/")
|
||||||
id := hrefArray[len(hrefArray)-1]
|
id := hrefArray[len(hrefArray)-1]
|
||||||
|
|
||||||
item := SearchItem{
|
allEntries = append(allEntries, SearchItem{
|
||||||
ID: id,
|
ID: id,
|
||||||
Title: title,
|
Title: rawBook.Find("h3").First().Text(),
|
||||||
Author: author,
|
Author: rawBook.Find("div:nth-child(2) > div:nth-child(4)").First().Text(),
|
||||||
Language: language,
|
Language: detailsSplit[0],
|
||||||
FileType: fileType,
|
FileType: detailsSplit[1],
|
||||||
FileSize: fileSize,
|
FileSize: detailsSplit[3],
|
||||||
}
|
})
|
||||||
|
|
||||||
allEntries = append(allEntries, item)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// Return Results
|
// Return Results
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ func getLibGenDownloadURL(md5 string, _ Source) ([]string, error) {
|
|||||||
// Return Download URL
|
// Return Download URL
|
||||||
downloadPath, exists := doc.Find("body > table > tbody > tr > td > a").Attr("href")
|
downloadPath, exists := doc.Find("body > table > tbody > tr > td > a").Attr("href")
|
||||||
if !exists {
|
if !exists {
|
||||||
return nil, fmt.Errorf("Download URL not found")
|
return nil, fmt.Errorf("download URL not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Possible Funky URL
|
// Possible Funky URL
|
||||||
@@ -37,10 +37,10 @@ func getLibraryDownloadURL(md5 string, source Source) ([]string, error) {
|
|||||||
// Derive Info URL
|
// Derive Info URL
|
||||||
var infoURL string
|
var infoURL string
|
||||||
switch source {
|
switch source {
|
||||||
case SOURCE_LIBGEN_FICTION, SOURCE_ANNAS_ARCHIVE:
|
case SOURCE_LIBGEN, SOURCE_ANNAS_ARCHIVE:
|
||||||
infoURL = "http://library.lol/fiction/" + md5
|
infoURL = "http://library.lol/fiction/" + md5
|
||||||
case SOURCE_LIBGEN_NON_FICTION:
|
// case SOURCE_LIBGEN_NON_FICTION:
|
||||||
infoURL = "http://library.lol/main/" + md5
|
// infoURL = "http://library.lol/main/" + md5
|
||||||
default:
|
default:
|
||||||
return nil, errors.New("invalid source")
|
return nil, errors.New("invalid source")
|
||||||
}
|
}
|
||||||
@@ -62,7 +62,7 @@ func getLibraryDownloadURL(md5 string, source Source) ([]string, error) {
|
|||||||
// downloadURL, _ := doc.Find("#download [href*=cloudflare]").Attr("href")
|
// downloadURL, _ := doc.Find("#download [href*=cloudflare]").Attr("href")
|
||||||
downloadURL, exists := doc.Find("#download h2 a").Attr("href")
|
downloadURL, exists := doc.Find("#download h2 a").Attr("href")
|
||||||
if !exists {
|
if !exists {
|
||||||
return nil, errors.New("Download URL not found")
|
return nil, errors.New("download URL not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
return []string{downloadURL}, nil
|
return []string{downloadURL}, nil
|
||||||
|
|||||||
131
search/libgen.go
131
search/libgen.go
@@ -1,89 +1,44 @@
|
|||||||
package search
|
package search
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/PuerkitoBio/goquery"
|
"github.com/PuerkitoBio/goquery"
|
||||||
)
|
)
|
||||||
|
|
||||||
func searchLibGenFiction(query string) ([]SearchItem, error) {
|
const LIBGEN_SEARCH_URL = "https://%s/index.php?req=ext:epub+%s&gmode=on"
|
||||||
searchURL := "https://libgen.is/fiction/?q=%s&language=English&format=epub"
|
|
||||||
url := fmt.Sprintf(searchURL, url.QueryEscape(query))
|
var libgenDomains []string = []string{
|
||||||
body, err := getPage(url)
|
"libgen.vg",
|
||||||
if err != nil {
|
"libgen.is",
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return parseLibGenFiction(body)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseLibGenFiction(body io.ReadCloser) ([]SearchItem, error) {
|
func searchLibGen(query string) ([]SearchItem, error) {
|
||||||
// Parse
|
var allErrors []error
|
||||||
defer body.Close()
|
|
||||||
doc, err := goquery.NewDocumentFromReader(body)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Normalize Results
|
for _, domain := range libgenDomains {
|
||||||
var allEntries []SearchItem
|
url := fmt.Sprintf(LIBGEN_SEARCH_URL, domain, url.QueryEscape(query))
|
||||||
doc.Find("table.catalog tbody > tr").Each(func(ix int, rawBook *goquery.Selection) {
|
body, err := getPage(url)
|
||||||
|
if err != nil {
|
||||||
// Parse File Details
|
allErrors = append(allErrors, err)
|
||||||
fileItem := rawBook.Find("td:nth-child(5)")
|
continue
|
||||||
fileDesc := fileItem.Text()
|
|
||||||
fileDescSplit := strings.Split(fileDesc, "/")
|
|
||||||
fileType := strings.ToLower(strings.TrimSpace(fileDescSplit[0]))
|
|
||||||
fileSize := strings.TrimSpace(fileDescSplit[1])
|
|
||||||
|
|
||||||
// Parse Upload Date
|
|
||||||
uploadedRaw, _ := fileItem.Attr("title")
|
|
||||||
uploadedDateRaw := strings.Split(uploadedRaw, "Uploaded at ")[1]
|
|
||||||
uploadDate, _ := time.Parse("2006-01-02 15:04:05", uploadedDateRaw)
|
|
||||||
|
|
||||||
// Parse MD5
|
|
||||||
editHref, _ := rawBook.Find("td:nth-child(7) a").Attr("href")
|
|
||||||
hrefArray := strings.Split(editHref, "/")
|
|
||||||
id := hrefArray[len(hrefArray)-1]
|
|
||||||
|
|
||||||
// Parse Other Details
|
|
||||||
title := rawBook.Find("td:nth-child(3) p a").Text()
|
|
||||||
author := rawBook.Find(".catalog_authors li a").Text()
|
|
||||||
language := rawBook.Find("td:nth-child(4)").Text()
|
|
||||||
series := rawBook.Find("td:nth-child(2)").Text()
|
|
||||||
|
|
||||||
item := SearchItem{
|
|
||||||
ID: id,
|
|
||||||
Title: title,
|
|
||||||
Author: author,
|
|
||||||
Series: series,
|
|
||||||
Language: language,
|
|
||||||
FileType: fileType,
|
|
||||||
FileSize: fileSize,
|
|
||||||
UploadDate: uploadDate.Format(time.RFC3339),
|
|
||||||
}
|
}
|
||||||
|
results, err := parseLibGen(body)
|
||||||
allEntries = append(allEntries, item)
|
if err != nil {
|
||||||
})
|
allErrors = append(allErrors, err)
|
||||||
|
continue
|
||||||
// Return Results
|
}
|
||||||
return allEntries, nil
|
return results, nil
|
||||||
}
|
|
||||||
|
|
||||||
func searchLibGenNonFiction(query string) ([]SearchItem, error) {
|
|
||||||
searchURL := "https://libgen.is/search.php?req=%s"
|
|
||||||
url := fmt.Sprintf(searchURL, url.QueryEscape(query))
|
|
||||||
body, err := getPage(url)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
return parseLibGenNonFiction(body)
|
|
||||||
|
return nil, fmt.Errorf("could not query libgen: %w", errors.Join(allErrors...))
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseLibGenNonFiction(body io.ReadCloser) ([]SearchItem, error) {
|
func parseLibGen(body io.ReadCloser) ([]SearchItem, error) {
|
||||||
// Parse
|
// Parse
|
||||||
defer body.Close()
|
defer body.Close()
|
||||||
doc, err := goquery.NewDocumentFromReader(body)
|
doc, err := goquery.NewDocumentFromReader(body)
|
||||||
@@ -93,35 +48,25 @@ func parseLibGenNonFiction(body io.ReadCloser) ([]SearchItem, error) {
|
|||||||
|
|
||||||
// Normalize Results
|
// Normalize Results
|
||||||
var allEntries []SearchItem
|
var allEntries []SearchItem
|
||||||
doc.Find("table.c tbody > tr:nth-child(n + 2)").Each(func(ix int, rawBook *goquery.Selection) {
|
doc.Find("#tablelibgen tbody > tr").Each(func(ix int, rawBook *goquery.Selection) {
|
||||||
|
|
||||||
// Parse Type & Size
|
|
||||||
fileSize := strings.ToLower(strings.TrimSpace(rawBook.Find("td:nth-child(8)").Text()))
|
|
||||||
fileType := strings.ToLower(strings.TrimSpace(rawBook.Find("td:nth-child(9)").Text()))
|
|
||||||
|
|
||||||
// Parse MD5
|
// Parse MD5
|
||||||
titleRaw := rawBook.Find("td:nth-child(3) [id]")
|
linksRaw := rawBook.Find("td:nth-child(9) a")
|
||||||
editHref, _ := titleRaw.Attr("href")
|
linksHref, _ := linksRaw.Attr("href")
|
||||||
hrefArray := strings.Split(editHref, "?md5=")
|
hrefArray := strings.Split(linksHref, "?md5=")
|
||||||
|
if len(hrefArray) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
id := hrefArray[1]
|
id := hrefArray[1]
|
||||||
|
|
||||||
// Parse Other Details
|
allEntries = append(allEntries, SearchItem{
|
||||||
title := titleRaw.Text()
|
|
||||||
author := rawBook.Find("td:nth-child(2)").Text()
|
|
||||||
language := rawBook.Find("td:nth-child(7)").Text()
|
|
||||||
series := rawBook.Find("td:nth-child(3) [href*='column=series']").Text()
|
|
||||||
|
|
||||||
item := SearchItem{
|
|
||||||
ID: id,
|
ID: id,
|
||||||
Title: title,
|
Title: rawBook.Find("td:nth-child(1) > a").First().Text(),
|
||||||
Author: author,
|
Author: rawBook.Find("td:nth-child(2)").Text(),
|
||||||
Series: series,
|
Series: rawBook.Find("td:nth-child(1) > b").Text(),
|
||||||
Language: language,
|
Language: rawBook.Find("td:nth-child(5)").Text(),
|
||||||
FileType: fileType,
|
FileType: strings.ToLower(strings.TrimSpace(rawBook.Find("td:nth-child(8)").Text())),
|
||||||
FileSize: fileSize,
|
FileSize: strings.ToLower(strings.TrimSpace(rawBook.Find("td:nth-child(7)").Text())),
|
||||||
}
|
})
|
||||||
|
|
||||||
allEntries = append(allEntries, item)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// Return Results
|
// Return Results
|
||||||
|
|||||||
@@ -25,9 +25,8 @@ const (
|
|||||||
type Source string
|
type Source string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
SOURCE_ANNAS_ARCHIVE Source = "Annas Archive"
|
SOURCE_ANNAS_ARCHIVE Source = "Annas Archive"
|
||||||
SOURCE_LIBGEN_FICTION Source = "LibGen Fiction"
|
SOURCE_LIBGEN Source = "LibGen"
|
||||||
SOURCE_LIBGEN_NON_FICTION Source = "LibGen Non-fiction"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type SearchItem struct {
|
type SearchItem struct {
|
||||||
@@ -45,9 +44,8 @@ type searchFunc func(query string) (searchResults []SearchItem, err error)
|
|||||||
type downloadFunc func(md5 string, source Source) (downloadURL []string, err error)
|
type downloadFunc func(md5 string, source Source) (downloadURL []string, err error)
|
||||||
|
|
||||||
var searchDefs = map[Source]searchFunc{
|
var searchDefs = map[Source]searchFunc{
|
||||||
SOURCE_ANNAS_ARCHIVE: searchAnnasArchive,
|
SOURCE_ANNAS_ARCHIVE: searchAnnasArchive,
|
||||||
SOURCE_LIBGEN_FICTION: searchLibGenFiction,
|
SOURCE_LIBGEN: searchLibGen,
|
||||||
SOURCE_LIBGEN_NON_FICTION: searchLibGenNonFiction,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var downloadFuncs = []downloadFunc{
|
var downloadFuncs = []downloadFunc{
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"net/http"
|
"net/http"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -52,12 +53,14 @@ func (s *server) Start() {
|
|||||||
ticker := time.NewTicker(15 * time.Minute)
|
ticker := time.NewTicker(15 * time.Minute)
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
|
|
||||||
|
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(5*time.Minute))
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ticker.C:
|
case <-ticker.C:
|
||||||
s.runScheduledTasks()
|
s.runScheduledTasks(ctx)
|
||||||
case <-s.done:
|
case <-s.done:
|
||||||
log.Info("Stopping task runner...")
|
log.Info("Stopping task runner...")
|
||||||
|
cancel()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -81,9 +84,9 @@ func (s *server) Stop() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Run normal scheduled tasks
|
// Run normal scheduled tasks
|
||||||
func (s *server) runScheduledTasks() {
|
func (s *server) runScheduledTasks(ctx context.Context) {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
if err := s.db.CacheTempTables(); err != nil {
|
if err := s.db.CacheTempTables(ctx); err != nil {
|
||||||
log.Warn("Refreshing temp table cache failed: ", err)
|
log.Warn("Refreshing temp table cache failed: ", err)
|
||||||
}
|
}
|
||||||
log.Debug("Completed in: ", time.Since(start))
|
log.Debug("Completed in: ", time.Since(start))
|
||||||
|
|||||||
13
shell.nix
13
shell.nix
@@ -1,13 +0,0 @@
|
|||||||
{ pkgs ? import <nixpkgs> { } }:
|
|
||||||
|
|
||||||
pkgs.mkShell {
|
|
||||||
packages = with pkgs; [
|
|
||||||
go
|
|
||||||
nodejs
|
|
||||||
nodePackages.tailwindcss
|
|
||||||
python311Packages.grip
|
|
||||||
];
|
|
||||||
shellHook = ''
|
|
||||||
export PATH=$PATH:~/go/bin
|
|
||||||
'';
|
|
||||||
}
|
|
||||||
@@ -35,9 +35,8 @@
|
|||||||
id="source"
|
id="source"
|
||||||
name="source"
|
name="source"
|
||||||
>
|
>
|
||||||
|
<option value="LibGen">Library Genesis</option>
|
||||||
<option value="Annas Archive">Annas Archive</option>
|
<option value="Annas Archive">Annas Archive</option>
|
||||||
<option value="LibGen Fiction">LibGen Fiction</option>
|
|
||||||
<option value="LibGen Non-fiction">LibGen Non-fiction</option>
|
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="lg:w-60">
|
<div class="lg:w-60">
|
||||||
@@ -133,7 +132,8 @@
|
|||||||
</form>
|
</form>
|
||||||
</td>
|
</td>
|
||||||
<td class="p-3 border-b border-gray-200">
|
<td class="p-3 border-b border-gray-200">
|
||||||
{{ $item.Author }} - {{ $item.Title }}
|
{{ $item.Author }} -
|
||||||
|
{{ $item.Title }}
|
||||||
</td>
|
</td>
|
||||||
<td class="p-3 border-b border-gray-200">
|
<td class="p-3 border-b border-gray-200">
|
||||||
<p>{{ or $item.Series "N/A" }}</p>
|
<p>{{ or $item.Series "N/A" }}</p>
|
||||||
|
|||||||
Reference in New Issue
Block a user