diff --git a/backend/app/api/v1/file.go b/backend/app/api/v1/file.go index 232e55090..620075791 100644 --- a/backend/app/api/v1/file.go +++ b/backend/app/api/v1/file.go @@ -76,3 +76,17 @@ func (b *BaseApi) ChangeFileMode(c *gin.Context) { } helper.SuccessWithData(c, nil) } + +func (b *BaseApi) CompressFile(c *gin.Context) { + var req dto.FileCompress + if err := c.ShouldBindJSON(&req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) + return + } + err := fileService.Compress(req) + if err != nil { + helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) + return + } + helper.SuccessWithData(c, nil) +} diff --git a/backend/app/dto/file.go b/backend/app/dto/file.go index befadbc6b..e7d420941 100644 --- a/backend/app/dto/file.go +++ b/backend/app/dto/file.go @@ -30,3 +30,11 @@ type FileDelete struct { Path string IsDir bool } + +type FileCompress struct { + Files []string + Dst string + Type string + Name string + Replace bool +} diff --git a/backend/app/service/file.go b/backend/app/service/file.go index f3306b47a..29c915518 100644 --- a/backend/app/service/file.go +++ b/backend/app/service/file.go @@ -8,6 +8,7 @@ import ( "github.com/pkg/errors" "io" "io/fs" + "path/filepath" ) type FileService struct { @@ -75,6 +76,15 @@ func (f FileService) ChangeMode(op dto.FileCreate) error { return fo.Chmod(op.Path, fs.FileMode(op.Mode)) } +func (f FileService) Compress(c dto.FileCompress) error { + fo := files.NewFileOp() + if !c.Replace && fo.Stat(filepath.Join(c.Dst, c.Name)) { + return errors.New("file is exist") + } + + return fo.Compress(c.Files, c.Dst, c.Name, files.CompressType(c.Type)) +} + func getUuid() string { b := make([]byte, 16) io.ReadFull(rand.Reader, b) diff --git a/backend/go.mod b/backend/go.mod index f17e4b6d9..564aad669 100644 --- a/backend/go.mod +++ b/backend/go.mod @@ -38,10 +38,13 @@ require ( github.com/KyleBanks/depth v1.2.1 // indirect github.com/PuerkitoBio/purell v1.1.1 // indirect github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect + github.com/andybalholm/brotli v1.0.4 // indirect github.com/cespare/xxhash v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.1.1 // indirect github.com/dgraph-io/ristretto v0.1.0 // indirect + github.com/dsnet/compress v0.0.1 // indirect github.com/dustin/go-humanize v1.0.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.1 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-openapi/jsonpointer v0.19.5 // indirect github.com/go-openapi/jsonreference v0.19.6 // indirect @@ -56,7 +59,7 @@ require ( github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.2 // indirect - github.com/golang/snappy v0.0.3 // indirect + github.com/golang/snappy v0.0.4 // indirect github.com/google/flatbuffers v1.12.1 // indirect github.com/gorilla/securecookie v1.1.1 // indirect github.com/hashicorp/hcl v1.0.0 // indirect @@ -64,26 +67,33 @@ require ( github.com/jinzhu/now v1.1.5 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.12.3 // indirect + github.com/klauspost/compress v1.15.9 // indirect + github.com/klauspost/pgzip v1.2.5 // indirect github.com/leodido/go-urn v1.2.1 // indirect github.com/magiconair/properties v1.8.6 // indirect github.com/mailru/easyjson v0.7.6 // indirect github.com/mattn/go-isatty v0.0.14 // indirect github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect + github.com/mholt/archiver/v4 v4.0.0-alpha.7 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/nwaples/rardecode/v2 v2.0.0-beta.2 // indirect github.com/pelletier/go-toml v1.9.5 // indirect github.com/pelletier/go-toml/v2 v2.0.2 // indirect + github.com/pierrec/lz4/v4 v4.1.15 // indirect + github.com/satori/go.uuid v1.2.0 // indirect github.com/spf13/afero v1.8.2 // indirect github.com/spf13/cast v1.5.0 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/subosito/gotenv v1.3.0 // indirect + github.com/therootcompany/xz v1.0.1 // indirect github.com/ugorji/go/codec v1.2.7 // indirect + github.com/ulikunitz/xz v0.5.10 // indirect go.opencensus.io v0.23.0 // indirect golang.org/x/image v0.0.0-20190802002840-cff245a6509b // indirect - golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2 // indirect + golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e // indirect golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect golang.org/x/tools v0.1.10 // indirect google.golang.org/protobuf v1.28.0 // indirect diff --git a/backend/go.sum b/backend/go.sum index 951ca346a..554687d12 100644 --- a/backend/go.sum +++ b/backend/go.sum @@ -48,6 +48,8 @@ github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbt github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/agiledragon/gomonkey/v2 v2.3.1/go.mod h1:ap1AmDzcVOAz1YpeJ3TCzIgstoaWLA6jbbgxfB4w2iY= +github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY= +github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= @@ -77,6 +79,9 @@ github.com/dgraph-io/ristretto v0.1.0 h1:Jv3CGQHp9OjuMBSne1485aDpUkTKEcUqF+jm/Lu github.com/dgraph-io/ristretto v0.1.0/go.mod h1:fux0lOrBhrVCJd3lcTHsIJhq1T2rokOu6v9Vcb3Q9ug= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dsnet/compress v0.0.1 h1:PlZu0n3Tuv04TzpfPbrnI0HW/YwodEXDS+oPKahKF0Q= +github.com/dsnet/compress v0.0.1/go.mod h1:Aw8dCMJ7RioblQeTqt88akK31OvO8Dhf5JflhBbQEHo= +github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -91,6 +96,8 @@ github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwV github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= github.com/fvbock/endless v0.0.0-20170109170031-447134032cb6 h1:6VSn3hB5U5GeA6kQw4TwWIWbOhtvR2hmbBJnTOtqTWc= github.com/fvbock/endless v0.0.0-20170109170031-447134032cb6/go.mod h1:YxOVT5+yHzKvwhsiSIWmbAYM3Dr9AEEbER2dVayfBkg= +github.com/gabriel-vasile/mimetype v1.4.1 h1:TRWk7se+TOjCYgRth7+1/OYLNiRNIotknkFtf/dnN7Q= +github.com/gabriel-vasile/mimetype v1.4.1/go.mod h1:05Vi0w3Y9c/lNvJOdmIwvrrAhX3rYhfQQCaf9VJcv7M= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4= github.com/gin-contrib/gzip v0.0.6/go.mod h1:QOJlmV2xmayAjkNS2Y8NQsMneuRShOU/kjovCXNuzzk= @@ -173,6 +180,8 @@ github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/flatbuffers v1.12.1 h1:MVlul7pQNoDzWRLTw5imwYsl+usrS1TXG2H4jg6ImGw= @@ -250,8 +259,14 @@ github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/X github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.12.3 h1:G5AfA94pHPysR56qqrkO2pxEexdDzrpFJ6yt/VqWxVU= github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= +github.com/klauspost/compress v1.15.9 h1:wKRjX6JRtDdrE9qwa4b/Cip7ACOshUI4smpCQanqjSY= +github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= +github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE= +github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= @@ -278,6 +293,8 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k github.com/mattn/go-sqlite3 v1.14.12/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= 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/mholt/archiver/v4 v4.0.0-alpha.7 h1:xzByj8G8tj0Oq7ZYYU4+ixL/CVb5ruWCm0EZQ1PjOkE= +github.com/mholt/archiver/v4 v4.0.0-alpha.7/go.mod h1:Fs8qUkO74HHaidabihzYephJH8qmGD/nCP6tE5xC9BM= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= @@ -295,6 +312,8 @@ github.com/natefinch/lumberjack v2.0.0+incompatible/go.mod h1:Wi9p2TTF5DG5oU+6Yf github.com/nicksnyder/go-i18n/v2 v2.1.2 h1:QHYxcUJnGHBaq7XbvgunmZ2Pn0focXFqTD61CkH146c= github.com/nicksnyder/go-i18n/v2 v2.1.2/go.mod h1:d++QJC9ZVf7pa48qrsRWhMJ5pSHIPmS3OLqK1niyLxs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nwaples/rardecode/v2 v2.0.0-beta.2 h1:e3mzJFJs4k83GXBEiTaQ5HgSc/kOK8q0rDaRO0MPaOk= +github.com/nwaples/rardecode/v2 v2.0.0-beta.2/go.mod h1:yntwv/HfMc/Hbvtq9I19D1n58te3h6KsqCf3GxyfBGY= github.com/otiai10/copy v1.7.0/go.mod h1:rmRl6QPdJj6EiUqXQ/4Nn2lLXoNQjFCQbbNrxgc/t3U= github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs= @@ -306,6 +325,8 @@ github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCko github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= github.com/pelletier/go-toml/v2 v2.0.2 h1:+jQXlF3scKIcSEKkdHzXhCTDLPFi5r1wnK6yPS+49Gw= github.com/pelletier/go-toml/v2 v2.0.2/go.mod h1:MovirKjgVRESsAvNZlAjtFwV867yGuwRkXbG66OzopI= +github.com/pierrec/lz4/v4 v4.1.15 h1:MO0/ucJhngq7299dKLwIMtgTfbkoSPF6AoMYDd8Q4q0= +github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= 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/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -367,12 +388,17 @@ github.com/swaggo/gin-swagger v1.5.1/go.mod h1:Cbj/MlHApPOjZdf4joWFXLLgmZVPyh54G github.com/swaggo/swag v1.8.1/go.mod h1:ugemnJsPZm/kRwFUnzBlbHRd0JY9zE1M4F+uy2pAaPQ= github.com/swaggo/swag v1.8.4 h1:oGB351qH1JqUqK1tsMYEE5qTBbPk394BhsZxmUfebcI= github.com/swaggo/swag v1.8.4/go.mod h1:jMLeXOOmYyjk8PvHTsXBdrubsNd9gUJTTCzL5iBnseg= +github.com/therootcompany/xz v1.0.1 h1:CmOtsn1CbtmyYiusbfmhmkpAAETj0wBIH6kCYaX+xzw= +github.com/therootcompany/xz v1.0.1/go.mod h1:3K3UH1yCKgBneZYhuQUvJ9HPD19UEXEI0BWbMn8qNMY= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= +github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= +github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8= +github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -475,6 +501,8 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2 h1:NWy5+hlRbC7HK+PmcXVUmW1IMyFce7to56IUvhUFm7Y= golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e h1:TsQ7F31D3bUCLeqPT0u+yjp1guoArKaNKmCr22PYgTQ= +golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -539,6 +567,7 @@ golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= diff --git a/backend/router/ro_file.go b/backend/router/ro_file.go index 3b66f7416..6fa85b8d3 100644 --- a/backend/router/ro_file.go +++ b/backend/router/ro_file.go @@ -20,6 +20,7 @@ func (f *FileRouter) InitFileRouter(Router *gin.RouterGroup) { fileRouter.POST("", baseApi.CreateFile) fileRouter.POST("/del", baseApi.DeleteFile) fileRouter.POST("/mode", baseApi.ChangeFileMode) + fileRouter.POST("/compress", baseApi.CompressFile) } } diff --git a/backend/utils/files/file_op.go b/backend/utils/files/file_op.go index 7abbbc1f5..4c62349d3 100644 --- a/backend/utils/files/file_op.go +++ b/backend/utils/files/file_op.go @@ -1,11 +1,14 @@ package files import ( + "context" + "github.com/mholt/archiver/v4" "github.com/spf13/afero" "io" "io/fs" "os" "path" + "path/filepath" ) type FileOp struct { @@ -62,3 +65,95 @@ func (f FileOp) WriteFile(dst string, in io.Reader, mode fs.FileMode) error { func (f FileOp) Chmod(dst string, mode fs.FileMode) error { return f.Fs.Chmod(dst, mode) } + +type CompressType string + +const ( + Zip CompressType = "zip" + Gz CompressType = "gz" + Bz2 CompressType = "bz2" + Tar CompressType = "tar" + TarGz CompressType = "tarGz" + Xz CompressType = "xz" +) + +func getFormat(cType CompressType) archiver.CompressedArchive { + format := archiver.CompressedArchive{} + switch cType { + case Tar: + format.Archival = archiver.Tar{} + case TarGz, Gz: + format.Compression = archiver.Gz{} + format.Archival = archiver.Tar{} + case Zip: + format.Archival = archiver.Zip{} + case Bz2: + format.Compression = archiver.Bz2{} + format.Archival = archiver.Tar{} + case Xz: + format.Compression = archiver.Xz{} + format.Archival = archiver.Tar{} + } + return format +} + +func (f FileOp) Compress(srcRiles []string, dst string, name string, cType CompressType) error { + format := getFormat(cType) + + fileMaps := make(map[string]string, len(srcRiles)) + for _, s := range srcRiles { + base := filepath.Base(s) + fileMaps[s] = base + } + + files, err := archiver.FilesFromDisk(nil, fileMaps) + if err != nil { + return err + } + dstFile := filepath.Join(dst, name) + out, err := f.Fs.Create(dstFile) + if err != nil { + return err + } + + err = format.Archive(context.Background(), out, files) + if err != nil { + return err + } + return nil +} + +func (f FileOp) Decompress(srcFile string, dst string, cType CompressType) error { + format := getFormat(cType) + + handler := func(ctx context.Context, archFile archiver.File) error { + info := archFile.FileInfo + filePath := filepath.Join(dst, archFile.NameInArchive) + if archFile.FileInfo.IsDir() { + if err := f.Fs.MkdirAll(filePath, info.Mode()); err != nil { + return err + } + return nil + } + fr, err := archFile.Open() + if err != nil { + return err + } + defer fr.Close() + fw, err := f.Fs.OpenFile(filePath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, info.Mode()) + if err != nil { + return err + } + defer fw.Close() + if _, err := io.Copy(fw, fr); err != nil { + return err + } + + return nil + } + input, err := f.Fs.Open(srcFile) + if err != nil { + return err + } + return format.Extract(context.Background(), input, nil, handler) +} diff --git a/backend/utils/files/fileinfo.go b/backend/utils/files/fileinfo.go index 3e7617ef9..e8448af2d 100644 --- a/backend/utils/files/fileinfo.go +++ b/backend/utils/files/fileinfo.go @@ -23,6 +23,7 @@ type FileInfo struct { IsSymlink bool `json:"isSymlink"` Type string `json:"type"` Mode string `json:"mode"` + MimeType string `json:"mimeType"` UpdateTime time.Time `json:"updateTime"` ModTime time.Time `json:"modTime"` FileMode os.FileMode `json:"-"` @@ -56,6 +57,7 @@ func NewFileInfo(op FileOption) (*FileInfo, error) { Mode: fmt.Sprintf("%04o", info.Mode().Perm()), User: GetUsername(info.Sys().(*syscall.Stat_t).Uid), Group: GetGroup(info.Sys().(*syscall.Stat_t).Gid), + MimeType: GetMimeType(op.Path), } if op.Expand { if file.IsDir { @@ -107,6 +109,7 @@ func (f *FileInfo) listChildren() error { Mode: fmt.Sprintf("%04o", df.Mode().Perm()), User: GetUsername(df.Sys().(*syscall.Stat_t).Uid), Group: GetGroup(df.Sys().(*syscall.Stat_t).Gid), + MimeType: GetMimeType(fPath), } if isInvalidLink { diff --git a/backend/utils/files/utils.go b/backend/utils/files/utils.go index a647eb403..29793cb36 100644 --- a/backend/utils/files/utils.go +++ b/backend/utils/files/utils.go @@ -1,6 +1,7 @@ package files import ( + "github.com/gabriel-vasile/mimetype" "os" "os/user" "strconv" @@ -25,3 +26,11 @@ func GetGroup(gid uint32) string { } return usr.Name } + +func GetMimeType(path string) string { + mime, err := mimetype.DetectFile(path) + if err != nil { + return "" + } + return mime.String() +} diff --git a/frontend/src/api/interface/file.ts b/frontend/src/api/interface/file.ts index 13e6c8402..ed9863667 100644 --- a/frontend/src/api/interface/file.ts +++ b/frontend/src/api/interface/file.ts @@ -13,6 +13,7 @@ export namespace File { updateTime: string; modTime: string; mode: number; + mimeType: string; items: File[]; } @@ -40,4 +41,12 @@ export namespace File { path: string; isDir: boolean; } + + export interface FileCompress { + files: string[]; + type: string; + dst: string; + name: string; + replace: boolean; + } } diff --git a/frontend/src/api/modules/files.ts b/frontend/src/api/modules/files.ts index 3435907f5..1d119fed8 100644 --- a/frontend/src/api/modules/files.ts +++ b/frontend/src/api/modules/files.ts @@ -18,5 +18,9 @@ export const DeleteFile = (form: File.FileDelete) => { }; export const ChangeFileMode = (form: File.FileCreate) => { - return http.post('files/mode', form); + return http.post('files/mode', form); +}; + +export const CompressFile = (form: File.FileCompress) => { + return http.post('files/compress', form); }; diff --git a/frontend/src/components/file-role/index.vue b/frontend/src/components/file-role/index.vue index b6b2e9150..3763364f4 100644 --- a/frontend/src/components/file-role/index.vue +++ b/frontend/src/components/file-role/index.vue @@ -24,7 +24,7 @@ diff --git a/frontend/src/views/file-management/create.vue b/frontend/src/views/file-management/create.vue index ddba23c29..037532536 100644 --- a/frontend/src/views/file-management/create.vue +++ b/frontend/src/views/file-management/create.vue @@ -8,8 +8,8 @@ v-loading="loading" > - - + + @@ -36,15 +36,14 @@ const fileForm = ref(); let loading = ref(false); let setRole = ref(false); let isLink = ref(false); -let name = ref(''); -let path = ref(''); const props = defineProps({ open: Boolean, file: Object, }); const { open, file } = toRefs(props); -let form = ref({ path: '', isDir: false, mode: 0o755 }); +let addItem = ref({ path: '', isDir: false, mode: 0o755 }); +let form = ref({ name: '', path: '' }); const em = defineEmits(['close']); const handleClose = () => { em('close', open); @@ -52,14 +51,19 @@ const handleClose = () => { const rules = reactive({ name: [Rules.required], + path: [Rules.required], }); const getMode = (val: number) => { - form.value.mode = val; + addItem.value.mode = val; }; let getPath = computed(() => { - return path.value + '/' + name.value; + if (form.value.path === '/') { + return form.value.path + form.value.name; + } else { + return form.value.path + '/' + form.value.name; + } }); const submit = async (formEl: FormInstance | undefined) => { @@ -69,8 +73,8 @@ const submit = async (formEl: FormInstance | undefined) => { return; } loading.value = true; - form.value.path = getPath.value; - CreateFile(form.value) + addItem.value.path = getPath.value; + CreateFile(addItem.value) .then(() => { ElMessage.success(i18n.global.t('commons.msg.createSuccess')); handleClose(); @@ -83,9 +87,9 @@ const submit = async (formEl: FormInstance | undefined) => { const onOpen = () => { const f = file?.value as File.FileCreate; - form.value.isDir = f.isDir; + addItem.value.isDir = f.isDir; + addItem.value.path = f.path; + form.value.name = ''; form.value.path = f.path; - path.value = f.path; - name.value = ''; }; diff --git a/frontend/src/views/file-management/index.vue b/frontend/src/views/file-management/index.vue index 1da0314f9..6bf76a6d6 100644 --- a/frontend/src/views/file-management/index.vue +++ b/frontend/src/views/file-management/index.vue @@ -1,5 +1,5 @@ @@ -114,21 +121,24 @@ import BreadCrumbs from '@/components/bread-crumbs/index.vue'; import BreadCrumbItem from '@/components/bread-crumbs/bread-crumbs-item.vue'; import CreateFile from './create.vue'; import ChangeRole from './change-role.vue'; +import Compress from './compress.vue'; import { useDeleteData } from '@/hooks/use-delete-data'; let data = ref(); let selects = ref([]); let req = reactive({ path: '/', expand: true }); -let loading = ref(false); -let treeLoading = ref(false); +let loading = ref(false); +let treeLoading = ref(false); let paths = ref([]); let fileTree = ref([]); let expandKeys = ref([]); -let openCreate = ref(false); +let openCreate = ref(false); let fileCreate = ref({ path: '/', isDir: false, mode: 0o755 }); -let openModePage = ref(false); +let openModePage = ref(false); let modeForm = ref({ path: '/', isDir: false, mode: 0o755 }); +let compressPage = reactive({ open: false, files: [''], name: '', dst: '' }); + const defaultProps = { children: 'children', label: 'name', @@ -252,6 +262,17 @@ const closeMode = () => { search(req); }; +const openCompress = (item: File.File) => { + compressPage.open = true; + compressPage.files = [item.path]; + compressPage.name = item.name; + compressPage.dst = req.path; +}; + +const closeCompress = () => { + compressPage.open = false; + search(req); +}; onMounted(() => { search(req); }); @@ -267,6 +288,7 @@ const buttons = [ }, { label: i18n.global.t('file.zip'), + click: openCompress, }, { label: i18n.global.t('file.rename'), @@ -283,7 +305,6 @@ const buttons = [