Test: thumbnail and authn / Modify: read thumbnail config from file
This commit is contained in:
parent
f35c585edf
commit
c3c0e92964
13 changed files with 491 additions and 98 deletions
|
@ -2,6 +2,11 @@
|
||||||
Debug = true
|
Debug = true
|
||||||
SessionSecret = 23333
|
SessionSecret = 23333
|
||||||
|
|
||||||
|
[Thumbnail]
|
||||||
|
MaxWidth = 400
|
||||||
|
MaxHeight = 300
|
||||||
|
FileSuffix = ._thumb
|
||||||
|
|
||||||
[Database]
|
[Database]
|
||||||
Type = mysql
|
Type = mysql
|
||||||
User = root
|
User = root
|
||||||
|
|
|
@ -2,12 +2,9 @@ package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
"encoding/binary"
|
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
"github.com/HFO4/cloudreve/pkg/util"
|
"github.com/HFO4/cloudreve/pkg/util"
|
||||||
"github.com/duo-labs/webauthn/webauthn"
|
|
||||||
"github.com/jinzhu/gorm"
|
"github.com/jinzhu/gorm"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -59,41 +56,6 @@ type UserOption struct {
|
||||||
PreferredTheme string `json:"preferred_theme"`
|
PreferredTheme string `json:"preferred_theme"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (user User) WebAuthnID() []byte {
|
|
||||||
bs := make([]byte, 8)
|
|
||||||
binary.LittleEndian.PutUint64(bs, uint64(user.ID))
|
|
||||||
return bs
|
|
||||||
}
|
|
||||||
|
|
||||||
func (user User) WebAuthnName() string {
|
|
||||||
return user.Email
|
|
||||||
}
|
|
||||||
|
|
||||||
func (user User) WebAuthnDisplayName() string {
|
|
||||||
return user.Nick
|
|
||||||
}
|
|
||||||
|
|
||||||
func (user User) WebAuthnIcon() string {
|
|
||||||
return "https://cdn4.buysellads.net/uu/1/46074/1559075156-slack-carbon-red_2x.png"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (user User) WebAuthnCredentials() []webauthn.Credential {
|
|
||||||
var res []webauthn.Credential
|
|
||||||
err := json.Unmarshal([]byte(user.Authn), &res)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
func (user *User) RegisterAuthn(credential *webauthn.Credential) {
|
|
||||||
res, err := json.Marshal([]webauthn.Credential{*credential})
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
}
|
|
||||||
DB.Model(user).UpdateColumn("authn", string(res))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Root 获取用户的根目录
|
// Root 获取用户的根目录
|
||||||
func (user *User) Root() (*Folder, error) {
|
func (user *User) Root() (*Folder, error) {
|
||||||
var folder Folder
|
var folder Folder
|
||||||
|
@ -157,18 +119,17 @@ func (user *User) GetPolicyID() uint {
|
||||||
return user.Group.PolicyList[0]
|
return user.Group.PolicyList[0]
|
||||||
}
|
}
|
||||||
return 1
|
return 1
|
||||||
} else {
|
|
||||||
// 用户指定时,先检查是否为可用策略列表中的值
|
|
||||||
if util.ContainsUint(user.Group.PolicyList, user.OptionsSerialized.PreferredPolicy) {
|
|
||||||
return user.OptionsSerialized.PreferredPolicy
|
|
||||||
}
|
|
||||||
// 不可用时,返回第一个
|
|
||||||
if len(user.Group.PolicyList) != 0 {
|
|
||||||
return user.Group.PolicyList[0]
|
|
||||||
}
|
|
||||||
return 1
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
// 用户指定时,先检查是否为可用策略列表中的值
|
||||||
|
if util.ContainsUint(user.Group.PolicyList, user.OptionsSerialized.PreferredPolicy) {
|
||||||
|
return user.OptionsSerialized.PreferredPolicy
|
||||||
|
}
|
||||||
|
// 不可用时,返回第一个
|
||||||
|
if len(user.Group.PolicyList) != 0 {
|
||||||
|
return user.Group.PolicyList[0]
|
||||||
|
}
|
||||||
|
return 1
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUserByID 用ID获取用户
|
// GetUserByID 用ID获取用户
|
||||||
|
|
53
models/user_authn.go
Normal file
53
models/user_authn.go
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
package model
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"github.com/duo-labs/webauthn/webauthn"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
`webauthn.User` 接口的实现
|
||||||
|
*/
|
||||||
|
|
||||||
|
// WebAuthnID 返回用户ID
|
||||||
|
func (user User) WebAuthnID() []byte {
|
||||||
|
bs := make([]byte, 8)
|
||||||
|
binary.LittleEndian.PutUint64(bs, uint64(user.ID))
|
||||||
|
return bs
|
||||||
|
}
|
||||||
|
|
||||||
|
// WebAuthnName 返回用户名
|
||||||
|
func (user User) WebAuthnName() string {
|
||||||
|
return user.Email
|
||||||
|
}
|
||||||
|
|
||||||
|
// WebAuthnDisplayName 获得用于展示的用户名
|
||||||
|
func (user User) WebAuthnDisplayName() string {
|
||||||
|
return user.Nick
|
||||||
|
}
|
||||||
|
|
||||||
|
// WebAuthnIcon 获得用户头像
|
||||||
|
func (user User) WebAuthnIcon() string {
|
||||||
|
return "https://cdn4.buysellads.net/uu/1/46074/1559075156-slack-carbon-red_2x.png"
|
||||||
|
}
|
||||||
|
|
||||||
|
// WebAuthnCredentials 获得已注册的验证器凭证
|
||||||
|
func (user User) WebAuthnCredentials() []webauthn.Credential {
|
||||||
|
var res []webauthn.Credential
|
||||||
|
err := json.Unmarshal([]byte(user.Authn), &res)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterAuthn 添加新的验证器
|
||||||
|
func (user *User) RegisterAuthn(credential *webauthn.Credential) {
|
||||||
|
res, err := json.Marshal([]webauthn.Credential{*credential})
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
DB.Model(user).UpdateColumn("authn", string(res))
|
||||||
|
}
|
84
models/user_authn_test.go
Normal file
84
models/user_authn_test.go
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
package model
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/DATA-DOG/go-sqlmock"
|
||||||
|
"github.com/duo-labs/webauthn/webauthn"
|
||||||
|
"github.com/jinzhu/gorm"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestUser_RegisterAuthn(t *testing.T) {
|
||||||
|
asserts := assert.New(t)
|
||||||
|
credential := webauthn.Credential{}
|
||||||
|
user := User{
|
||||||
|
Model: gorm.Model{ID: 1},
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
mock.ExpectBegin()
|
||||||
|
mock.ExpectExec("UPDATE(.+)").
|
||||||
|
WillReturnResult(sqlmock.NewResult(1, 1))
|
||||||
|
mock.ExpectCommit()
|
||||||
|
user.RegisterAuthn(&credential)
|
||||||
|
asserts.NoError(mock.ExpectationsWereMet())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUser_WebAuthnCredentials(t *testing.T) {
|
||||||
|
asserts := assert.New(t)
|
||||||
|
user := User{
|
||||||
|
Model: gorm.Model{ID: 1},
|
||||||
|
Authn: `[{"ID":"123","PublicKey":"+4sg1vYcjg/+=","AttestationType":"packed","Authenticator":{"AAGUID":"+lg==","SignCount":0,"CloneWarning":false}}]`,
|
||||||
|
}
|
||||||
|
{
|
||||||
|
credentials := user.WebAuthnCredentials()
|
||||||
|
asserts.Len(credentials, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUser_WebAuthnDisplayName(t *testing.T) {
|
||||||
|
asserts := assert.New(t)
|
||||||
|
user := User{
|
||||||
|
Model: gorm.Model{ID: 1},
|
||||||
|
Nick: "123",
|
||||||
|
}
|
||||||
|
{
|
||||||
|
nick := user.WebAuthnDisplayName()
|
||||||
|
asserts.Equal("123", nick)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUser_WebAuthnIcon(t *testing.T) {
|
||||||
|
asserts := assert.New(t)
|
||||||
|
user := User{
|
||||||
|
Model: gorm.Model{ID: 1},
|
||||||
|
}
|
||||||
|
{
|
||||||
|
icon := user.WebAuthnIcon()
|
||||||
|
asserts.NotEmpty(icon)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUser_WebAuthnID(t *testing.T) {
|
||||||
|
asserts := assert.New(t)
|
||||||
|
user := User{
|
||||||
|
Model: gorm.Model{ID: 1},
|
||||||
|
}
|
||||||
|
{
|
||||||
|
id := user.WebAuthnID()
|
||||||
|
asserts.Len(id, 8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUser_WebAuthnName(t *testing.T) {
|
||||||
|
asserts := assert.New(t)
|
||||||
|
user := User{
|
||||||
|
Model: gorm.Model{ID: 1},
|
||||||
|
Email: "abslant@foxmail.com",
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name := user.WebAuthnName()
|
||||||
|
asserts.Equal("abslant@foxmail.com", name)
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,11 +5,11 @@ import (
|
||||||
"github.com/duo-labs/webauthn/webauthn"
|
"github.com/duo-labs/webauthn/webauthn"
|
||||||
)
|
)
|
||||||
|
|
||||||
var Authn *webauthn.WebAuthn
|
var AuthnInstance *webauthn.WebAuthn
|
||||||
|
|
||||||
func Init() {
|
func Init() {
|
||||||
var err error
|
var err error
|
||||||
Authn, err = webauthn.New(&webauthn.Config{
|
AuthnInstance, err = webauthn.New(&webauthn.Config{
|
||||||
RPDisplayName: "Duo Labs", // Display Name for your site
|
RPDisplayName: "Duo Labs", // Display Name for your site
|
||||||
RPID: "localhost", // Generally the FQDN for your site
|
RPID: "localhost", // Generally the FQDN for your site
|
||||||
RPOrigin: "http://localhost:3000", // The origin URL for WebAuthn requests
|
RPOrigin: "http://localhost:3000", // The origin URL for WebAuthn requests
|
||||||
|
|
15
pkg/authn/auth_test.go
Normal file
15
pkg/authn/auth_test.go
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
package authn
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestInit(t *testing.T) {
|
||||||
|
asserts := assert.New(t)
|
||||||
|
|
||||||
|
asserts.NotPanics(func() {
|
||||||
|
Init()
|
||||||
|
})
|
||||||
|
asserts.NotNil(AuthnInstance)
|
||||||
|
}
|
|
@ -3,7 +3,6 @@ package conf
|
||||||
import (
|
import (
|
||||||
"github.com/HFO4/cloudreve/pkg/util"
|
"github.com/HFO4/cloudreve/pkg/util"
|
||||||
"github.com/go-ini/ini"
|
"github.com/go-ini/ini"
|
||||||
"github.com/mojocn/base64Captcha"
|
|
||||||
"gopkg.in/go-playground/validator.v8"
|
"gopkg.in/go-playground/validator.v8"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -45,36 +44,11 @@ type redis struct {
|
||||||
DB string
|
DB string
|
||||||
}
|
}
|
||||||
|
|
||||||
// RedisConfig Redis服务器配置
|
// 缩略图 配置
|
||||||
var RedisConfig = &redis{
|
type thumb struct {
|
||||||
Server: "",
|
MaxWidth uint
|
||||||
Password: "",
|
MaxHeight uint
|
||||||
DB: "0",
|
FileSuffix string `validate:"min=1"`
|
||||||
}
|
|
||||||
|
|
||||||
// DatabaseConfig 数据库配置
|
|
||||||
var DatabaseConfig = &database{
|
|
||||||
Type: "UNSET",
|
|
||||||
}
|
|
||||||
|
|
||||||
// SystemConfig 系统公用配置
|
|
||||||
var SystemConfig = &system{
|
|
||||||
Debug: false,
|
|
||||||
}
|
|
||||||
|
|
||||||
// CaptchaConfig 验证码配置
|
|
||||||
var CaptchaConfig = &captcha{
|
|
||||||
Height: 60,
|
|
||||||
Width: 240,
|
|
||||||
Mode: 3,
|
|
||||||
ComplexOfNoiseText: base64Captcha.CaptchaComplexLower,
|
|
||||||
ComplexOfNoiseDot: base64Captcha.CaptchaComplexLower,
|
|
||||||
IsShowHollowLine: false,
|
|
||||||
IsShowNoiseDot: false,
|
|
||||||
IsShowNoiseText: false,
|
|
||||||
IsShowSlimeLine: false,
|
|
||||||
IsShowSineLine: false,
|
|
||||||
CaptchaLen: 6,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var cfg *ini.File
|
var cfg *ini.File
|
||||||
|
@ -90,10 +64,11 @@ func Init(path string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
sections := map[string]interface{}{
|
sections := map[string]interface{}{
|
||||||
"Database": DatabaseConfig,
|
"Database": DatabaseConfig,
|
||||||
"System": SystemConfig,
|
"System": SystemConfig,
|
||||||
"Captcha": CaptchaConfig,
|
"Captcha": CaptchaConfig,
|
||||||
"Redis": RedisConfig,
|
"Redis": RedisConfig,
|
||||||
|
"Thumbnail": ThumbConfig,
|
||||||
}
|
}
|
||||||
for sectionName, sectionStruct := range sections {
|
for sectionName, sectionStruct := range sections {
|
||||||
err = mapSection(sectionName, sectionStruct)
|
err = mapSection(sectionName, sectionStruct)
|
||||||
|
|
41
pkg/conf/defaults.go
Normal file
41
pkg/conf/defaults.go
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
package conf
|
||||||
|
|
||||||
|
import "github.com/mojocn/base64Captcha"
|
||||||
|
|
||||||
|
// RedisConfig Redis服务器配置
|
||||||
|
var RedisConfig = &redis{
|
||||||
|
Server: "",
|
||||||
|
Password: "",
|
||||||
|
DB: "0",
|
||||||
|
}
|
||||||
|
|
||||||
|
// DatabaseConfig 数据库配置
|
||||||
|
var DatabaseConfig = &database{
|
||||||
|
Type: "UNSET",
|
||||||
|
}
|
||||||
|
|
||||||
|
// SystemConfig 系统公用配置
|
||||||
|
var SystemConfig = &system{
|
||||||
|
Debug: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
// CaptchaConfig 验证码配置
|
||||||
|
var CaptchaConfig = &captcha{
|
||||||
|
Height: 60,
|
||||||
|
Width: 240,
|
||||||
|
Mode: 3,
|
||||||
|
ComplexOfNoiseText: base64Captcha.CaptchaComplexLower,
|
||||||
|
ComplexOfNoiseDot: base64Captcha.CaptchaComplexLower,
|
||||||
|
IsShowHollowLine: false,
|
||||||
|
IsShowNoiseDot: false,
|
||||||
|
IsShowNoiseText: false,
|
||||||
|
IsShowSlimeLine: false,
|
||||||
|
IsShowSineLine: false,
|
||||||
|
CaptchaLen: 6,
|
||||||
|
}
|
||||||
|
|
||||||
|
var ThumbConfig = &thumb{
|
||||||
|
MaxWidth: 400,
|
||||||
|
MaxHeight: 300,
|
||||||
|
FileSuffix: "._thumb",
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
model "github.com/HFO4/cloudreve/models"
|
model "github.com/HFO4/cloudreve/models"
|
||||||
|
"github.com/HFO4/cloudreve/pkg/conf"
|
||||||
"github.com/HFO4/cloudreve/pkg/filesystem/response"
|
"github.com/HFO4/cloudreve/pkg/filesystem/response"
|
||||||
"github.com/HFO4/cloudreve/pkg/thumb"
|
"github.com/HFO4/cloudreve/pkg/thumb"
|
||||||
"github.com/HFO4/cloudreve/pkg/util"
|
"github.com/HFO4/cloudreve/pkg/util"
|
||||||
|
@ -54,7 +55,7 @@ func (fs *FileSystem) GenerateThumbnail(ctx context.Context, file *model.File) {
|
||||||
|
|
||||||
image, err := thumb.NewThumbFromFile(source, file.Name)
|
image, err := thumb.NewThumbFromFile(source, file.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
util.Log().Warning("生成缩略图时无法解析[%s]图像数据:%s", file.SourceName, err)
|
util.Log().Warning("生成缩略图时无法解析 [%s] 图像数据:%s", file.SourceName, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,9 +65,9 @@ func (fs *FileSystem) GenerateThumbnail(ctx context.Context, file *model.File) {
|
||||||
// 生成缩略图
|
// 生成缩略图
|
||||||
image.GetThumb(fs.GenerateThumbnailSize(w, h))
|
image.GetThumb(fs.GenerateThumbnailSize(w, h))
|
||||||
// 保存到文件
|
// 保存到文件
|
||||||
err = image.Save(file.SourceName + "._thumb")
|
err = image.Save(file.SourceName + conf.ThumbConfig.FileSuffix)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
util.Log().Warning("无法保存缩略图:%s", file.SourceName, err)
|
util.Log().Warning("无法保存缩略图:%s", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,12 +76,12 @@ func (fs *FileSystem) GenerateThumbnail(ctx context.Context, file *model.File) {
|
||||||
|
|
||||||
// 失败时删除缩略图文件
|
// 失败时删除缩略图文件
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_, _ = fs.Handler.Delete(newCtx, []string{file.SourceName + "._thumb"})
|
_, _ = fs.Handler.Delete(newCtx, []string{file.SourceName + conf.ThumbConfig.FileSuffix})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenerateThumbnailSize 获取要生成的缩略图的尺寸
|
// GenerateThumbnailSize 获取要生成的缩略图的尺寸
|
||||||
// TODO 从配置文件读取
|
// TODO 优先从数据库中获得
|
||||||
func (fs *FileSystem) GenerateThumbnailSize(w, h int) (uint, uint) {
|
func (fs *FileSystem) GenerateThumbnailSize(w, h int) (uint, uint) {
|
||||||
return 400, 300
|
return conf.ThumbConfig.MaxWidth, conf.ThumbConfig.MaxHeight
|
||||||
}
|
}
|
||||||
|
|
156
pkg/filesystem/image_test.go
Normal file
156
pkg/filesystem/image_test.go
Normal file
|
@ -0,0 +1,156 @@
|
||||||
|
package filesystem
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"github.com/DATA-DOG/go-sqlmock"
|
||||||
|
model "github.com/HFO4/cloudreve/models"
|
||||||
|
"github.com/HFO4/cloudreve/pkg/conf"
|
||||||
|
"github.com/HFO4/cloudreve/pkg/filesystem/response"
|
||||||
|
"github.com/HFO4/cloudreve/pkg/util"
|
||||||
|
"github.com/jinzhu/gorm"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
testMock "github.com/stretchr/testify/mock"
|
||||||
|
"image"
|
||||||
|
"image/jpeg"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func CreateTestImage() *os.File {
|
||||||
|
file, err := os.Create("TestFileSystem_GenerateThumbnail.jpeg")
|
||||||
|
alpha := image.NewAlpha(image.Rect(0, 0, 500, 200))
|
||||||
|
jpeg.Encode(file, alpha, nil)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
_, _ = file.Seek(0, 0)
|
||||||
|
return file
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFileSystem_GetThumb(t *testing.T) {
|
||||||
|
asserts := assert.New(t)
|
||||||
|
fs := FileSystem{
|
||||||
|
User: &model.User{
|
||||||
|
Model: gorm.Model{ID: 1},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
// 正常
|
||||||
|
{
|
||||||
|
testHandler := new(FileHeaderMock)
|
||||||
|
testHandler.On("Thumb", testMock.Anything, "123.jpg").Return(&response.ContentResponse{URL: "123"}, nil)
|
||||||
|
fs.Handler = testHandler
|
||||||
|
mock.ExpectQuery("SELECT(.+)").
|
||||||
|
WithArgs(10, 1).
|
||||||
|
WillReturnRows(
|
||||||
|
sqlmock.NewRows(
|
||||||
|
[]string{"id", "pic_info", "source_name"}).
|
||||||
|
AddRow(10, "10,10", "123.jpg"),
|
||||||
|
)
|
||||||
|
|
||||||
|
res, err := fs.GetThumb(ctx, 10)
|
||||||
|
asserts.NoError(mock.ExpectationsWereMet())
|
||||||
|
testHandler.AssertExpectations(t)
|
||||||
|
asserts.NoError(err)
|
||||||
|
asserts.Equal("123", res.URL)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 文件不存在
|
||||||
|
{
|
||||||
|
|
||||||
|
mock.ExpectQuery("SELECT(.+)").
|
||||||
|
WithArgs(10, 1).
|
||||||
|
WillReturnRows(
|
||||||
|
sqlmock.NewRows(
|
||||||
|
[]string{"id", "pic_info", "source_name"}),
|
||||||
|
)
|
||||||
|
|
||||||
|
_, err := fs.GetThumb(ctx, 10)
|
||||||
|
asserts.NoError(mock.ExpectationsWereMet())
|
||||||
|
asserts.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFileSystem_GenerateThumbnail(t *testing.T) {
|
||||||
|
asserts := assert.New(t)
|
||||||
|
fs := FileSystem{
|
||||||
|
User: &model.User{
|
||||||
|
Model: gorm.Model{ID: 1},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
// 成功
|
||||||
|
{
|
||||||
|
src := CreateTestImage()
|
||||||
|
testHandler := new(FileHeaderMock)
|
||||||
|
testHandler.On("Get", testMock.Anything, "TestFileSystem_GenerateThumbnail.jpeg").Return(src, nil)
|
||||||
|
fs.Handler = testHandler
|
||||||
|
|
||||||
|
mock.ExpectBegin()
|
||||||
|
mock.ExpectExec("UPDATE(.+)").WillReturnResult(sqlmock.NewResult(1, 1))
|
||||||
|
mock.ExpectCommit()
|
||||||
|
|
||||||
|
file := &model.File{
|
||||||
|
Name: "123.jpg",
|
||||||
|
SourceName: "TestFileSystem_GenerateThumbnail.jpeg",
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.GenerateThumbnail(ctx, file)
|
||||||
|
asserts.NoError(mock.ExpectationsWereMet())
|
||||||
|
testHandler.AssertExpectations(t)
|
||||||
|
asserts.True(util.Exists("TestFileSystem_GenerateThumbnail.jpeg" + conf.ThumbConfig.FileSuffix))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新信息失败后删除文件
|
||||||
|
{
|
||||||
|
src := CreateTestImage()
|
||||||
|
testHandler := new(FileHeaderMock)
|
||||||
|
testHandler.On("Get", testMock.Anything, "TestFileSystem_GenerateThumbnail.jpeg").Return(src, nil)
|
||||||
|
testHandler.On("Delete", testMock.Anything, testMock.Anything).Return([]string{}, nil)
|
||||||
|
fs.Handler = testHandler
|
||||||
|
|
||||||
|
mock.ExpectBegin()
|
||||||
|
mock.ExpectExec("UPDATE(.+)").WillReturnError(errors.New("error"))
|
||||||
|
mock.ExpectRollback()
|
||||||
|
|
||||||
|
file := &model.File{
|
||||||
|
Name: "123.jpg",
|
||||||
|
SourceName: "TestFileSystem_GenerateThumbnail.jpeg",
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.GenerateThumbnail(ctx, file)
|
||||||
|
asserts.NoError(mock.ExpectationsWereMet())
|
||||||
|
testHandler.AssertExpectations(t)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 不能生成缩略图
|
||||||
|
{
|
||||||
|
file := &model.File{
|
||||||
|
Name: "123.123",
|
||||||
|
SourceName: "TestFileSystem_GenerateThumbnail.jpeg",
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.GenerateThumbnail(ctx, file)
|
||||||
|
asserts.NoError(mock.ExpectationsWereMet())
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFileSystem_GenerateThumbnailSize(t *testing.T) {
|
||||||
|
asserts := assert.New(t)
|
||||||
|
fs := FileSystem{
|
||||||
|
User: &model.User{
|
||||||
|
Model: gorm.Model{ID: 1},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
asserts.NotPanics(func() {
|
||||||
|
_, _ = fs.GenerateThumbnailSize(0, 0)
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ package local
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"github.com/HFO4/cloudreve/pkg/conf"
|
||||||
"github.com/HFO4/cloudreve/pkg/filesystem/response"
|
"github.com/HFO4/cloudreve/pkg/filesystem/response"
|
||||||
"github.com/HFO4/cloudreve/pkg/util"
|
"github.com/HFO4/cloudreve/pkg/util"
|
||||||
"io"
|
"io"
|
||||||
|
@ -78,7 +79,7 @@ func (handler Handler) Delete(ctx context.Context, files []string) ([]string, er
|
||||||
}
|
}
|
||||||
|
|
||||||
// 尝试删除文件的缩略图(如果有)
|
// 尝试删除文件的缩略图(如果有)
|
||||||
_ = os.Remove(value + "._thumb")
|
_ = os.Remove(value + conf.ThumbConfig.FileSuffix)
|
||||||
}
|
}
|
||||||
|
|
||||||
return deleteFailed, retErr
|
return deleteFailed, retErr
|
||||||
|
@ -86,7 +87,7 @@ func (handler Handler) Delete(ctx context.Context, files []string) ([]string, er
|
||||||
|
|
||||||
// Thumb 获取文件缩略图
|
// Thumb 获取文件缩略图
|
||||||
func (handler Handler) Thumb(ctx context.Context, path string) (*response.ContentResponse, error) {
|
func (handler Handler) Thumb(ctx context.Context, path string) (*response.ContentResponse, error) {
|
||||||
file, err := handler.Get(ctx, path+"._thumb")
|
file, err := handler.Get(ctx, path+conf.ThumbConfig.FileSuffix)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
101
pkg/thumb/image_test.go
Normal file
101
pkg/thumb/image_test.go
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
package thumb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/HFO4/cloudreve/pkg/util"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"image"
|
||||||
|
"image/jpeg"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func CreateTestImage() *os.File {
|
||||||
|
file, err := os.Create("TestNewThumbFromFile.jpeg")
|
||||||
|
alpha := image.NewAlpha(image.Rect(0, 0, 500, 200))
|
||||||
|
jpeg.Encode(file, alpha, nil)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
_, _ = file.Seek(0, 0)
|
||||||
|
return file
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewThumbFromFile(t *testing.T) {
|
||||||
|
asserts := assert.New(t)
|
||||||
|
file := CreateTestImage()
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
// 无扩展名时
|
||||||
|
{
|
||||||
|
thumb, err := NewThumbFromFile(file, "123")
|
||||||
|
asserts.Error(err)
|
||||||
|
asserts.Nil(thumb)
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
thumb, err := NewThumbFromFile(file, "123.jpg")
|
||||||
|
asserts.NoError(err)
|
||||||
|
asserts.NotNil(thumb)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
thumb, err := NewThumbFromFile(file, "123.jpeg")
|
||||||
|
asserts.Error(err)
|
||||||
|
asserts.Nil(thumb)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
thumb, err := NewThumbFromFile(file, "123.png")
|
||||||
|
asserts.Error(err)
|
||||||
|
asserts.Nil(thumb)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
thumb, err := NewThumbFromFile(file, "123.gif")
|
||||||
|
asserts.Error(err)
|
||||||
|
asserts.Nil(thumb)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
thumb, err := NewThumbFromFile(file, "123.3211")
|
||||||
|
asserts.Error(err)
|
||||||
|
asserts.Nil(thumb)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestThumb_GetSize(t *testing.T) {
|
||||||
|
asserts := assert.New(t)
|
||||||
|
file := CreateTestImage()
|
||||||
|
defer file.Close()
|
||||||
|
thumb, err := NewThumbFromFile(file, "123.jpg")
|
||||||
|
asserts.NoError(err)
|
||||||
|
|
||||||
|
w, h := thumb.GetSize()
|
||||||
|
asserts.Equal(500, w)
|
||||||
|
asserts.Equal(200, h)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestThumb_GetThumb(t *testing.T) {
|
||||||
|
asserts := assert.New(t)
|
||||||
|
file := CreateTestImage()
|
||||||
|
defer file.Close()
|
||||||
|
thumb, err := NewThumbFromFile(file, "123.jpg")
|
||||||
|
asserts.NoError(err)
|
||||||
|
|
||||||
|
asserts.NotPanics(func() {
|
||||||
|
thumb.GetThumb(10, 10)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestThumb_Save(t *testing.T) {
|
||||||
|
asserts := assert.New(t)
|
||||||
|
file := CreateTestImage()
|
||||||
|
defer file.Close()
|
||||||
|
thumb, err := NewThumbFromFile(file, "123.jpg")
|
||||||
|
asserts.NoError(err)
|
||||||
|
|
||||||
|
err = thumb.Save("/:noteexist/")
|
||||||
|
asserts.Error(err)
|
||||||
|
|
||||||
|
err = thumb.Save("TestThumb_Save.png")
|
||||||
|
asserts.NoError(err)
|
||||||
|
asserts.True(util.Exists("TestThumb_Save.png"))
|
||||||
|
|
||||||
|
}
|
|
@ -20,7 +20,7 @@ func StartLoginAuthn(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
options, sessionData, err := authn.Authn.BeginLogin(expectedUser)
|
options, sessionData, err := authn.AuthnInstance.BeginLogin(expectedUser)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(200, ErrorResponse(err))
|
c.JSON(200, ErrorResponse(err))
|
||||||
return
|
return
|
||||||
|
@ -52,7 +52,7 @@ func FinishLoginAuthn(c *gin.Context) {
|
||||||
var sessionData webauthn.SessionData
|
var sessionData webauthn.SessionData
|
||||||
err = json.Unmarshal(sessionDataJSON, &sessionData)
|
err = json.Unmarshal(sessionDataJSON, &sessionData)
|
||||||
|
|
||||||
_, err = authn.Authn.FinishLogin(expectedUser, sessionData, c.Request)
|
_, err = authn.AuthnInstance.FinishLogin(expectedUser, sessionData, c.Request)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(200, serializer.Err(401, "用户邮箱或密码错误", err))
|
c.JSON(200, serializer.Err(401, "用户邮箱或密码错误", err))
|
||||||
|
@ -68,7 +68,7 @@ func FinishLoginAuthn(c *gin.Context) {
|
||||||
// StartRegAuthn 开始注册WebAuthn信息
|
// StartRegAuthn 开始注册WebAuthn信息
|
||||||
func StartRegAuthn(c *gin.Context) {
|
func StartRegAuthn(c *gin.Context) {
|
||||||
currUser := CurrentUser(c)
|
currUser := CurrentUser(c)
|
||||||
options, sessionData, err := authn.Authn.BeginRegistration(currUser)
|
options, sessionData, err := authn.AuthnInstance.BeginRegistration(currUser)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(200, ErrorResponse(err))
|
c.JSON(200, ErrorResponse(err))
|
||||||
return
|
return
|
||||||
|
@ -94,7 +94,7 @@ func FinishRegAuthn(c *gin.Context) {
|
||||||
var sessionData webauthn.SessionData
|
var sessionData webauthn.SessionData
|
||||||
err := json.Unmarshal(sessionDataJSON, &sessionData)
|
err := json.Unmarshal(sessionDataJSON, &sessionData)
|
||||||
|
|
||||||
credential, err := authn.Authn.FinishRegistration(currUser, sessionData, c.Request)
|
credential, err := authn.AuthnInstance.FinishRegistration(currUser, sessionData, c.Request)
|
||||||
|
|
||||||
currUser.RegisterAuthn(credential)
|
currUser.RegisterAuthn(credential)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
Loading…
Add table
Reference in a new issue