This is an automated email from the ASF dual-hosted git repository. lufei pushed a commit to branch cos in repository https://gitbox.apache.org/repos/asf/incubator-answer-plugins.git
commit 60e371a267414bf5f97b9534ec9245204c781b2d Author: sy-records <5...@qq52o.cn> AuthorDate: Wed Sep 25 11:09:53 2024 +0800 feat: Support Tencent COS Storage --- storage-tencentyuncos/README.md | 21 +++ storage-tencentyuncos/go.mod | 51 ++++++ storage-tencentyuncos/go.sum | 166 +++++++++++++++++++ storage-tencentyuncos/i18n/en_US.yaml | 72 ++++++++ storage-tencentyuncos/i18n/translation.go | 46 +++++ storage-tencentyuncos/i18n/zh_CN.yaml | 72 ++++++++ storage-tencentyuncos/info.yaml | 22 +++ storage-tencentyuncos/tencentyuncos.go | 267 ++++++++++++++++++++++++++++++ 8 files changed, 717 insertions(+) diff --git a/storage-tencentyuncos/README.md b/storage-tencentyuncos/README.md new file mode 100644 index 0000000..013fc10 --- /dev/null +++ b/storage-tencentyuncos/README.md @@ -0,0 +1,21 @@ +# Tencent COS Storage (preview) + +> This plugin can be used to store attachments and avatars to Tencent COS. + +## How to use + +### Build + +```bash +./answer build --with github.com/apache/incubator-answer-plugins/storage-tencentyuncos +``` + +### Configuration + +- `Region` - Region of Tencent COS storage, like 'ap-beijing' +- `Bucket Name` - Your bucket name +- `Object Key Prefix` - Prefix of the object key like 'answer/data/' that ending with '/' +- `Secret ID` - Secret ID of the Tencent COS storage +- `Secret Key` - Secret Key of the Tencent COS storage +- `Visit Url Prefix` - Prefix of access address for the uploaded file, ending with '/' such as https://example.com/xxx/ +- `Max File Size` - Max file size in MB, default is 10MB diff --git a/storage-tencentyuncos/go.mod b/storage-tencentyuncos/go.mod new file mode 100644 index 0000000..bebd74e --- /dev/null +++ b/storage-tencentyuncos/go.mod @@ -0,0 +1,51 @@ +module tencentyuncos + +go 1.21.3 + +require ( + github.com/apache/incubator-answer v1.4.0 + github.com/apache/incubator-answer-plugins/util v1.0.2 + github.com/tencentyun/cos-go-sdk-v5 v0.7.55 +) + +require ( + github.com/LinkinStars/go-i18n/v2 v2.2.2 // indirect + github.com/aymerick/douceur v0.2.0 // indirect + github.com/bytedance/sonic v1.9.1 // indirect + github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect + github.com/clbanning/mxj v1.8.4 // indirect + github.com/gabriel-vasile/mimetype v1.4.2 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect + github.com/gin-gonic/gin v1.9.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/validator/v10 v10.14.0 // indirect + github.com/goccy/go-json v0.10.2 // indirect + github.com/google/go-querystring v1.0.0 // indirect + github.com/google/wire v0.5.0 // indirect + github.com/gorilla/css v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/cpuid/v2 v2.2.4 // indirect + github.com/kr/text v0.2.0 // indirect + github.com/leodido/go-urn v1.2.4 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect + github.com/microcosm-cc/bluemonday v1.0.21 // 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/mozillazg/go-httpheader v0.2.1 // indirect + github.com/pelletier/go-toml/v2 v2.0.8 // indirect + github.com/segmentfault/pacman v1.0.5-0.20230822083413-c0075a2d401f // indirect + github.com/segmentfault/pacman/contrib/i18n v0.0.0-20230516093754-b76aef1c1150 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.11 // indirect + golang.org/x/arch v0.3.0 // indirect + golang.org/x/crypto v0.21.0 // indirect + golang.org/x/net v0.21.0 // indirect + golang.org/x/sys v0.18.0 // indirect + golang.org/x/text v0.14.0 // indirect + google.golang.org/protobuf v1.30.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + sigs.k8s.io/yaml v1.3.0 // indirect +) diff --git a/storage-tencentyuncos/go.sum b/storage-tencentyuncos/go.sum new file mode 100644 index 0000000..2fa1db7 --- /dev/null +++ b/storage-tencentyuncos/go.sum @@ -0,0 +1,166 @@ +github.com/BurntSushi/toml v1.0.0 h1:dtDWrepsVPfW9H/4y7dDgFc2MBUSeJhlaDtK13CxFlU= +github.com/BurntSushi/toml v1.0.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/LinkinStars/go-i18n/v2 v2.2.2 h1:ZfjpzbW13dv6btv3RALKZkpN9A+7K1JA//2QcNeWaxU= +github.com/LinkinStars/go-i18n/v2 v2.2.2/go.mod h1:hLglSJ4/3M0Y7ZVcoEJI+OwqkglHCA32DdjuJJR2LbM= +github.com/QcloudApi/qcloud_sign_golang v0.0.0-20141224014652-e4130a326409/go.mod h1:1pk82RBxDY/JZnPQrtqHlUFfCctgdorsd9M06fMynOM= +github.com/apache/incubator-answer v1.4.0 h1:W3y4TAQ4sdzgcqntGqNBPe0BdyeW7+l8FWYBDs9g8+Y= +github.com/apache/incubator-answer v1.4.0/go.mod h1:Q4NkQmBd0sV7t3Cd8NBsWh9w8jFRo/2qjzOw9MlRNwk= +github.com/apache/incubator-answer-plugins/util v1.0.2 h1:PontocVaiEm+oTj+4aDonwWDZnxywUeHsaTwlQgclfA= +github.com/apache/incubator-answer-plugins/util v1.0.2/go.mod h1:KPMSiM4ec4uEl2njaGINYuSl6zVmHdvPB2nHUxVcQDo= +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/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= +github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= +github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= +github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= +github.com/clbanning/mxj v1.8.4 h1:HuhwZtbyvyOw+3Z1AowPkU87JkJUSv751ELWaiTpj8I= +github.com/clbanning/mxj v1.8.4/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng= +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.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= +github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= +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-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= +github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= +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/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= +github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +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/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/wire v0.5.0 h1:I7ELFeVBr3yfPIcc8+MWvrjk+3VjbcSzoXm3JVa+jD8= +github.com/google/wire v0.5.0/go.mod h1:ngWDr9Qvq3yZA10YrxfyGELY/AFWGVpy9c1LTRi1EoU= +github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= +github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= +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/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= +github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +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/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/microcosm-cc/bluemonday v1.0.21 h1:dNH3e4PSyE4vNX+KlRGHT5KrSvjeUkoNPwEORjffHJg= +github.com/microcosm-cc/bluemonday v1.0.21/go.mod h1:ytNkv4RrDrLJ2pqlsSI46O6IVXmZOBBD4SaJyDwwTkM= +github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +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/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +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/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/mozillazg/go-httpheader v0.2.1 h1:geV7TrjbL8KXSyvghnFm+NyTux/hxwueTSrwhe88TQQ= +github.com/mozillazg/go-httpheader v0.2.1/go.mod h1:jJ8xECTlalr6ValeXYdOF8fFUISeBAdw6E61aqQma60= +github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= +github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +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/segmentfault/pacman v1.0.5-0.20230822083413-c0075a2d401f h1:9f2Bjf6bdMvNyUop32wAGJCdp+Jdm/d6nKBYvFvkRo0= +github.com/segmentfault/pacman v1.0.5-0.20230822083413-c0075a2d401f/go.mod h1:5lNp5REd8QMThmBUvR3Fi9Y3AsOB4GRq7soCB4QLqOs= +github.com/segmentfault/pacman/contrib/i18n v0.0.0-20230516093754-b76aef1c1150 h1:OEuW1D7RGDE0CZDr0oGMw9Eiq7fAbD9C4WMrvSixamk= +github.com/segmentfault/pacman/contrib/i18n v0.0.0-20230516093754-b76aef1c1150/go.mod h1:7QcRmnV7OYq4hNOOCWXT5HXnN/u756JUsqIW0Bw8n9E= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +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/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.563/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/kms v1.0.563/go.mod h1:uom4Nvi9W+Qkom0exYiJ9VWJjXwyxtPYTkKkaLMlfE0= +github.com/tencentyun/cos-go-sdk-v5 v0.7.55 h1:9DfH3umWUd0I2jdqcUxrU1kLfUPOydULNy4T9qN5PF8= +github.com/tencentyun/cos-go-sdk-v5 v0.7.55/go.mod h1:8+hG+mQMuRP/OIS9d83syAvXvrMj9HhkND6Q1fLghw0= +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/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= +github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= +golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +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-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +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/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-20210615035016-665e8c7367d1/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-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +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/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.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +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/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190422233926-fe54fb35175b/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +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/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/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/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= +sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/storage-tencentyuncos/i18n/en_US.yaml b/storage-tencentyuncos/i18n/en_US.yaml new file mode 100644 index 0000000..e3ae90d --- /dev/null +++ b/storage-tencentyuncos/i18n/en_US.yaml @@ -0,0 +1,72 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +plugin: + tencentyuncos_storage: + backend: + info: + name: + other: Tencent COS storage + description: + other: Upload files to Tencent COS storage + config: + region: + title: + other: Region + description: + other: Region of Tencent COS storage, like 'ap-beijing' + bucket_name: + title: + other: Bucket name + description: + other: Bucket name of Tencent COS storage + object_key_prefix: + title: + other: Object Key prefix + description: + other: prefix of the object key like 'answer/data/' that ending with '/' + secret_id: + title: + other: SecretID + description: + other: SecretID of the Tencent COS storage + secret_key: + title: + other: SecretKey + description: + other: SecretKey of the Tencent COS storage + visit_url_prefix: + title: + other: Access URL prefix + description: + other: prefix of the final access address of the uploaded file, ending with '/' https://example.com/xxx/ + max_file_size: + title: + other: Maximum file size(MB) + description: + other: Limit the maximum size of uploaded files, in MB, default is 10MB + err: + mis_storage_config: + other: Wrong storage configuration causes upload failure. + file_not_found: + other: File not found. + unsupported_file_type: + other: Unsupported file type. + over_file_size_limit: + other: File size limit exceeded. + upload_file_failed: + other: Failed to upload a file. diff --git a/storage-tencentyuncos/i18n/translation.go b/storage-tencentyuncos/i18n/translation.go new file mode 100644 index 0000000..2664a8c --- /dev/null +++ b/storage-tencentyuncos/i18n/translation.go @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package i18n + +const ( + InfoName = "plugin.tencentyuncos_storage.backend.info.name" + InfoDescription = "plugin.tencentyuncos_storage.backend.info.description" + + ConfigRegionTitle = "plugin.tencentyuncos_storage.backend.config.region.title" + ConfigRegionDescription = "plugin.tencentyuncos_storage.backend.config.region.description" + ConfigBucketNameTitle = "plugin.tencentyuncos_storage.backend.config.bucket_name.title" + ConfigBucketNameDescription = "plugin.tencentyuncos_storage.backend.config.bucket_name.description" + ConfigObjectKeyPrefixTitle = "plugin.tencentyuncos_storage.backend.config.object_key_prefix.title" + ConfigObjectKeyPrefixDescription = "plugin.tencentyuncos_storage.backend.config.object_key_prefix.description" + ConfigSecretIdTitle = "plugin.tencentyuncos_storage.backend.config.secret_id.title" + ConfigSecretIdDescription = "plugin.tencentyuncos_storage.backend.config.secret_id.description" + ConfigSecretKeyTitle = "plugin.tencentyuncos_storage.backend.config.secret_key.title" + ConfigSecretKeyDescription = "plugin.tencentyuncos_storage.backend.config.secret_key.description" + ConfigVisitUrlPrefixTitle = "plugin.tencentyuncos_storage.backend.config.visit_url_prefix.title" + ConfigVisitUrlPrefixDescription = "plugin.tencentyuncos_storage.backend.config.visit_url_prefix.description" + ConfigMaxFileSizeTitle = "plugin.tencentyuncos_storage.backend.config.max_file_size.title" + ConfigMaxFileSizeDescription = "plugin.tencentyuncos_storage.backend.config.max_file_size.description" + + ErrMisStorageConfig = "plugin.tencentyuncos_storage.backend.err.mis_storage_config" + ErrFileNotFound = "plugin.tencentyuncos_storage.backend.err.file_not_found" + ErrUnsupportedFileType = "plugin.tencentyuncos_storage.backend.err.unsupported_file_type" + ErrOverFileSizeLimit = "plugin.tencentyuncos_storage.backend.err.over_file_size_limit" + ErrUploadFileFailed = "plugin.tencentyuncos_storage.backend.err.upload_file_failed" +) diff --git a/storage-tencentyuncos/i18n/zh_CN.yaml b/storage-tencentyuncos/i18n/zh_CN.yaml new file mode 100644 index 0000000..280aa19 --- /dev/null +++ b/storage-tencentyuncos/i18n/zh_CN.yaml @@ -0,0 +1,72 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +plugin: + tencentyuncos_storage: + backend: + info: + name: + other: 腾讯云COS对象存储 + description: + other: 上传文件到腾讯云COS对象存储 + config: + region: + title: + other: 所属地域 + description: + other: 存储桶的所属地域,如'ap-beijing' + bucket_name: + title: + other: 存储桶名称 + description: + other: 存储桶的名称,如'example-1234567890' + object_key_prefix: + title: + other: 对象Key前缀 + description: + other: 对象键的前缀,如'answer/data/',以'/'结尾 + secret_id: + title: + other: SecretID + description: + other: 腾讯云COS对象存储的SecretID,在 https://console.cloud.tencent.com/cam/capi 获取 + secret_key: + title: + other: SecretKey + description: + other: 腾讯云COS对象存储的SecretKey + visit_url_prefix: + title: + other: 访问URL前缀 + description: + other: 上传文件最终访问地址的前缀,以 '/' 结尾 https://example.com/xxx/ + max_file_size: + title: + other: 最大文件大小(MB) + description: + other: 限制上传文件的最大大小,单位为MB,默认为 10MB + err: + mis_storage_config: + other: 错误的存储配置导致上传失败 + file_not_found: + other: 文件未找到 + unsupported_file_type: + other: 不支持的文件类型 + over_file_size_limit: + other: 超过文件大小限制 + upload_file_failed: + other: 上传文件失败 diff --git a/storage-tencentyuncos/info.yaml b/storage-tencentyuncos/info.yaml new file mode 100644 index 0000000..5ee9905 --- /dev/null +++ b/storage-tencentyuncos/info.yaml @@ -0,0 +1,22 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +slug_name: tencentyuncos_storage +type: storage +version: 1.0.0 +author: Luffy +link: https://github.com/apache/incubator-answer-plugins/tree/main/storage-tencentyuncos diff --git a/storage-tencentyuncos/tencentyuncos.go b/storage-tencentyuncos/tencentyuncos.go new file mode 100644 index 0000000..f2273ee --- /dev/null +++ b/storage-tencentyuncos/tencentyuncos.go @@ -0,0 +1,267 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package tencentyuncos + +import ( + "crypto/rand" + "embed" + "encoding/hex" + "encoding/json" + "fmt" + "github.com/apache/incubator-answer-plugins/util" + "net/http" + "net/url" + "path/filepath" + "strconv" + "strings" + "time" + + "github.com/apache/incubator-answer-plugins/storage-tencentyuncos/i18n" + "github.com/apache/incubator-answer/plugin" + "github.com/tencentyun/cos-go-sdk-v5" +) + +//go:embed info.yaml +var Info embed.FS + +const ( + // 10MB + defaultMaxFileSize int64 = 10 * 1024 * 1024 +) + +type Storage struct { + Config *StorageConfig +} + +type StorageConfig struct { + Region string `json:"region"` + BucketName string `json:"bucket_name"` + ObjectKeyPrefix string `json:"object_key_prefix"` + SecretID string `json:"secret_id"` + SecretKey string `json:"secret_key"` + VisitUrlPrefix string `json:"visit_url_prefix"` + MaxFileSize string `json:"max_file_size"` +} + +func init() { + plugin.Register(&Storage{ + Config: &StorageConfig{}, + }) +} + +func (s *Storage) Info() plugin.Info { + info := &util.Info{} + info.GetInfo(Info) + + return plugin.Info{ + Name: plugin.MakeTranslator(i18n.InfoName), + SlugName: info.SlugName, + Description: plugin.MakeTranslator(i18n.InfoDescription), + Author: info.Author, + Version: info.Version, + Link: info.Link, + } +} + +func (s *Storage) UploadFile(ctx *plugin.GinContext, source plugin.UploadSource) (resp plugin.UploadFileResponse) { + resp = plugin.UploadFileResponse{} + + BucketURL, _ := url.Parse(fmt.Sprintf("https://%s.cos.%s.myqcloud.com", s.Config.BucketName, s.Config.Region)) + BaseURL := &cos.BaseURL{BucketURL: BucketURL} + client := cos.NewClient(BaseURL, &http.Client{ + Transport: &cos.AuthorizationTransport{ + SecretID: s.Config.SecretID, + SecretKey: s.Config.SecretKey, + }, + }) + + _, err := client.Bucket.IsExist(ctx) + if err != nil { + resp.OriginalError = fmt.Errorf("head bucket failed: %v", err) + resp.DisplayErrorMsg = plugin.MakeTranslator(i18n.ErrMisStorageConfig) + return resp + } + + file, err := ctx.FormFile("file") + if err != nil { + resp.OriginalError = fmt.Errorf("get upload file failed: %v", err) + resp.DisplayErrorMsg = plugin.MakeTranslator(i18n.ErrFileNotFound) + return resp + } + + if !s.CheckFileType(file.Filename, source) { + resp.OriginalError = fmt.Errorf("file type not allowed") + resp.DisplayErrorMsg = plugin.MakeTranslator(i18n.ErrUnsupportedFileType) + return resp + } + + if file.Size > s.maxFileSizeLimit() { + resp.OriginalError = fmt.Errorf("file size too large") + resp.DisplayErrorMsg = plugin.MakeTranslator(i18n.ErrOverFileSizeLimit) + return resp + } + + openFile, err := file.Open() + if err != nil { + resp.OriginalError = fmt.Errorf("get file failed: %v", err) + resp.DisplayErrorMsg = plugin.MakeTranslator(i18n.ErrFileNotFound) + return resp + } + defer openFile.Close() + + objectKey := s.createObjectKey(file.Filename, source) + _, err = client.Object.Put(ctx, objectKey, openFile, nil) + if err != nil { + resp.OriginalError = fmt.Errorf("upload file failed: %v", err) + resp.DisplayErrorMsg = plugin.MakeTranslator(i18n.ErrUploadFileFailed) + return resp + } + resp.FullURL = s.Config.VisitUrlPrefix + objectKey + return resp +} + +func (s *Storage) createObjectKey(originalFilename string, source plugin.UploadSource) string { + ext := strings.ToLower(filepath.Ext(originalFilename)) + randomString := s.randomObjectKey() + switch source { + case plugin.UserAvatar: + return s.Config.ObjectKeyPrefix + "avatar/" + randomString + ext + case plugin.UserPost: + return s.Config.ObjectKeyPrefix + "post/" + randomString + ext + case plugin.AdminBranding: + return s.Config.ObjectKeyPrefix + "branding/" + randomString + ext + default: + return s.Config.ObjectKeyPrefix + "other/" + randomString + ext + } +} + +func (s *Storage) randomObjectKey() string { + bytes := make([]byte, 4) + _, _ = rand.Read(bytes) + return fmt.Sprintf("%d", time.Now().UnixNano()) + hex.EncodeToString(bytes) +} + +func (s *Storage) CheckFileType(originalFilename string, source plugin.UploadSource) bool { + ext := strings.ToLower(filepath.Ext(originalFilename)) + if _, ok := plugin.DefaultFileTypeCheckMapping[source][ext]; ok { + return true + } + return false +} + +func (s *Storage) maxFileSizeLimit() int64 { + if len(s.Config.MaxFileSize) == 0 { + return defaultMaxFileSize + } + limit, _ := strconv.Atoi(s.Config.MaxFileSize) + if limit <= 0 { + return defaultMaxFileSize + } + return int64(limit) * 1024 * 1024 +} + +func (s *Storage) ConfigFields() []plugin.ConfigField { + return []plugin.ConfigField{ + { + Name: "region", + Type: plugin.ConfigTypeInput, + Title: plugin.MakeTranslator(i18n.ConfigRegionTitle), + Description: plugin.MakeTranslator(i18n.ConfigRegionDescription), + Required: true, + UIOptions: plugin.ConfigFieldUIOptions{ + InputType: plugin.InputTypeText, + }, + Value: s.Config.Region, + }, + { + Name: "bucket_name", + Type: plugin.ConfigTypeInput, + Title: plugin.MakeTranslator(i18n.ConfigBucketNameTitle), + Description: plugin.MakeTranslator(i18n.ConfigBucketNameDescription), + Required: true, + UIOptions: plugin.ConfigFieldUIOptions{ + InputType: plugin.InputTypeText, + }, + Value: s.Config.BucketName, + }, + { + Name: "object_key_prefix", + Type: plugin.ConfigTypeInput, + Title: plugin.MakeTranslator(i18n.ConfigObjectKeyPrefixTitle), + Description: plugin.MakeTranslator(i18n.ConfigObjectKeyPrefixDescription), + Required: false, + UIOptions: plugin.ConfigFieldUIOptions{ + InputType: plugin.InputTypeText, + }, + Value: s.Config.ObjectKeyPrefix, + }, + { + Name: "secret_id", + Type: plugin.ConfigTypeInput, + Title: plugin.MakeTranslator(i18n.ConfigSecretIdTitle), + Description: plugin.MakeTranslator(i18n.ConfigSecretIdDescription), + Required: true, + UIOptions: plugin.ConfigFieldUIOptions{ + InputType: plugin.InputTypeText, + }, + Value: s.Config.SecretID, + }, + { + Name: "secret_key", + Type: plugin.ConfigTypeInput, + Title: plugin.MakeTranslator(i18n.ConfigSecretKeyTitle), + Description: plugin.MakeTranslator(i18n.ConfigSecretKeyDescription), + Required: true, + UIOptions: plugin.ConfigFieldUIOptions{ + InputType: plugin.InputTypeText, + }, + Value: s.Config.SecretKey, + }, + { + Name: "visit_url_prefix", + Type: plugin.ConfigTypeInput, + Title: plugin.MakeTranslator(i18n.ConfigVisitUrlPrefixTitle), + Description: plugin.MakeTranslator(i18n.ConfigVisitUrlPrefixDescription), + Required: true, + UIOptions: plugin.ConfigFieldUIOptions{ + InputType: plugin.InputTypeText, + }, + Value: s.Config.VisitUrlPrefix, + }, + { + Name: "max_file_size", + Type: plugin.ConfigTypeInput, + Title: plugin.MakeTranslator(i18n.ConfigMaxFileSizeTitle), + Description: plugin.MakeTranslator(i18n.ConfigMaxFileSizeDescription), + Required: false, + UIOptions: plugin.ConfigFieldUIOptions{ + InputType: plugin.InputTypeNumber, + }, + Value: s.Config.MaxFileSize, + }, + } +} + +func (s *Storage) ConfigReceiver(config []byte) error { + c := &StorageConfig{} + _ = json.Unmarshal(config, c) + s.Config = c + return nil +}