mirror of
https://github.com/Forceu/Gokapi.git
synced 2026-05-03 21:10:50 -05:00
Store upload defaults locally (#214), breaking API changes
This commit is contained in:
@@ -74,10 +74,6 @@ func Migrate(configOld, configNew models.DbConnection) {
|
||||
dbNew.SaveHotlink(file)
|
||||
}
|
||||
}
|
||||
defaults, ok := dbOld.GetUploadDefaults()
|
||||
if ok {
|
||||
dbNew.SaveUploadDefaults(defaults)
|
||||
}
|
||||
dbOld.Close()
|
||||
dbNew.Close()
|
||||
}
|
||||
@@ -226,30 +222,6 @@ func DeleteAllSessions() {
|
||||
db.DeleteAllSessions()
|
||||
}
|
||||
|
||||
// Upload Defaults Section
|
||||
|
||||
// GetUploadDefaults returns the last used setting for amount of downloads allowed, last expiry in days and
|
||||
// a password for the file
|
||||
func GetUploadDefaults() models.LastUploadValues {
|
||||
values, ok := db.GetUploadDefaults()
|
||||
if ok {
|
||||
return values
|
||||
}
|
||||
defaultValues := models.LastUploadValues{
|
||||
Downloads: 1,
|
||||
TimeExpiry: 14,
|
||||
Password: "",
|
||||
UnlimitedDownload: false,
|
||||
UnlimitedTime: false,
|
||||
}
|
||||
return defaultValues
|
||||
}
|
||||
|
||||
// SaveUploadDefaults saves the last used setting for an upload
|
||||
func SaveUploadDefaults(values models.LastUploadValues) {
|
||||
db.SaveUploadDefaults(values)
|
||||
}
|
||||
|
||||
// Upload Status Section
|
||||
|
||||
// GetAllUploadStatus returns all UploadStatus values from the past 24 hours
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/alicebob/miniredis/v2"
|
||||
"github.com/forceu/gokapi/internal/configuration/database/dbabstraction"
|
||||
"github.com/forceu/gokapi/internal/models"
|
||||
@@ -101,26 +100,6 @@ func TestSessions(t *testing.T) {
|
||||
runAllTypesCompareTwoOutputs(t, func() (any, any) { return GetSession("newsession") }, models.Session{}, false)
|
||||
}
|
||||
|
||||
func TestUploadDefaults(t *testing.T) {
|
||||
defaultValues := models.LastUploadValues{
|
||||
Downloads: 1,
|
||||
TimeExpiry: 14,
|
||||
Password: "",
|
||||
UnlimitedDownload: false,
|
||||
UnlimitedTime: false,
|
||||
}
|
||||
runAllTypesCompareOutput(t, func() any { return GetUploadDefaults() }, defaultValues)
|
||||
newValues := models.LastUploadValues{
|
||||
Downloads: 5,
|
||||
TimeExpiry: 20,
|
||||
Password: "123",
|
||||
UnlimitedDownload: true,
|
||||
UnlimitedTime: true,
|
||||
}
|
||||
runAllTypesNoOutput(t, func() { SaveUploadDefaults(newValues) })
|
||||
runAllTypesCompareOutput(t, func() any { return GetUploadDefaults() }, newValues)
|
||||
}
|
||||
|
||||
func TestUploadStatus(t *testing.T) {
|
||||
runAllTypesCompareTwoOutputs(t, func() (any, any) { return GetUploadStatus("newstatus") }, models.UploadStatus{}, false)
|
||||
runAllTypesCompareOutput(t, func() any { return GetAllUploadStatus() }, []models.UploadStatus{})
|
||||
@@ -288,7 +267,6 @@ func TestMigration(t *testing.T) {
|
||||
dbOld.SaveMetaData(testFile)
|
||||
dbOld.SaveHotlink(testFile)
|
||||
dbOld.SaveApiKey(models.ApiKey{Id: "api123"})
|
||||
dbOld.SaveUploadDefaults(models.LastUploadValues{Password: "pw123"})
|
||||
dbOld.SaveHotlink(testFile)
|
||||
dbOld.Close()
|
||||
|
||||
@@ -300,10 +278,6 @@ func TestMigration(t *testing.T) {
|
||||
test.IsEqualBool(t, ok, true)
|
||||
_, ok = dbNew.GetApiKey("api123")
|
||||
test.IsEqualBool(t, ok, true)
|
||||
defaults, ok := dbNew.GetUploadDefaults()
|
||||
test.IsEqualBool(t, ok, true)
|
||||
fmt.Printf("defaults: %+v\n", defaults)
|
||||
test.IsEqualString(t, defaults.Password, "pw123")
|
||||
_, ok = dbNew.GetMetaDataById("file1234")
|
||||
test.IsEqualBool(t, ok, true)
|
||||
}
|
||||
|
||||
@@ -82,12 +82,6 @@ type Database interface {
|
||||
// DeleteAllSessions logs all users out
|
||||
DeleteAllSessions()
|
||||
|
||||
// GetUploadDefaults returns the last used setting for amount of downloads allowed, last expiry in days and
|
||||
// a password for the file
|
||||
GetUploadDefaults() (models.LastUploadValues, bool)
|
||||
// SaveUploadDefaults saves the last used setting for an upload
|
||||
SaveUploadDefaults(values models.LastUploadValues)
|
||||
// GetUploadStatus returns a models.UploadStatus from the ID passed or false if the id is not valid
|
||||
GetUploadStatus(id string) (models.UploadStatus, bool)
|
||||
// GetAllUploadStatus returns all UploadStatus values from the past 24 hours
|
||||
GetAllUploadStatus() []models.UploadStatus
|
||||
|
||||
@@ -68,8 +68,6 @@ func TestMigration(t *testing.T) {
|
||||
test.IsEqualBool(t, ok, true)
|
||||
_, ok = database.GetApiKey("validkey")
|
||||
test.IsEqualBool(t, ok, true)
|
||||
defaults := database.GetUploadDefaults()
|
||||
test.IsEqualString(t, defaults.Password, "123")
|
||||
_, ok = database.GetMetaDataById("Wzol7LyY2QVczXynJtVo")
|
||||
test.IsEqualBool(t, ok, true)
|
||||
}
|
||||
|
||||
@@ -331,25 +331,6 @@ func TestSession(t *testing.T) {
|
||||
test.IsEqualBool(t, ok, false)
|
||||
}
|
||||
|
||||
func TestUploadDefaults(t *testing.T) {
|
||||
defaults, ok := dbInstance.GetUploadDefaults()
|
||||
test.IsEqualBool(t, ok, false)
|
||||
dbInstance.SaveUploadDefaults(models.LastUploadValues{
|
||||
Downloads: 20,
|
||||
TimeExpiry: 30,
|
||||
Password: "abcd",
|
||||
UnlimitedDownload: true,
|
||||
UnlimitedTime: true,
|
||||
})
|
||||
defaults, ok = dbInstance.GetUploadDefaults()
|
||||
test.IsEqualBool(t, ok, true)
|
||||
test.IsEqualInt(t, defaults.Downloads, 20)
|
||||
test.IsEqualInt(t, defaults.TimeExpiry, 30)
|
||||
test.IsEqualString(t, defaults.Password, "abcd")
|
||||
test.IsEqualBool(t, defaults.UnlimitedDownload, true)
|
||||
test.IsEqualBool(t, defaults.UnlimitedTime, true)
|
||||
}
|
||||
|
||||
func TestUploadStatus(t *testing.T) {
|
||||
allStatus := dbInstance.GetAllUploadStatus()
|
||||
test.IsEqualInt(t, len(allStatus), 0)
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
package redis
|
||||
|
||||
import (
|
||||
"github.com/forceu/gokapi/internal/helper"
|
||||
"github.com/forceu/gokapi/internal/models"
|
||||
redigo "github.com/gomodule/redigo/redis"
|
||||
)
|
||||
|
||||
const (
|
||||
idUploadDefaults = "uploadDefaults"
|
||||
)
|
||||
|
||||
// GetUploadDefaults returns the last used setting for amount of downloads allowed, last expiry in days and
|
||||
// a password for the file
|
||||
func (p DatabaseProvider) GetUploadDefaults() (models.LastUploadValues, bool) {
|
||||
var result models.LastUploadValues
|
||||
values, ok := p.getHashMap(idUploadDefaults)
|
||||
if !ok {
|
||||
return models.LastUploadValues{}, false
|
||||
}
|
||||
|
||||
err := redigo.ScanStruct(values, &result)
|
||||
helper.Check(err)
|
||||
return result, true
|
||||
}
|
||||
|
||||
// SaveUploadDefaults saves the last used setting for an upload
|
||||
func (p DatabaseProvider) SaveUploadDefaults(values models.LastUploadValues) {
|
||||
p.setHashMap(p.buildArgs(idUploadDefaults).AddFlat(values))
|
||||
}
|
||||
@@ -253,27 +253,8 @@ func TestSession(t *testing.T) {
|
||||
test.IsEqualBool(t, ok, false)
|
||||
}
|
||||
|
||||
func TestUploadDefaults(t *testing.T) {
|
||||
defaults, ok := dbInstance.GetUploadDefaults()
|
||||
test.IsEqualBool(t, ok, false)
|
||||
dbInstance.SaveUploadDefaults(models.LastUploadValues{
|
||||
Downloads: 20,
|
||||
TimeExpiry: 30,
|
||||
Password: "abcd",
|
||||
UnlimitedDownload: true,
|
||||
UnlimitedTime: true,
|
||||
})
|
||||
defaults, ok = dbInstance.GetUploadDefaults()
|
||||
test.IsEqualBool(t, ok, true)
|
||||
test.IsEqualInt(t, defaults.Downloads, 20)
|
||||
test.IsEqualInt(t, defaults.TimeExpiry, 30)
|
||||
test.IsEqualString(t, defaults.Password, "abcd")
|
||||
test.IsEqualBool(t, defaults.UnlimitedDownload, true)
|
||||
test.IsEqualBool(t, defaults.UnlimitedTime, true)
|
||||
}
|
||||
|
||||
func TestGarbageCollectionUploads(t *testing.T) {
|
||||
orgiginalFunc := currentTime
|
||||
originalFunc := currentTime
|
||||
currentTime = func() time.Time {
|
||||
return time.Now().Add(-25 * time.Hour)
|
||||
}
|
||||
@@ -297,7 +278,7 @@ func TestGarbageCollectionUploads(t *testing.T) {
|
||||
ChunkId: "ctodelete5",
|
||||
CurrentStatus: 1,
|
||||
})
|
||||
currentTime = orgiginalFunc
|
||||
currentTime = originalFunc
|
||||
|
||||
dbInstance.SaveUploadStatus(models.UploadStatus{
|
||||
ChunkId: "ctokeep1",
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
package sqlite
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"github.com/forceu/gokapi/internal/helper"
|
||||
"github.com/forceu/gokapi/internal/models"
|
||||
)
|
||||
|
||||
type schemaUploadConfig struct {
|
||||
Id int64
|
||||
Downloads int
|
||||
TimeExpiry int
|
||||
Password string
|
||||
UnlimitedDownloads int
|
||||
UnlimitedTime int
|
||||
}
|
||||
|
||||
// GetUploadDefaults returns the last used setting for amount of downloads allowed, last expiry in days and
|
||||
// a password for the file
|
||||
func (p DatabaseProvider) GetUploadDefaults() (models.LastUploadValues, bool) {
|
||||
rowResult := schemaUploadConfig{}
|
||||
row := p.sqliteDb.QueryRow("SELECT * FROM UploadConfig WHERE id = 1")
|
||||
err := row.Scan(&rowResult.Id, &rowResult.Downloads, &rowResult.TimeExpiry, &rowResult.Password, &rowResult.UnlimitedDownloads, &rowResult.UnlimitedTime)
|
||||
if err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return models.LastUploadValues{}, false
|
||||
}
|
||||
helper.Check(err)
|
||||
return models.LastUploadValues{}, false
|
||||
}
|
||||
|
||||
result := models.LastUploadValues{
|
||||
Downloads: rowResult.Downloads,
|
||||
TimeExpiry: rowResult.TimeExpiry,
|
||||
Password: rowResult.Password,
|
||||
UnlimitedDownload: rowResult.UnlimitedDownloads == 1,
|
||||
UnlimitedTime: rowResult.UnlimitedTime == 1,
|
||||
}
|
||||
return result, true
|
||||
}
|
||||
|
||||
// SaveUploadDefaults saves the last used setting for an upload
|
||||
func (p DatabaseProvider) SaveUploadDefaults(values models.LastUploadValues) {
|
||||
|
||||
newData := schemaUploadConfig{
|
||||
Downloads: values.Downloads,
|
||||
TimeExpiry: values.TimeExpiry,
|
||||
Password: values.Password,
|
||||
}
|
||||
if values.UnlimitedDownload {
|
||||
newData.UnlimitedDownloads = 1
|
||||
}
|
||||
if values.UnlimitedTime {
|
||||
newData.UnlimitedTime = 1
|
||||
}
|
||||
|
||||
_, err := p.sqliteDb.Exec("INSERT OR REPLACE INTO UploadConfig (id, Downloads,TimeExpiry,Password,UnlimitedDownloads,UnlimitedTime) VALUES (1, ?, ?, ?, ?, ?)",
|
||||
newData.Downloads, newData.TimeExpiry, newData.Password, newData.UnlimitedDownloads, newData.UnlimitedTime)
|
||||
helper.Check(err)
|
||||
}
|
||||
@@ -36,15 +36,6 @@ type Encryption struct {
|
||||
ChecksumSalt string
|
||||
}
|
||||
|
||||
// LastUploadValues is used to save the last used values for uploads in the database
|
||||
type LastUploadValues struct {
|
||||
Downloads int `redis:"downloads"`
|
||||
TimeExpiry int `redis:"time_expiry"`
|
||||
Password string `redis:"password"`
|
||||
UnlimitedDownload bool `redis:"unlimited_download"`
|
||||
UnlimitedTime bool `redis:"unlimited_time"`
|
||||
}
|
||||
|
||||
// ToJson returns an idented JSon representation
|
||||
func (c Configuration) ToJson() []byte {
|
||||
result, err := json.MarshalIndent(c, "", " ")
|
||||
|
||||
@@ -53,13 +53,6 @@ func Create(initFiles bool) {
|
||||
}
|
||||
database.Connect(config)
|
||||
writeTestSessions()
|
||||
database.SaveUploadDefaults(models.LastUploadValues{
|
||||
Downloads: 3,
|
||||
TimeExpiry: 20,
|
||||
Password: "123",
|
||||
UnlimitedDownload: false,
|
||||
UnlimitedTime: false,
|
||||
})
|
||||
writeTestFiles()
|
||||
database.SaveHotlink(models.File{Id: "n1tSTAGj8zan9KaT4u6p", HotlinkId: "PhSs6mFtf8O5YGlLMfNw9rYXx9XRNkzCnJZpQBi7inunv3Z4A.jpg", ExpireAt: time.Now().Add(time.Hour).Unix()})
|
||||
writeApiKeys()
|
||||
|
||||
@@ -558,28 +558,23 @@ type e2ESetupView struct {
|
||||
|
||||
// UploadView contains parameters for the admin menu template
|
||||
type UploadView struct {
|
||||
Items []models.FileApiOutput
|
||||
ApiKeys []models.ApiKey
|
||||
ServerUrl string
|
||||
DefaultPassword string
|
||||
Logs string
|
||||
PublicName string
|
||||
SystemKey string
|
||||
IsAdminView bool
|
||||
IsDownloadView bool
|
||||
IsApiView bool
|
||||
IsLogoutAvailable bool
|
||||
DefaultUnlimitedDownload bool
|
||||
DefaultUnlimitedTime bool
|
||||
EndToEndEncryption bool
|
||||
IncludeFilename bool
|
||||
MaxFileSize int
|
||||
DefaultDownloads int
|
||||
DefaultExpiry int
|
||||
ActiveView int
|
||||
ChunkSize int
|
||||
MaxParallelUploads int
|
||||
TimeNow int64
|
||||
Items []models.FileApiOutput
|
||||
ApiKeys []models.ApiKey
|
||||
ServerUrl string
|
||||
Logs string
|
||||
PublicName string
|
||||
SystemKey string
|
||||
IsAdminView bool
|
||||
IsDownloadView bool
|
||||
IsApiView bool
|
||||
IsLogoutAvailable bool
|
||||
EndToEndEncryption bool
|
||||
IncludeFilename bool
|
||||
MaxFileSize int
|
||||
ActiveView int
|
||||
ChunkSize int
|
||||
MaxParallelUploads int
|
||||
TimeNow int64
|
||||
}
|
||||
|
||||
// ViewMain is the identifier for the main menu
|
||||
@@ -640,12 +635,6 @@ func (u *UploadView) convertGlobalConfig(view int) *UploadView {
|
||||
u.ActiveView = view
|
||||
u.MaxFileSize = config.MaxFileSizeMB
|
||||
u.IsLogoutAvailable = authentication.IsLogoutAvailable()
|
||||
defaultValues := database.GetUploadDefaults()
|
||||
u.DefaultDownloads = defaultValues.Downloads
|
||||
u.DefaultExpiry = defaultValues.TimeExpiry
|
||||
u.DefaultPassword = defaultValues.Password
|
||||
u.DefaultUnlimitedDownload = defaultValues.UnlimitedDownload
|
||||
u.DefaultUnlimitedTime = defaultValues.UnlimitedTime
|
||||
u.EndToEndEncryption = config.Encryption.Level == encryption.EndToEndEncryption
|
||||
u.MaxParallelUploads = config.MaxParallelUploads
|
||||
u.ChunkSize = config.ChunkSize
|
||||
@@ -671,7 +660,7 @@ func uploadChunk(w http.ResponseWriter, r *http.Request) {
|
||||
// If the user is authenticated, this parses the uploaded chunk and stores it
|
||||
func uploadComplete(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
|
||||
err := fileupload.CompleteChunk(w, r, false)
|
||||
err := fileupload.CompleteChunk(w, r)
|
||||
responseError(w, err)
|
||||
}
|
||||
|
||||
|
||||
@@ -481,7 +481,7 @@ func TestPostUpload(t *testing.T) {
|
||||
Key: "filesize",
|
||||
Value: "50",
|
||||
}},
|
||||
RequiredContent: []string{"{\"Result\":\"OK\"", "\"Name\":\"fileupload.jpg\"", "DownloadsRemaining\":3"},
|
||||
RequiredContent: []string{"{\"Result\":\"OK\"", "\"Name\":\"fileupload.jpg\"", "DownloadsRemaining\":1"},
|
||||
ExcludedContent: []string{"\"Id\":\"\"", "HotlinkId\":\"\"", "ErrorMessage"},
|
||||
Cookies: []test.Cookie{{
|
||||
Name: "session_token",
|
||||
|
||||
@@ -289,7 +289,7 @@ func chunkComplete(w http.ResponseWriter, request apiRequest) {
|
||||
return
|
||||
}
|
||||
request.request.Form.Set("chunkid", request.request.Form.Get("uuid"))
|
||||
err = fileupload.CompleteChunk(w, request.request, true)
|
||||
err = fileupload.CompleteChunk(w, request.request)
|
||||
if err != nil {
|
||||
sendError(w, http.StatusBadRequest, err.Error())
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package fileupload
|
||||
|
||||
import (
|
||||
"github.com/forceu/gokapi/internal/configuration"
|
||||
"github.com/forceu/gokapi/internal/configuration/database"
|
||||
"github.com/forceu/gokapi/internal/models"
|
||||
"github.com/forceu/gokapi/internal/storage"
|
||||
"github.com/forceu/gokapi/internal/storage/chunking"
|
||||
@@ -19,7 +18,7 @@ func Process(w http.ResponseWriter, r *http.Request, maxMemory int) error {
|
||||
return err
|
||||
}
|
||||
defer r.MultipartForm.RemoveAll()
|
||||
config, err := parseConfig(r.Form, false)
|
||||
config, err := parseConfig(r.Form)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -63,13 +62,13 @@ func ProcessNewChunk(w http.ResponseWriter, r *http.Request, isApiCall bool) err
|
||||
}
|
||||
|
||||
// CompleteChunk processes a file after all the chunks have been completed
|
||||
func CompleteChunk(w http.ResponseWriter, r *http.Request, isApiCall bool) error {
|
||||
func CompleteChunk(w http.ResponseWriter, r *http.Request) error {
|
||||
err := r.ParseForm()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
chunkId := r.Form.Get("chunkid")
|
||||
config, err := parseConfig(r.Form, !isApiCall)
|
||||
config, err := parseConfig(r.Form)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -86,19 +85,17 @@ func CompleteChunk(w http.ResponseWriter, r *http.Request, isApiCall bool) error
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseConfig(values formOrHeader, setNewDefaults bool) (models.UploadRequest, error) {
|
||||
func parseConfig(values formOrHeader) (models.UploadRequest, error) {
|
||||
allowedDownloads := values.Get("allowedDownloads")
|
||||
expiryDays := values.Get("expiryDays")
|
||||
password := values.Get("password")
|
||||
allowedDownloadsInt, err := strconv.Atoi(allowedDownloads)
|
||||
if err != nil {
|
||||
previousValues := database.GetUploadDefaults()
|
||||
allowedDownloadsInt = previousValues.Downloads
|
||||
allowedDownloadsInt = 1
|
||||
}
|
||||
expiryDaysInt, err := strconv.Atoi(expiryDays)
|
||||
if err != nil {
|
||||
previousValues := database.GetUploadDefaults()
|
||||
expiryDaysInt = previousValues.TimeExpiry
|
||||
expiryDaysInt = 14
|
||||
}
|
||||
|
||||
unlimitedDownload := values.Get("isUnlimitedDownload") == "true"
|
||||
@@ -111,16 +108,6 @@ func parseConfig(values formOrHeader, setNewDefaults bool) (models.UploadRequest
|
||||
unlimitedTime = true
|
||||
}
|
||||
|
||||
if setNewDefaults {
|
||||
values := models.LastUploadValues{
|
||||
Downloads: allowedDownloadsInt,
|
||||
TimeExpiry: expiryDaysInt,
|
||||
Password: password,
|
||||
UnlimitedDownload: unlimitedDownload,
|
||||
UnlimitedTime: unlimitedTime,
|
||||
}
|
||||
database.SaveUploadDefaults(values)
|
||||
}
|
||||
var isEnd2End bool
|
||||
var realSize int64
|
||||
if values.Get("isE2E") == "true" {
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"github.com/forceu/gokapi/internal/configuration"
|
||||
"github.com/forceu/gokapi/internal/configuration/database"
|
||||
"github.com/forceu/gokapi/internal/models"
|
||||
"github.com/forceu/gokapi/internal/test"
|
||||
"github.com/forceu/gokapi/internal/test/testconfiguration"
|
||||
@@ -36,43 +35,38 @@ func TestParseConfig(t *testing.T) {
|
||||
isE2E: "",
|
||||
realSize: "",
|
||||
}
|
||||
config, err := parseConfig(data, false)
|
||||
config, err := parseConfig(data)
|
||||
test.IsNil(t, err)
|
||||
test.IsEqualBool(t, config.IsEndToEndEncrypted, false)
|
||||
test.IsEqualInt64(t, config.RealSize, 0)
|
||||
|
||||
defaults := database.GetUploadDefaults()
|
||||
test.IsEqualInt(t, config.AllowedDownloads, 9)
|
||||
test.IsEqualString(t, config.Password, "123")
|
||||
test.IsEqualInt(t, config.Expiry, 5)
|
||||
test.IsEqualInt(t, defaults.Downloads, 3)
|
||||
|
||||
config, err = parseConfig(data, true)
|
||||
config, err = parseConfig(data)
|
||||
test.IsNil(t, err)
|
||||
defaults = database.GetUploadDefaults()
|
||||
test.IsEqualInt(t, defaults.Downloads, 9)
|
||||
database.SaveUploadDefaults(models.LastUploadValues{Downloads: 3, TimeExpiry: 20})
|
||||
|
||||
data.allowedDownloads = ""
|
||||
data.expiryDays = "invalid"
|
||||
|
||||
config, err = parseConfig(data, false)
|
||||
config, err = parseConfig(data)
|
||||
test.IsNil(t, err)
|
||||
test.IsEqualInt(t, config.AllowedDownloads, 3)
|
||||
test.IsEqualInt(t, config.Expiry, 20)
|
||||
test.IsEqualInt(t, config.AllowedDownloads, 1)
|
||||
test.IsEqualInt(t, config.Expiry, 14)
|
||||
test.IsEqualBool(t, config.UnlimitedTime, false)
|
||||
test.IsEqualBool(t, config.UnlimitedDownload, false)
|
||||
|
||||
data.allowedDownloads = "0"
|
||||
data.expiryDays = "0"
|
||||
config, err = parseConfig(data, false)
|
||||
config, err = parseConfig(data)
|
||||
test.IsNil(t, err)
|
||||
test.IsEqualBool(t, config.UnlimitedTime, true)
|
||||
test.IsEqualBool(t, config.UnlimitedDownload, true)
|
||||
|
||||
data.isE2E = "true"
|
||||
data.realSize = "200"
|
||||
config, err = parseConfig(data, false)
|
||||
config, err = parseConfig(data)
|
||||
test.IsNil(t, err)
|
||||
test.IsEqualBool(t, config.IsEndToEndEncrypted, true)
|
||||
test.IsEqualInt64(t, config.RealSize, 200)
|
||||
@@ -122,12 +116,12 @@ func TestProcessNewChunk(t *testing.T) {
|
||||
|
||||
func TestCompleteChunk(t *testing.T) {
|
||||
w, r := test.GetRecorder("POST", "/uploadComplete", nil, nil, strings.NewReader("invalid§$%&%§"))
|
||||
err := CompleteChunk(w, r, false)
|
||||
err := CompleteChunk(w, r)
|
||||
test.IsNotNil(t, err)
|
||||
|
||||
w = httptest.NewRecorder()
|
||||
r = getFileUploadRecorder(false)
|
||||
err = CompleteChunk(w, r, false)
|
||||
err = CompleteChunk(w, r)
|
||||
test.IsNotNil(t, err)
|
||||
|
||||
data := url.Values{}
|
||||
@@ -139,7 +133,7 @@ func TestCompleteChunk(t *testing.T) {
|
||||
data.Set("filesize", "13")
|
||||
w, r = test.GetRecorder("POST", "/uploadComplete", nil, nil, strings.NewReader(data.Encode()))
|
||||
r.Header.Set("Content-type", "application/x-www-form-urlencoded")
|
||||
err = CompleteChunk(w, r, false)
|
||||
err = CompleteChunk(w, r)
|
||||
test.IsNil(t, err)
|
||||
|
||||
result := struct {
|
||||
@@ -154,7 +148,7 @@ func TestCompleteChunk(t *testing.T) {
|
||||
data.Set("chunkid", "invalid")
|
||||
w, r = test.GetRecorder("POST", "/uploadComplete", nil, nil, strings.NewReader(data.Encode()))
|
||||
r.Header.Set("Content-type", "application/x-www-form-urlencoded")
|
||||
err = CompleteChunk(w, r, false)
|
||||
err = CompleteChunk(w, r)
|
||||
test.IsNotNil(t, err)
|
||||
}
|
||||
|
||||
|
||||
@@ -721,11 +721,11 @@
|
||||
},
|
||||
"allowedDownloads": {
|
||||
"type": "integer",
|
||||
"description": "How many downloads are allowed. Last used value from web interface will be used if empty. Unlimited if 0 is passed."
|
||||
"description": "How many downloads are allowed. Default of 1 will be used if empty. Unlimited if 0 is passed."
|
||||
},
|
||||
"expiryDays": {
|
||||
"type": "integer",
|
||||
"description": "How many days the file will be stored. Last used value from web interface will be used if empty. Unlimited if 0 is passed."
|
||||
"description": "How many days the file will be stored. Default of 14 will be used if empty. Unlimited if 0 is passed."
|
||||
},
|
||||
"password": {
|
||||
"type": "string",
|
||||
@@ -811,11 +811,11 @@
|
||||
},
|
||||
"allowedDownloads": {
|
||||
"type": "integer",
|
||||
"description": "How many downloads are allowed. Last used value from web interface will be used if empty. Unlimited if 0 is passed."
|
||||
"description": "How many downloads are allowed. Default of 1 will be used if empty. Unlimited if 0 is passed."
|
||||
},
|
||||
"expiryDays": {
|
||||
"type": "integer",
|
||||
"description": "How many days the file will be stored. Last used value from web interface will be used if empty. Unlimited if 0 is passed."
|
||||
"description": "How many days the file will be stored. Default of 14 will be used if empty. Unlimited if 0 is passed."
|
||||
},
|
||||
"password": {
|
||||
"type": "string",
|
||||
|
||||
@@ -23,6 +23,7 @@ Dropzone.options.uploaddropzone = {
|
||||
init: function() {
|
||||
dropzoneObject = this;
|
||||
this.on("addedfile", file => {
|
||||
saveUploadDefaults();
|
||||
addFileProgress(file);
|
||||
});
|
||||
this.on("queuecomplete", function() {
|
||||
@@ -73,10 +74,10 @@ function updateProgressbar(file, progress, bytesSent) {
|
||||
let millisSinceUpload = Date.now() - container.getAttribute('data-starttime');
|
||||
let megabytePerSecond = bytesSent / (millisSinceUpload / 1000) / 1024 / 1024;
|
||||
document.getElementById(`us-progressbar-${chunkId}`).style.width = rounded + "%";
|
||||
|
||||
|
||||
let uploadSpeed = Math.round(megabytePerSecond * 10) / 10;
|
||||
if (!Number.isNaN(uploadSpeed))
|
||||
document.getElementById(`us-progress-info-${chunkId}`).innerText = rounded + "% - " + uploadSpeed + "MB/s";
|
||||
document.getElementById(`us-progress-info-${chunkId}`).innerText = rounded + "% - " + uploadSpeed + "MB/s";
|
||||
}
|
||||
|
||||
function setProgressStatus(chunkId, progressCode) {
|
||||
@@ -130,6 +131,52 @@ document.onpaste = function(event) {
|
||||
}
|
||||
}
|
||||
|
||||
function setUploadDefaults() {
|
||||
let defaultDownloads = getLocalStorageWithDefault("defaultDownloads", 1);
|
||||
let defaultExpiry = getLocalStorageWithDefault("defaultExpiry", 14);
|
||||
let defaultPassword = getLocalStorageWithDefault("defaultPassword", "");
|
||||
let defaultUnlimitedDownloads = getLocalStorageWithDefault("defaultUnlimitedDownloads", false) === "true";
|
||||
let defaultUnlimitedTime = getLocalStorageWithDefault("defaultUnlimitedTime", false) === "true";
|
||||
|
||||
document.getElementById("allowedDownloads").value = defaultDownloads;
|
||||
document.getElementById("expiryDays").value = defaultExpiry;
|
||||
document.getElementById("password").value = defaultPassword;
|
||||
document.getElementById("enableDownloadLimit").checked = !defaultUnlimitedDownloads;
|
||||
document.getElementById("enableTimeLimit").checked = !defaultUnlimitedTime;
|
||||
|
||||
if (defaultPassword === "") {
|
||||
document.getElementById("enablePassword").checked = false;
|
||||
document.getElementById("password").disabled = true;
|
||||
} else {
|
||||
document.getElementById("enablePassword").checked = true;
|
||||
document.getElementById("password").disabled = false;
|
||||
}
|
||||
|
||||
if (defaultUnlimitedDownloads) {
|
||||
document.getElementById("allowedDownloads").disabled = true;
|
||||
}
|
||||
if (defaultUnlimitedTime) {
|
||||
document.getElementById("expiryDays").disabled = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function saveUploadDefaults() {
|
||||
localStorage.setItem("defaultDownloads", document.getElementById("allowedDownloads").value);
|
||||
localStorage.setItem("defaultExpiry", document.getElementById("expiryDays").value);
|
||||
localStorage.setItem("defaultPassword", document.getElementById("password").value);
|
||||
localStorage.setItem("defaultUnlimitedDownloads", !document.getElementById("enableDownloadLimit").checked);
|
||||
localStorage.setItem("defaultUnlimitedTime", !document.getElementById("enableTimeLimit").checked);
|
||||
}
|
||||
|
||||
function getLocalStorageWithDefault(key, default_value) {
|
||||
var value = localStorage.getItem(key);
|
||||
if (value === null) {
|
||||
return default_value;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function urlencodeFormData(fd) {
|
||||
let s = '';
|
||||
|
||||
@@ -430,7 +477,7 @@ function changeApiPermission(apiKey, permission, buttonId) {
|
||||
|
||||
function deleteApiKey(apiKey) {
|
||||
|
||||
document.getElementById("delete-"+apiKey).disabled = true;
|
||||
document.getElementById("delete-" + apiKey).disabled = true;
|
||||
var apiUrl = './api/auth/delete';
|
||||
const requestOptions = {
|
||||
method: 'POST',
|
||||
@@ -448,7 +495,7 @@ function deleteApiKey(apiKey) {
|
||||
}
|
||||
})
|
||||
.then(data => {
|
||||
document.getElementById("row-"+apiKey).remove();
|
||||
document.getElementById("row-" + apiKey).remove();
|
||||
})
|
||||
.catch(error => {
|
||||
alert("Unable to delete API key: " + error);
|
||||
@@ -478,7 +525,7 @@ function newApiKey() {
|
||||
}
|
||||
})
|
||||
.then(data => {
|
||||
location.reload();
|
||||
location.reload();
|
||||
})
|
||||
.catch(error => {
|
||||
alert("Unable to create API key: " + error);
|
||||
@@ -489,7 +536,7 @@ function newApiKey() {
|
||||
|
||||
function deleteFile(id) {
|
||||
|
||||
document.getElementById("button-delete-"+id).disabled = true;
|
||||
document.getElementById("button-delete-" + id).disabled = true;
|
||||
var apiUrl = './api/files/delete';
|
||||
const requestOptions = {
|
||||
method: 'POST',
|
||||
@@ -507,7 +554,7 @@ function deleteFile(id) {
|
||||
}
|
||||
})
|
||||
.then(data => {
|
||||
location.reload();
|
||||
location.reload();
|
||||
})
|
||||
.catch(error => {
|
||||
alert("Unable to delete file: " + error);
|
||||
@@ -546,7 +593,7 @@ function registerChangeHandler() {
|
||||
source.onmessage = (event) => {
|
||||
try {
|
||||
let eventData = JSON.parse(event.data);
|
||||
setProgressStatus(eventData.chunkid, eventData.currentstatus);
|
||||
setProgressStatus(eventData.chunkid, eventData.currentstatus);
|
||||
} catch (e) {
|
||||
console.error("Failed to parse event data:", e);
|
||||
}
|
||||
@@ -638,7 +685,7 @@ function addRow(jsonText) {
|
||||
let item = jsonObject.FileInfo;
|
||||
let table = document.getElementById("downloadtable");
|
||||
let row = table.insertRow(0);
|
||||
row.id = "row-"+ item.Id;
|
||||
row.id = "row-" + item.Id;
|
||||
let cellFilename = row.insertCell(0);
|
||||
let cellFileSize = row.insertCell(1);
|
||||
let cellRemainingDownloads = row.insertCell(2);
|
||||
@@ -668,12 +715,12 @@ function addRow(jsonText) {
|
||||
cellUrl.innerHTML = '<a target="_blank" style="color: inherit" id="url-href-' + item.Id + '" href="' + item.UrlDownload + '">' + item.Id + '</a>' + lockIcon;
|
||||
|
||||
let buttons = '<button type="button" onclick="showToast()" id="url-button-' + item.Id + '" data-clipboard-text="' + item.UrlDownload + '" class="copyurl btn btn-outline-light btn-sm"><i class="bi bi-copy"></i> URL</button> ';
|
||||
if (item.UrlHotlink === "") {
|
||||
buttons = buttons + '<button type="button"class="copyurl btn btn-outline-light btn-sm disabled"><i class="bi bi-copy"></i> Hotlink</button> ';
|
||||
} else {
|
||||
buttons = buttons + '<button type="button" onclick="showToast()" data-clipboard-text="' + item.UrlHotlink + '" class="copyurl btn btn-outline-light btn-sm"><i class="bi bi-copy"></i> Hotlink</button> ';
|
||||
}
|
||||
buttons = buttons + '<button type="button" id="qrcode-'+item.Id+'" title="QR Code" class="btn btn-outline-light btn-sm" onclick="showQrCode(\'' + item.UrlDownload + '\');"><i class="bi bi-qr-code"></i></button> ';
|
||||
if (item.UrlHotlink === "") {
|
||||
buttons = buttons + '<button type="button"class="copyurl btn btn-outline-light btn-sm disabled"><i class="bi bi-copy"></i> Hotlink</button> ';
|
||||
} else {
|
||||
buttons = buttons + '<button type="button" onclick="showToast()" data-clipboard-text="' + item.UrlHotlink + '" class="copyurl btn btn-outline-light btn-sm"><i class="bi bi-copy"></i> Hotlink</button> ';
|
||||
}
|
||||
buttons = buttons + '<button type="button" id="qrcode-' + item.Id + '" title="QR Code" class="btn btn-outline-light btn-sm" onclick="showQrCode(\'' + item.UrlDownload + '\');"><i class="bi bi-qr-code"></i></button> ';
|
||||
buttons = buttons + '<button type="button" title="Edit" class="btn btn-outline-light btn-sm" onclick="showEditModal(\'' + item.Name + '\',\'' + item.Id + '\', ' + item.DownloadsRemaining + ', ' + item.ExpireAt + ', ' + item.IsPasswordProtected + ', ' + item.UnlimitedDownloads + ', ' + item.UnlimitedTime + ');"><i class="bi bi-pencil"></i></button> ';
|
||||
buttons = buttons + '<button type="button" id="button-delete-' + item.Id + '" title="Delete" class="btn btn-outline-danger btn-sm" onclick="deleteFile(\'' + item.Id + '\')"><i class="bi bi-trash3"></i></button>';
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -19,27 +19,27 @@
|
||||
<div class="container-md">
|
||||
<div class="row">
|
||||
<div class="form-group col">
|
||||
<input class="form-check-input" type="checkbox" name="enableDownloadLimit" id="enableDownloadLimit" onchange="checkBoxChanged(this, 'allowedDownloads')" value="" aria-label="Enable Download Limit" {{ if not .DefaultUnlimitedDownload }} checked {{ end }}>
|
||||
<input class="form-check-input" type="checkbox" name="enableDownloadLimit" id="enableDownloadLimit" onchange="checkBoxChanged(this, 'allowedDownloads')" value="" aria-label="Enable Download Limit" checked>
|
||||
<label class="control-label small" for="allowedDownloads">Limit Downloads</label>
|
||||
<div class="input-group mb-3">
|
||||
<input type="number" class="form-control admin-input" value="{{ .DefaultDownloads }}" name="allowedDownloads" id="allowedDownloads" min="1" {{ if .DefaultUnlimitedDownload }} disabled {{ end }} style="text-align: right;">
|
||||
<input type="number" class="form-control admin-input" value="1" name="allowedDownloads" id="allowedDownloads" min="1" style="text-align: right;">
|
||||
<span class="input-group-text">Downloads</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="break"></div>
|
||||
<div class="form-group col">
|
||||
<input class="form-check-input" type="checkbox" name="enableTimeLimit" id="enableTimeLimit" onchange="checkBoxChanged(this, 'expiryDays')" value="" aria-label="Enable Time Limit" {{ if not .DefaultUnlimitedTime }} checked {{ end }}>
|
||||
<input class="form-check-input" type="checkbox" name="enableTimeLimit" id="enableTimeLimit" onchange="checkBoxChanged(this, 'expiryDays')" value="" aria-label="Enable Time Limit" checked>
|
||||
<label class="control-label small" for="expiryDays">Expiry</label>
|
||||
<div class="input-group mb-3">
|
||||
<input type="number" class="form-control admin-input" value="{{ .DefaultExpiry }}" name="expiryDays" id="expiryDays" min="1" {{ if .DefaultUnlimitedTime }} disabled {{ end }} style="text-align: right;">
|
||||
<input type="number" class="form-control admin-input" value="14" name="expiryDays" id="expiryDays" min="1" style="text-align: right;">
|
||||
<span class="input-group-text">Days</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="break"></div>
|
||||
<div class="form-group col">
|
||||
<input class="form-check-input" type="checkbox" name="enablePassword" id="enablePassword" onchange="checkBoxChanged(this, 'password')" value="" aria-label="Enable Password Protection" {{ if ne .DefaultPassword "" }} checked {{ end }}>
|
||||
<input class="form-check-input" type="checkbox" name="enablePassword" id="enablePassword" onchange="checkBoxChanged(this, 'password')" value="" aria-label="Enable Password Protection">
|
||||
<label class="control-label small" for="password">Password</label>
|
||||
<input class="form-control admin-input" value="{{ .DefaultPassword }}" name="password" id="password" placeholder="None" {{ if eq .DefaultPassword "" }} disabled {{ end }}>
|
||||
<input class="form-control admin-input" value="" name="password" id="password" placeholder="None" disabled>
|
||||
</div>
|
||||
<div id="errordiv" class="alert alert-danger" style="display:none">
|
||||
<span id="errormessage" ></span>
|
||||
@@ -177,6 +177,7 @@
|
||||
});
|
||||
registerChangeHandler();
|
||||
var systemKey = "{{.SystemKey}}";
|
||||
setUploadDefaults();
|
||||
</script>
|
||||
|
||||
{{ if .EndToEndEncryption }}
|
||||
|
||||
+4
-4
@@ -721,11 +721,11 @@
|
||||
},
|
||||
"allowedDownloads": {
|
||||
"type": "integer",
|
||||
"description": "How many downloads are allowed. Last used value from web interface will be used if empty. Unlimited if 0 is passed."
|
||||
"description": "How many downloads are allowed. Default of 1 will be used if empty. Unlimited if 0 is passed."
|
||||
},
|
||||
"expiryDays": {
|
||||
"type": "integer",
|
||||
"description": "How many days the file will be stored. Last used value from web interface will be used if empty. Unlimited if 0 is passed."
|
||||
"description": "How many days the file will be stored. Default of 14 will be used if empty. Unlimited if 0 is passed."
|
||||
},
|
||||
"password": {
|
||||
"type": "string",
|
||||
@@ -811,11 +811,11 @@
|
||||
},
|
||||
"allowedDownloads": {
|
||||
"type": "integer",
|
||||
"description": "How many downloads are allowed. Last used value from web interface will be used if empty. Unlimited if 0 is passed."
|
||||
"description": "How many downloads are allowed. Default of 1 will be used if empty. Unlimited if 0 is passed."
|
||||
},
|
||||
"expiryDays": {
|
||||
"type": "integer",
|
||||
"description": "How many days the file will be stored. Last used value from web interface will be used if empty. Unlimited if 0 is passed."
|
||||
"description": "How many days the file will be stored. Default of 14 will be used if empty. Unlimited if 0 is passed."
|
||||
},
|
||||
"password": {
|
||||
"type": "string",
|
||||
|
||||
Reference in New Issue
Block a user